aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2017-05-02 10:50:00 +0200
committerMichaël Zasso <targos@protonmail.com>2017-05-06 20:02:35 +0200
commit60d1aac8d225e844e68ae48e8f3d58802e635fbe (patch)
tree922f347dd054db18d88666fad7181e5a777f4022 /deps/v8/src/ic
parent73d9c0f903ae371cd5011af64c3a6f69a1bda978 (diff)
downloadandroid-node-v8-60d1aac8d225e844e68ae48e8f3d58802e635fbe.tar.gz
android-node-v8-60d1aac8d225e844e68ae48e8f3d58802e635fbe.tar.bz2
android-node-v8-60d1aac8d225e844e68ae48e8f3d58802e635fbe.zip
deps: update V8 to 5.8.283.38
PR-URL: https://github.com/nodejs/node/pull/12784 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/access-compiler.cc1
-rw-r--r--deps/v8/src/ic/accessor-assembler-impl.h203
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc833
-rw-r--r--deps/v8/src/ic/accessor-assembler.h285
-rw-r--r--deps/v8/src/ic/arm/handler-compiler-arm.cc39
-rw-r--r--deps/v8/src/ic/arm/ic-arm.cc37
-rw-r--r--deps/v8/src/ic/arm64/handler-compiler-arm64.cc44
-rw-r--r--deps/v8/src/ic/arm64/ic-arm64.cc31
-rw-r--r--deps/v8/src/ic/call-optimization.cc2
-rw-r--r--deps/v8/src/ic/handler-compiler.cc5
-rw-r--r--deps/v8/src/ic/handler-compiler.h6
-rw-r--r--deps/v8/src/ic/handler-configuration-inl.h11
-rw-r--r--deps/v8/src/ic/handler-configuration.h5
-rw-r--r--deps/v8/src/ic/ia32/handler-compiler-ia32.cc49
-rw-r--r--deps/v8/src/ic/ia32/ic-ia32.cc47
-rw-r--r--deps/v8/src/ic/ic-compiler.cc121
-rw-r--r--deps/v8/src/ic/ic-compiler.h40
-rw-r--r--deps/v8/src/ic/ic-inl.h34
-rw-r--r--deps/v8/src/ic/ic-state.cc8
-rw-r--r--deps/v8/src/ic/ic-state.h94
-rw-r--r--deps/v8/src/ic/ic.cc898
-rw-r--r--deps/v8/src/ic/ic.h144
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc255
-rw-r--r--deps/v8/src/ic/mips/handler-compiler-mips.cc39
-rw-r--r--deps/v8/src/ic/mips/ic-mips.cc37
-rw-r--r--deps/v8/src/ic/mips64/handler-compiler-mips64.cc39
-rw-r--r--deps/v8/src/ic/mips64/ic-mips64.cc37
-rw-r--r--deps/v8/src/ic/ppc/handler-compiler-ppc.cc44
-rw-r--r--deps/v8/src/ic/ppc/ic-ppc.cc37
-rw-r--r--deps/v8/src/ic/s390/handler-compiler-s390.cc42
-rw-r--r--deps/v8/src/ic/s390/ic-s390.cc34
-rw-r--r--deps/v8/src/ic/stub-cache.cc14
-rw-r--r--deps/v8/src/ic/stub-cache.h4
-rw-r--r--deps/v8/src/ic/x64/access-compiler-x64.cc1
-rw-r--r--deps/v8/src/ic/x64/handler-compiler-x64.cc48
-rw-r--r--deps/v8/src/ic/x64/ic-x64.cc48
-rw-r--r--deps/v8/src/ic/x87/handler-compiler-x87.cc49
-rw-r--r--deps/v8/src/ic/x87/ic-x87.cc47
38 files changed, 1681 insertions, 2031 deletions
diff --git a/deps/v8/src/ic/access-compiler.cc b/deps/v8/src/ic/access-compiler.cc
index d92f9c0c53..d210ea8c71 100644
--- a/deps/v8/src/ic/access-compiler.cc
+++ b/deps/v8/src/ic/access-compiler.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/ic/access-compiler.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/accessor-assembler-impl.h b/deps/v8/src/ic/accessor-assembler-impl.h
deleted file mode 100644
index 1699b5c855..0000000000
--- a/deps/v8/src/ic/accessor-assembler-impl.h
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2016 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
-#define V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
-
-#include "src/code-stub-assembler.h"
-
-namespace v8 {
-namespace internal {
-
-namespace compiler {
-class CodeAssemblerState;
-}
-
-using compiler::Node;
-
-#define ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(V) \
- V(LoadIC) \
- V(LoadField) \
- V(LoadICTrampoline) \
- V(KeyedLoadICTF) \
- V(KeyedLoadICTrampolineTF) \
- V(KeyedLoadICMegamorphic) \
- V(StoreIC) \
- V(StoreICTrampoline)
-// The other IC entry points need custom handling because of additional
-// parameters like "typeof_mode" or "language_mode".
-
-class AccessorAssemblerImpl : public CodeStubAssembler {
- public:
- explicit AccessorAssemblerImpl(compiler::CodeAssemblerState* state)
- : CodeStubAssembler(state) {}
-
-#define DECLARE_PUBLIC_METHOD(Name) void Generate##Name();
-
- ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DECLARE_PUBLIC_METHOD)
-#undef DECLARE_PUBLIC_METHOD
-
- void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
-
- void GenerateLoadGlobalIC(TypeofMode typeof_mode);
- void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
-
- void GenerateKeyedStoreICTF(LanguageMode language_mode);
- void GenerateKeyedStoreICTrampolineTF(LanguageMode language_mode);
-
- void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
- Label* if_handler, Variable* var_handler,
- Label* if_miss);
-
- Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
- return StubCachePrimaryOffset(name, map);
- }
- Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
- return StubCacheSecondaryOffset(name, map);
- }
-
- protected:
- struct LoadICParameters {
- LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
- Node* vector)
- : context(context),
- receiver(receiver),
- name(name),
- slot(slot),
- vector(vector) {}
-
- Node* context;
- Node* receiver;
- Node* name;
- Node* slot;
- Node* vector;
- };
-
- struct StoreICParameters : public LoadICParameters {
- StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
- Node* slot, Node* vector)
- : LoadICParameters(context, receiver, name, slot, vector),
- value(value) {}
- Node* value;
- };
-
- enum ElementSupport { kOnlyProperties, kSupportElements };
- void HandleStoreICHandlerCase(
- const StoreICParameters* p, Node* handler, Label* miss,
- ElementSupport support_elements = kOnlyProperties);
-
- private:
- // Stub generation entry points.
-
- void LoadIC(const LoadICParameters* p);
- void LoadICProtoArray(const LoadICParameters* p, Node* handler,
- bool throw_reference_error_if_nonexistent);
- void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
- void KeyedLoadIC(const LoadICParameters* p);
- void KeyedLoadICGeneric(const LoadICParameters* p);
- void StoreIC(const StoreICParameters* p);
- void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
-
- // IC dispatcher behavior.
-
- // Checks monomorphic case. Returns {feedback} entry of the vector.
- Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map,
- Label* if_handler, Variable* var_handler,
- Label* if_miss);
- void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
- Label* if_handler, Variable* var_handler,
- Label* if_miss, int unroll_count);
- void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback,
- Label* if_handler, Variable* var_handler,
- Label* if_transition_handler,
- Variable* var_transition_map_cell,
- Label* if_miss);
-
- // LoadIC implementation.
-
- void HandleLoadICHandlerCase(
- const LoadICParameters* p, Node* handler, Label* miss,
- ElementSupport support_elements = kOnlyProperties);
-
- void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
- Node* smi_handler, Label* miss,
- ElementSupport support_elements);
-
- void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
- Variable* var_holder,
- Variable* var_smi_handler,
- Label* if_smi_handler, Label* miss,
- bool throw_reference_error_if_nonexistent);
-
- Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
- Node* handler_length, Node* handler_flags,
- Label* miss,
- bool throw_reference_error_if_nonexistent);
-
- // LoadGlobalIC implementation.
-
- void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
- Label* miss,
- bool throw_reference_error_if_nonexistent);
-
- // StoreIC implementation.
-
- void HandleStoreICElementHandlerCase(const StoreICParameters* p,
- Node* handler, Label* miss);
-
- void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
- Label* miss);
- // If |transition| is nullptr then the normal field store is generated or
- // transitioning store otherwise.
- void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
- Node* value, Node* transition, Label* miss);
- // If |transition| is nullptr then the normal field store is generated or
- // transitioning store otherwise.
- void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
- Representation representation, Node* value,
- Node* transition, Label* miss);
-
- // Low-level helpers.
-
- Node* PrepareValueForStore(Node* handler_word, Node* holder,
- Representation representation, Node* transition,
- Node* value, Label* bailout);
-
- // Extends properties backing store by JSObject::kFieldsAdded elements.
- void ExtendPropertiesBackingStore(Node* object);
-
- void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
- Representation representation, Node* value,
- bool transition_to_field);
-
- void EmitFastElementsBoundsCheck(Node* object, Node* elements,
- Node* intptr_index,
- Node* is_jsarray_condition, Label* miss);
- void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
- Node* key, Node* is_jsarray_condition, Label* if_hole,
- Label* rebox_double, Variable* var_double_value,
- Label* unimplemented_elements_kind, Label* out_of_bounds,
- Label* miss);
- void CheckPrototype(Node* prototype_cell, Node* name, Label* miss);
- void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss);
-
- // Stub cache access helpers.
-
- // This enum is used here as a replacement for StubCache::Table to avoid
- // including stub cache header.
- enum StubCacheTable : int;
-
- Node* StubCachePrimaryOffset(Node* name, Node* map);
- Node* StubCacheSecondaryOffset(Node* name, Node* seed);
-
- void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
- Node* entry_offset, Node* name, Node* map,
- Label* if_handler, Variable* var_handler,
- Label* if_miss);
-};
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index c2b2d17950..d3379ab6d2 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -3,25 +3,27 @@
// found in the LICENSE file.
#include "src/ic/accessor-assembler.h"
-#include "src/ic/accessor-assembler-impl.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
+#include "src/counters.h"
#include "src/ic/handler-configuration.h"
#include "src/ic/stub-cache.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
using compiler::CodeAssemblerState;
+using compiler::Node;
//////////////////// Private helpers.
-Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector,
- Node* receiver_map,
- Label* if_handler,
- Variable* var_handler,
- Label* if_miss) {
+Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector,
+ Node* receiver_map,
+ Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
Comment("TryMonomorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@@ -51,9 +53,11 @@ Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector,
return feedback;
}
-void AccessorAssemblerImpl::HandlePolymorphicCase(
- Node* receiver_map, Node* feedback, Label* if_handler,
- Variable* var_handler, Label* if_miss, int unroll_count) {
+void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
+ Node* feedback, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss,
+ int unroll_count) {
Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@@ -78,7 +82,7 @@ void AccessorAssemblerImpl::HandlePolymorphicCase(
Node* init = IntPtrConstant(unroll_count * kEntrySize);
Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
BuildFastLoop(
- MachineType::PointerRepresentation(), init, length,
+ init, length,
[this, receiver_map, feedback, if_handler, var_handler](Node* index) {
Node* cached_map =
LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
@@ -93,12 +97,12 @@ void AccessorAssemblerImpl::HandlePolymorphicCase(
Bind(&next_entry);
},
- kEntrySize, IndexAdvanceMode::kPost);
+ kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// The loop falls through if no handler was found.
Goto(if_miss);
}
-void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
+void AccessorAssembler::HandleKeyedStorePolymorphicCase(
Node* receiver_map, Node* feedback, Label* if_handler,
Variable* var_handler, Label* if_transition_handler,
Variable* var_transition_map_cell, Label* if_miss) {
@@ -109,7 +113,7 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
Node* init = IntPtrConstant(0);
Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
- BuildFastLoop(MachineType::PointerRepresentation(), init, length,
+ BuildFastLoop(init, length,
[this, receiver_map, feedback, if_handler, var_handler,
if_transition_handler, var_transition_map_cell](Node* index) {
Node* cached_map =
@@ -130,15 +134,17 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
Bind(&next_entry);
},
- kEntrySize, IndexAdvanceMode::kPost);
+ kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// The loop falls through if no handler was found.
Goto(if_miss);
}
-void AccessorAssemblerImpl::HandleLoadICHandlerCase(
+void AccessorAssembler::HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
Comment("have_handler");
+ ExitPoint direct_exit(this);
+
Variable var_holder(this, MachineRepresentation::kTagged);
var_holder.Bind(p->receiver);
Variable var_smi_handler(this, MachineRepresentation::kTagged);
@@ -155,14 +161,14 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase(
Bind(&if_smi_handler);
{
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
- miss, support_elements);
+ miss, &direct_exit, support_elements);
}
Bind(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss, false);
+ &if_smi_handler, miss, &direct_exit, false);
}
Bind(&call_handler);
@@ -173,9 +179,9 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase(
}
}
-void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
+void AccessorAssembler::HandleLoadICSmiHandlerCase(
const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
- ElementSupport support_elements) {
+ ExitPoint* exit_point, ElementSupport support_elements) {
Variable var_double_value(this, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
@@ -183,7 +189,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
if (support_elements == kSupportElements) {
Label property(this);
- GotoUnless(
+ GotoIfNot(
WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
&property);
@@ -199,7 +205,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
EmitElementLoad(holder, elements, elements_kind, intptr_index,
is_jsarray_condition, &if_hole, &rebox_double,
&var_double_value, &unimplemented_elements_kind,
- out_of_bounds, miss);
+ out_of_bounds, miss, exit_point);
Bind(&unimplemented_elements_kind);
{
@@ -212,14 +218,14 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Bind(&if_hole);
{
Comment("convert hole");
- GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
+ GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
miss);
- Return(UndefinedConstant());
+ exit_point->Return(UndefinedConstant());
}
Bind(&property);
@@ -243,7 +249,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
{
Label is_double(this);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
- Return(LoadObjectField(holder, offset));
+ exit_point->Return(LoadObjectField(holder, offset));
Bind(&is_double);
if (FLAG_unbox_double_fields) {
@@ -262,7 +268,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Node* properties = LoadProperties(holder);
Node* value = LoadObjectField(properties, offset);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
- Return(value);
+ exit_point->Return(value);
Bind(&is_double);
var_double_value.Bind(LoadHeapNumberValue(value));
@@ -270,7 +276,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
}
Bind(&rebox_double);
- Return(AllocateHeapNumberWithValue(var_double_value.value()));
+ exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
}
Bind(&constant);
@@ -287,18 +293,19 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Label if_accessor_info(this);
GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
&if_accessor_info);
- Return(value);
+ exit_point->Return(value);
Bind(&if_accessor_info);
Callable callable = CodeFactory::ApiGetter(isolate());
- TailCallStub(callable, p->context, p->receiver, holder, value);
+ exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
+ value);
}
}
-void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
+void AccessorAssembler::HandleLoadICProtoHandlerCase(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
- bool throw_reference_error_if_nonexistent) {
+ ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
@@ -327,7 +334,7 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
Node* handler_flags = SmiUntag(smi_handler);
Label check_prototypes(this);
- GotoUnless(
+ GotoIfNot(
IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
&check_prototypes);
{
@@ -350,9 +357,10 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
// This is a handler for a load of a non-existent value.
if (throw_reference_error_if_nonexistent) {
- TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name);
+ exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
+ p->name);
} else {
- Return(UndefinedConstant());
+ exit_point->Return(UndefinedConstant());
}
Bind(&load_existent);
@@ -368,15 +376,14 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
Bind(&array_handler);
{
- typedef LoadICProtoArrayDescriptor Descriptor;
- LoadICProtoArrayStub stub(isolate(), throw_reference_error_if_nonexistent);
- Node* target = HeapConstant(stub.GetCode());
- TailCallStub(Descriptor(isolate()), target, p->context, p->receiver,
- p->name, p->slot, p->vector, handler);
+ exit_point->ReturnCallStub(
+ CodeFactory::LoadICProtoArray(isolate(),
+ throw_reference_error_if_nonexistent),
+ p->context, p->receiver, p->name, p->slot, p->vector, handler);
}
}
-Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
+Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
const LoadICParameters* p, Node* handler, Node* handler_length,
Node* handler_flags, Label* miss,
bool throw_reference_error_if_nonexistent) {
@@ -384,8 +391,8 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
Label can_access(this);
- GotoUnless(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
- &can_access);
+ GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
+ &can_access);
{
// Skip this entry of a handler.
start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
@@ -399,7 +406,7 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
Node* native_context = LoadNativeContext(p->context);
GotoIf(WordEqual(expected_native_context, native_context), &can_access);
// If the receiver is not a JSGlobalProxy then we miss.
- GotoUnless(IsJSGlobalProxy(p->receiver), miss);
+ GotoIfNot(IsJSGlobalProxy(p->receiver), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
Node* expected_token = LoadContextElement(expected_native_context,
@@ -410,13 +417,13 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
}
Bind(&can_access);
- BuildFastLoop(
- MachineType::PointerRepresentation(), start_index.value(), handler_length,
- [this, p, handler, miss](Node* current) {
- Node* prototype_cell = LoadFixedArrayElement(handler, current);
- CheckPrototype(prototype_cell, p->name, miss);
- },
- 1, IndexAdvanceMode::kPost);
+ BuildFastLoop(start_index.value(), handler_length,
+ [this, p, handler, miss](Node* current) {
+ Node* prototype_cell =
+ LoadFixedArrayElement(handler, current);
+ CheckPrototype(prototype_cell, p->name, miss);
+ },
+ 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
Node* maybe_holder_cell =
LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
@@ -438,9 +445,9 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
return holder;
}
-void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase(
+void AccessorAssembler::HandleLoadGlobalICHandlerCase(
const LoadICParameters* pp, Node* handler, Label* miss,
- bool throw_reference_error_if_nonexistent) {
+ ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
LoadICParameters p = *pp;
DCHECK_NULL(p.receiver);
Node* native_context = LoadNativeContext(p.context);
@@ -450,14 +457,14 @@ void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase(
Variable var_smi_handler(this, MachineRepresentation::kTagged);
Label if_smi_handler(this);
HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss,
+ &if_smi_handler, miss, exit_point,
throw_reference_error_if_nonexistent);
Bind(&if_smi_handler);
HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
- miss, kOnlyProperties);
+ miss, exit_point, kOnlyProperties);
}
-void AccessorAssemblerImpl::HandleStoreICHandlerCase(
+void AccessorAssembler::HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
Label if_smi_handler(this), if_nonsmi_handler(this);
@@ -504,7 +511,7 @@ void AccessorAssemblerImpl::HandleStoreICHandlerCase(
}
}
-void AccessorAssemblerImpl::HandleStoreICElementHandlerCase(
+void AccessorAssembler::HandleStoreICElementHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss) {
Comment("HandleStoreICElementHandlerCase");
Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
@@ -521,8 +528,8 @@ void AccessorAssemblerImpl::HandleStoreICElementHandlerCase(
p->value, p->slot, p->vector);
}
-void AccessorAssemblerImpl::HandleStoreICProtoHandler(
- const StoreICParameters* p, Node* handler, Label* miss) {
+void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
+ Node* handler, Label* miss) {
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset ==
StoreHandler::kTransitionCellOffset);
@@ -564,14 +571,13 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler(
Bind(&array_handler);
{
Node* length = SmiUntag(maybe_transition_cell);
- BuildFastLoop(MachineType::PointerRepresentation(),
- IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
+ BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
[this, p, handler, miss](Node* current) {
Node* prototype_cell =
LoadFixedArrayElement(handler, current);
CheckPrototype(prototype_cell, p->name, miss);
},
- 1, IndexAdvanceMode::kPost);
+ 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
Node* maybe_transition_cell =
LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
@@ -613,11 +619,10 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler(
}
}
-void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
- Node* holder,
- Node* value,
- Node* transition,
- Label* miss) {
+void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
+ Node* holder, Node* value,
+ Node* transition,
+ Label* miss) {
Comment(transition ? "transitioning field store" : "field store");
#ifdef DEBUG
@@ -631,8 +636,17 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant))));
} else {
- CSA_ASSERT(this, WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kStoreField)));
+ if (FLAG_track_constant_fields) {
+ CSA_ASSERT(
+ this,
+ Word32Or(WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreField)),
+ WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreConstField))));
+ } else {
+ CSA_ASSERT(this, WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreField)));
+ }
}
#endif
@@ -683,9 +697,11 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
}
}
-void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
- Node* handler_word, Node* holder, Representation representation,
- Node* value, Node* transition, Label* miss) {
+void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
+ Node* holder,
+ Representation representation,
+ Node* value, Node* transition,
+ Label* miss) {
bool transition_to_field = transition != nullptr;
Node* prepared_value = PrepareValueForStore(
handler_word, holder, representation, transition, value, miss);
@@ -697,7 +713,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
Bind(&if_inobject);
{
StoreNamedField(handler_word, holder, true, representation, prepared_value,
- transition_to_field);
+ transition_to_field, miss);
if (transition_to_field) {
StoreMap(holder, transition);
}
@@ -708,8 +724,8 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
{
if (transition_to_field) {
Label storage_extended(this);
- GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
- &storage_extended);
+ GotoIfNot(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
+ &storage_extended);
Comment("[ Extend storage");
ExtendPropertiesBackingStore(holder);
Comment("] Extend storage");
@@ -719,7 +735,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
}
StoreNamedField(handler_word, holder, false, representation, prepared_value,
- transition_to_field);
+ transition_to_field, miss);
if (transition_to_field) {
StoreMap(holder, transition);
}
@@ -727,16 +743,24 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
}
}
-Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
- Node* holder,
- Representation representation,
- Node* transition, Node* value,
- Label* bailout) {
+Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
+ Representation representation,
+ Node* transition, Node* value,
+ Label* bailout) {
if (representation.IsDouble()) {
value = TryTaggedToFloat64(value, bailout);
} else if (representation.IsHeapObject()) {
GotoIf(TaggedIsSmi(value), bailout);
+
+ Label done(this);
+ if (FLAG_track_constant_fields && !transition) {
+ // Skip field type check in favor of constant value check when storing
+ // to constant field.
+ GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
+ IntPtrConstant(StoreHandler::kStoreConstField)),
+ &done);
+ }
Node* value_index_in_descriptor =
DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
Node* descriptors =
@@ -744,7 +768,6 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
Node* maybe_field_type =
LoadFixedArrayElement(descriptors, value_index_in_descriptor);
- Label done(this);
GotoIf(TaggedIsSmi(maybe_field_type), &done);
// Check that value type matches the field type.
{
@@ -754,7 +777,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
Bind(&done);
} else if (representation.IsSmi()) {
- GotoUnless(TaggedIsSmi(value), bailout);
+ GotoIfNot(TaggedIsSmi(value), bailout);
} else {
DCHECK(representation.IsTagged());
@@ -762,7 +785,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
return value;
}
-void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) {
+void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) {
Node* properties = LoadProperties(object);
Node* length = LoadFixedArrayBaseLength(properties);
@@ -798,11 +821,11 @@ void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) {
StoreObjectField(object, JSObject::kPropertiesOffset, new_properties);
}
-void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
- bool is_inobject,
- Representation representation,
- Node* value,
- bool transition_to_field) {
+void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
+ bool is_inobject,
+ Representation representation,
+ Node* value, bool transition_to_field,
+ Label* bailout) {
bool store_value_as_double = representation.IsDouble();
Node* property_storage = object;
if (!is_inobject) {
@@ -826,6 +849,27 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
}
}
+ // Do constant value check if necessary.
+ if (FLAG_track_constant_fields && !transition_to_field) {
+ Label done(this);
+ GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
+ IntPtrConstant(StoreHandler::kStoreConstField)),
+ &done);
+ {
+ if (store_value_as_double) {
+ Node* current_value =
+ LoadObjectField(property_storage, offset, MachineType::Float64());
+ GotoIfNot(Float64Equal(current_value, value), bailout);
+ } else {
+ Node* current_value = LoadObjectField(property_storage, offset);
+ GotoIfNot(WordEqual(current_value, value), bailout);
+ }
+ Goto(&done);
+ }
+ Bind(&done);
+ }
+
+ // Do the store.
if (store_value_as_double) {
StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
MachineRepresentation::kFloat64);
@@ -836,9 +880,11 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
}
}
-void AccessorAssemblerImpl::EmitFastElementsBoundsCheck(
- Node* object, Node* elements, Node* intptr_index,
- Node* is_jsarray_condition, Label* miss) {
+void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
+ Node* elements,
+ Node* intptr_index,
+ Node* is_jsarray_condition,
+ Label* miss) {
Variable var_length(this, MachineType::PointerRepresentation());
Comment("Fast elements bounds check");
Label if_array(this), length_loaded(this, &var_length);
@@ -853,14 +899,14 @@ void AccessorAssemblerImpl::EmitFastElementsBoundsCheck(
Goto(&length_loaded);
}
Bind(&length_loaded);
- GotoUnless(UintPtrLessThan(intptr_index, var_length.value()), miss);
+ GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
}
-void AccessorAssemblerImpl::EmitElementLoad(
+void AccessorAssembler::EmitElementLoad(
Node* object, Node* elements, Node* elements_kind, Node* intptr_index,
Node* is_jsarray_condition, Label* if_hole, Label* rebox_double,
Variable* var_double_value, Label* unimplemented_elements_kind,
- Label* out_of_bounds, Label* miss) {
+ Label* out_of_bounds, Label* miss, ExitPoint* exit_point) {
Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
if_dictionary(this);
@@ -892,7 +938,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
Bind(&if_fast_packed);
{
Comment("fast packed elements");
- Return(LoadFixedArrayElement(elements, intptr_index));
+ exit_point->Return(LoadFixedArrayElement(elements, intptr_index));
}
Bind(&if_fast_holey);
@@ -900,7 +946,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
Comment("fast holey elements");
Node* element = LoadFixedArrayElement(elements, intptr_index);
GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
- Return(element);
+ exit_point->Return(element);
}
Bind(&if_fast_double);
@@ -943,16 +989,15 @@ void AccessorAssemblerImpl::EmitElementLoad(
elements, intptr_index, &if_found, &var_entry, if_hole);
Bind(&if_found);
// Check that the value is a data property.
- Node* details_index = EntryToIndex<SeededNumberDictionary>(
- var_entry.value(), SeededNumberDictionary::kEntryDetailsIndex);
- Node* details = SmiToWord32(LoadFixedArrayElement(elements, details_index));
+ Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value());
+ Node* details =
+ LoadDetailsByKeyIndex<SeededNumberDictionary>(elements, index);
Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
// TODO(jkummerow): Support accessors without missing?
- GotoUnless(Word32Equal(kind, Int32Constant(kData)), miss);
+ GotoIfNot(Word32Equal(kind, Int32Constant(kData)), miss);
// Finally, load the value.
- Node* value_index = EntryToIndex<SeededNumberDictionary>(
- var_entry.value(), SeededNumberDictionary::kEntryValueIndex);
- Return(LoadFixedArrayElement(elements, value_index));
+ exit_point->Return(
+ LoadValueByKeyIndex<SeededNumberDictionary>(elements, index));
}
Bind(&if_typed_array);
@@ -965,7 +1010,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
// Bounds check.
Node* length =
SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
- GotoUnless(UintPtrLessThan(intptr_index, length), out_of_bounds);
+ GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
// Backing store = external_pointer + base_pointer.
Node* external_pointer =
@@ -998,41 +1043,41 @@ void AccessorAssemblerImpl::EmitElementLoad(
{
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&int8_elements);
{
Comment("INT8_ELEMENTS");
Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&uint16_elements);
{
Comment("UINT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Uint16(), backing_store, index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&int16_elements);
{
Comment("INT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Int16(), backing_store, index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&uint32_elements);
{
Comment("UINT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Uint32(), backing_store, index);
- Return(ChangeUint32ToTagged(element));
+ exit_point->Return(ChangeUint32ToTagged(element));
}
Bind(&int32_elements);
{
Comment("INT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Int32(), backing_store, index);
- Return(ChangeInt32ToTagged(element));
+ exit_point->Return(ChangeInt32ToTagged(element));
}
Bind(&float32_elements);
{
@@ -1053,8 +1098,8 @@ void AccessorAssemblerImpl::EmitElementLoad(
}
}
-void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name,
- Label* miss) {
+void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name,
+ Label* miss) {
Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss);
Label done(this);
@@ -1083,9 +1128,8 @@ void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name,
Bind(&done);
}
-void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object,
- Node* name,
- Label* miss) {
+void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
+ Label* miss) {
CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
Node* properties = LoadProperties(object);
// Ensure the property does not exist in a dictionary-mode object.
@@ -1096,14 +1140,199 @@ void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object,
Bind(&done);
}
+void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* index,
+ Label* slow) {
+ Comment("integer index");
+
+ ExitPoint direct_exit(this);
+
+ Label if_element_hole(this), if_oob(this);
+ // Receivers requiring non-standard element accesses (interceptors, access
+ // checks, strings and string wrappers, proxies) are handled in the runtime.
+ GotoIf(Int32LessThanOrEqual(instance_type,
+ Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
+ slow);
+ Node* elements = LoadElements(receiver);
+ Node* elements_kind = LoadMapElementsKind(receiver_map);
+ Node* is_jsarray_condition =
+ Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
+ Variable var_double_value(this, MachineRepresentation::kFloat64);
+ Label rebox_double(this, &var_double_value);
+
+ // Unimplemented elements kinds fall back to a runtime call.
+ Label* unimplemented_elements_kind = slow;
+ IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
+ EmitElementLoad(receiver, elements, elements_kind, index,
+ is_jsarray_condition, &if_element_hole, &rebox_double,
+ &var_double_value, unimplemented_elements_kind, &if_oob, slow,
+ &direct_exit);
+
+ Bind(&rebox_double);
+ Return(AllocateHeapNumberWithValue(var_double_value.value()));
+
+ Bind(&if_oob);
+ {
+ Comment("out of bounds");
+ // Negative keys can't take the fast OOB path.
+ GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow);
+ // Positive OOB indices are effectively the same as hole loads.
+ Goto(&if_element_hole);
+ }
+
+ Bind(&if_element_hole);
+ {
+ Comment("found the hole");
+ Label return_undefined(this);
+ BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
+
+ Bind(&return_undefined);
+ Return(UndefinedConstant());
+ }
+}
+
+void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* key,
+ const LoadICParameters* p,
+ Label* slow) {
+ Comment("key is unique name");
+ Label if_found_on_receiver(this), if_property_dictionary(this),
+ lookup_prototype_chain(this);
+ Variable var_details(this, MachineRepresentation::kWord32);
+ Variable var_value(this, MachineRepresentation::kTagged);
+
+ // Receivers requiring non-standard accesses (interceptors, access
+ // checks, strings and string wrappers, proxies) are handled in the runtime.
+ GotoIf(Int32LessThanOrEqual(instance_type,
+ Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
+ slow);
+
+ // Check if the receiver has fast or slow properties.
+ Node* properties = LoadProperties(receiver);
+ Node* properties_map = LoadMap(properties);
+ GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
+ &if_property_dictionary);
+
+ // Try looking up the property on the receiver; if unsuccessful, look
+ // for a handler in the stub cache.
+ Node* bitfield3 = LoadMapBitField3(receiver_map);
+ Node* descriptors = LoadMapDescriptors(receiver_map);
+
+ Label if_descriptor_found(this), stub_cache(this);
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found,
+ &var_name_index, &stub_cache);
+
+ Bind(&if_descriptor_found);
+ {
+ LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
+ var_name_index.value(), &var_details,
+ &var_value);
+ Goto(&if_found_on_receiver);
+ }
+
+ Bind(&stub_cache);
+ {
+ Comment("stub cache probe for fast property load");
+ Variable var_handler(this, MachineRepresentation::kTagged);
+ Label found_handler(this, &var_handler), stub_cache_miss(this);
+ TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
+ &found_handler, &var_handler, &stub_cache_miss);
+ Bind(&found_handler);
+ { HandleLoadICHandlerCase(p, var_handler.value(), slow); }
+
+ Bind(&stub_cache_miss);
+ {
+ // TODO(jkummerow): Check if the property exists on the prototype
+ // chain. If it doesn't, then there's no point in missing.
+ Comment("KeyedLoadGeneric_miss");
+ TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
+ p->name, p->slot, p->vector);
+ }
+ }
+
+ Bind(&if_property_dictionary);
+ {
+ Comment("dictionary property load");
+ // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
+ // seeing global objects here (which would need special handling).
+
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ Label dictionary_found(this, &var_name_index);
+ NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
+ &var_name_index,
+ &lookup_prototype_chain);
+ Bind(&dictionary_found);
+ {
+ LoadPropertyFromNameDictionary(properties, var_name_index.value(),
+ &var_details, &var_value);
+ Goto(&if_found_on_receiver);
+ }
+ }
+
+ Bind(&if_found_on_receiver);
+ {
+ Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context, receiver, slow);
+ IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
+ Return(value);
+ }
+
+ Bind(&lookup_prototype_chain);
+ {
+ Variable var_holder_map(this, MachineRepresentation::kTagged);
+ Variable var_holder_instance_type(this, MachineRepresentation::kWord32);
+ Label return_undefined(this);
+ Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
+ Label loop(this, arraysize(merged_variables), merged_variables);
+
+ var_holder_map.Bind(receiver_map);
+ var_holder_instance_type.Bind(instance_type);
+ // Private symbols must not be looked up on the prototype chain.
+ GotoIf(IsPrivateSymbol(key), &return_undefined);
+ Goto(&loop);
+ Bind(&loop);
+ {
+ // Bailout if it can be an integer indexed exotic case.
+ GotoIf(Word32Equal(var_holder_instance_type.value(),
+ Int32Constant(JS_TYPED_ARRAY_TYPE)),
+ slow);
+ Node* proto = LoadMapPrototype(var_holder_map.value());
+ GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
+ Node* proto_map = LoadMap(proto);
+ Node* proto_instance_type = LoadMapInstanceType(proto_map);
+ var_holder_map.Bind(proto_map);
+ var_holder_instance_type.Bind(proto_instance_type);
+ Label next_proto(this), return_value(this, &var_value), goto_slow(this);
+ TryGetOwnProperty(p->context, receiver, proto, proto_map,
+ proto_instance_type, key, &return_value, &var_value,
+ &next_proto, &goto_slow);
+
+ // This trampoline and the next are required to appease Turbofan's
+ // variable merging.
+ Bind(&next_proto);
+ Goto(&loop);
+
+ Bind(&goto_slow);
+ Goto(slow);
+
+ Bind(&return_value);
+ Return(var_value.value());
+ }
+
+ Bind(&return_undefined);
+ Return(UndefinedConstant());
+ }
+}
+
//////////////////// Stub cache access helpers.
-enum AccessorAssemblerImpl::StubCacheTable : int {
+enum AccessorAssembler::StubCacheTable : int {
kPrimary = static_cast<int>(StubCache::kPrimary),
kSecondary = static_cast<int>(StubCache::kSecondary)
};
-Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) {
+Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
// See v8::internal::StubCache::PrimaryOffset().
STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
// Compute the hash of the name (use entire hash field).
@@ -1125,7 +1354,7 @@ Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) {
return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
}
-Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) {
+Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
// See v8::internal::StubCache::SecondaryOffset().
// Use the seed from the primary cache in the secondary cache.
@@ -1137,10 +1366,12 @@ Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) {
return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
}
-void AccessorAssemblerImpl::TryProbeStubCacheTable(
- StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset,
- Node* name, Node* map, Label* if_handler, Variable* var_handler,
- Label* if_miss) {
+void AccessorAssembler::TryProbeStubCacheTable(StubCache* stub_cache,
+ StubCacheTable table_id,
+ Node* entry_offset, Node* name,
+ Node* map, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
StubCache::Table table = static_cast<StubCache::Table>(table_id);
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
@@ -1180,11 +1411,10 @@ void AccessorAssemblerImpl::TryProbeStubCacheTable(
Goto(if_handler);
}
-void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache,
- Node* receiver, Node* name,
- Label* if_handler,
- Variable* var_handler,
- Label* if_miss) {
+void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
+ Node* name, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
Label try_secondary(this), miss(this);
Counters* counters = isolate()->counters();
@@ -1217,7 +1447,7 @@ void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache,
//////////////////// Entry points into private implementation (one per stub).
-void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
+void AccessorAssembler::LoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
@@ -1238,8 +1468,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
{
// Check polymorphic case.
Comment("LoadIC_try_polymorphic");
- GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
- &try_megamorphic);
+ GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@@ -1247,9 +1477,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
Bind(&try_megamorphic);
{
// Check megamorphic case.
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
@@ -1261,13 +1490,15 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::LoadICProtoArray(
+void AccessorAssembler::LoadICProtoArray(
const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent) {
Label miss(this);
CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler)));
+ ExitPoint direct_exit(this);
+
Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
Node* handler_flags = SmiUntag(smi_handler);
@@ -1277,7 +1508,8 @@ void AccessorAssemblerImpl::LoadICProtoArray(
EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
&miss, throw_reference_error_if_nonexistent);
- HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, kOnlyProperties);
+ HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
+ kOnlyProperties);
Bind(&miss);
{
@@ -1286,36 +1518,41 @@ void AccessorAssemblerImpl::LoadICProtoArray(
}
}
-void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p,
- TypeofMode typeof_mode) {
- Label try_handler(this), call_handler(this), miss(this);
- Node* weak_cell =
- LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS);
+void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
+ Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
+ Label* miss, ParameterMode slot_mode) {
+ Comment("LoadGlobalIC_TryPropertyCellCase");
+
+ Node* weak_cell = LoadFixedArrayElement(vector, slot, 0, slot_mode);
CSA_ASSERT(this, HasInstanceType(weak_cell, WEAK_CELL_TYPE));
// Load value or try handler case if the {weak_cell} is cleared.
- Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler);
+ Node* property_cell = LoadWeakCellValue(weak_cell, try_handler);
CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
- GotoIf(WordEqual(value, TheHoleConstant()), &miss);
- Return(value);
+ GotoIf(WordEqual(value, TheHoleConstant()), miss);
+ exit_point->Return(value);
+}
- Node* handler;
- Bind(&try_handler);
- {
- handler =
- LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
- CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
- GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
- &miss);
- GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
+ TypeofMode typeof_mode,
+ ExitPoint* exit_point,
+ Label* miss) {
+ Comment("LoadGlobalIC_TryHandlerCase");
- bool throw_reference_error_if_nonexistent =
- typeof_mode == NOT_INSIDE_TYPEOF;
- HandleLoadGlobalICHandlerCase(p, handler, &miss,
- throw_reference_error_if_nonexistent);
- }
+ Label call_handler(this);
+
+ Node* handler =
+ LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
+ CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
+ GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
+ miss);
+ GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+
+ bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF;
+ HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point,
+ throw_reference_error_if_nonexistent);
Bind(&call_handler);
{
@@ -1323,17 +1560,35 @@ void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p,
Node* native_context = LoadNativeContext(p->context);
Node* receiver =
LoadContextElement(native_context, Context::EXTENSION_INDEX);
- TailCallStub(descriptor, handler, p->context, receiver, p->name, p->slot,
- p->vector);
+ exit_point->ReturnCallStub(descriptor, handler, p->context, receiver,
+ p->name, p->slot, p->vector);
}
+}
+
+void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p,
+ ExitPoint* exit_point) {
+ Comment("LoadGlobalIC_MissCase");
+
+ exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context,
+ p->name, p->slot, p->vector);
+}
+
+void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p,
+ TypeofMode typeof_mode) {
+ ExitPoint direct_exit(this);
+
+ Label try_handler(this), miss(this);
+ LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit,
+ &try_handler, &miss);
+
+ Bind(&try_handler);
+ LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss);
+
Bind(&miss);
- {
- TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->name, p->slot,
- p->vector);
- }
+ LoadGlobalIC_MissCase(p, &direct_exit);
}
-void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
+void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
@@ -1355,8 +1610,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// Check polymorphic case.
Comment("KeyedLoadIC_try_polymorphic");
- GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
- &try_megamorphic);
+ GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@@ -1365,9 +1620,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &try_polymorphic_name);
+ GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &try_polymorphic_name);
// TODO(jkummerow): Inline this? Or some of it?
TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
p->receiver, p->name, p->slot, p->vector);
@@ -1376,7 +1630,7 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedLoadIC_try_polymorphic_name");
- GotoUnless(WordEqual(feedback, p->name), &miss);
+ GotoIfNot(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
Node* offset = ElementOffsetFromIndex(
@@ -1394,150 +1648,30 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) {
+void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Variable var_index(this, MachineType::PointerRepresentation());
- Variable var_details(this, MachineRepresentation::kWord32);
- Variable var_value(this, MachineRepresentation::kTagged);
- Label if_index(this), if_unique_name(this), if_element_hole(this),
- if_oob(this), slow(this), stub_cache_miss(this),
- if_property_dictionary(this), if_found_on_receiver(this);
+ Variable var_unique(this, MachineRepresentation::kTagged);
+ var_unique.Bind(p->name); // Dummy initialization.
+ Label if_index(this), if_unique_name(this), slow(this);
Node* receiver = p->receiver;
GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
- // Receivers requiring non-standard element accesses (interceptors, access
- // checks, strings and string wrappers, proxies) are handled in the runtime.
- GotoIf(Int32LessThanOrEqual(instance_type,
- Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
- &slow);
- Node* key = p->name;
- TryToName(key, &if_index, &var_index, &if_unique_name, &slow);
+ TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
+ &slow);
Bind(&if_index);
{
- Comment("integer index");
- Node* index = var_index.value();
- Node* elements = LoadElements(receiver);
- Node* elements_kind = LoadMapElementsKind(receiver_map);
- Node* is_jsarray_condition =
- Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
- Variable var_double_value(this, MachineRepresentation::kFloat64);
- Label rebox_double(this, &var_double_value);
-
- // Unimplemented elements kinds fall back to a runtime call.
- Label* unimplemented_elements_kind = &slow;
- IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
- EmitElementLoad(receiver, elements, elements_kind, index,
- is_jsarray_condition, &if_element_hole, &rebox_double,
- &var_double_value, unimplemented_elements_kind, &if_oob,
- &slow);
-
- Bind(&rebox_double);
- Return(AllocateHeapNumberWithValue(var_double_value.value()));
- }
-
- Bind(&if_oob);
- {
- Comment("out of bounds");
- Node* index = var_index.value();
- // Negative keys can't take the fast OOB path.
- GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), &slow);
- // Positive OOB indices are effectively the same as hole loads.
- Goto(&if_element_hole);
- }
-
- Bind(&if_element_hole);
- {
- Comment("found the hole");
- Label return_undefined(this);
- BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, &slow);
-
- Bind(&return_undefined);
- Return(UndefinedConstant());
+ GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
+ &slow);
}
- Node* properties = nullptr;
Bind(&if_unique_name);
{
- Comment("key is unique name");
- // Check if the receiver has fast or slow properties.
- properties = LoadProperties(receiver);
- Node* properties_map = LoadMap(properties);
- GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
- &if_property_dictionary);
-
- // Try looking up the property on the receiver; if unsuccessful, look
- // for a handler in the stub cache.
- Comment("DescriptorArray lookup");
-
- // Skip linear search if there are too many descriptors.
- // TODO(jkummerow): Consider implementing binary search.
- // See also TryLookupProperty() which has the same limitation.
- const int32_t kMaxLinear = 210;
- Label stub_cache(this);
- Node* bitfield3 = LoadMapBitField3(receiver_map);
- Node* nof =
- DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
- GotoIf(UintPtrLessThan(IntPtrConstant(kMaxLinear), nof), &stub_cache);
- Node* descriptors = LoadMapDescriptors(receiver_map);
- Variable var_name_index(this, MachineType::PointerRepresentation());
- Label if_descriptor_found(this);
- DescriptorLookupLinear(key, descriptors, nof, &if_descriptor_found,
- &var_name_index, &stub_cache);
-
- Bind(&if_descriptor_found);
- {
- LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
- var_name_index.value(), &var_details,
- &var_value);
- Goto(&if_found_on_receiver);
- }
-
- Bind(&stub_cache);
- {
- Comment("stub cache probe for fast property load");
- Variable var_handler(this, MachineRepresentation::kTagged);
- Label found_handler(this, &var_handler), stub_cache_miss(this);
- TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
- &found_handler, &var_handler, &stub_cache_miss);
- Bind(&found_handler);
- { HandleLoadICHandlerCase(p, var_handler.value(), &slow); }
-
- Bind(&stub_cache_miss);
- {
- Comment("KeyedLoadGeneric_miss");
- TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
- p->name, p->slot, p->vector);
- }
- }
- }
-
- Bind(&if_property_dictionary);
- {
- Comment("dictionary property load");
- // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
- // seeing global objects here (which would need special handling).
-
- Variable var_name_index(this, MachineType::PointerRepresentation());
- Label dictionary_found(this, &var_name_index);
- NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
- &var_name_index, &slow);
- Bind(&dictionary_found);
- {
- LoadPropertyFromNameDictionary(properties, var_name_index.value(),
- &var_details, &var_value);
- Goto(&if_found_on_receiver);
- }
- }
-
- Bind(&if_found_on_receiver);
- {
- Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
- p->context, receiver, &slow);
- IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
- Return(value);
+ GenericPropertyLoad(receiver, receiver_map, instance_type,
+ var_unique.value(), p, &slow);
}
Bind(&slow);
@@ -1550,7 +1684,7 @@ void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
+void AccessorAssembler::StoreIC(const StoreICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
@@ -1574,7 +1708,7 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
{
// Check polymorphic case.
Comment("StoreIC_try_polymorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
@@ -1584,9 +1718,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
Bind(&try_megamorphic);
{
// Check megamorphic case.
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
@@ -1598,8 +1731,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
}
}
-void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
- LanguageMode language_mode) {
+void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
+ LanguageMode language_mode) {
// TODO(ishell): defer blocks when it works.
Label miss(this /*, Label::kDeferred*/);
{
@@ -1627,7 +1760,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// CheckPolymorphic case.
Comment("KeyedStoreIC_try_polymorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
Label if_transition_handler(this);
@@ -1643,7 +1776,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
Label call_handler(this);
Variable var_code_handler(this, MachineRepresentation::kTagged);
var_code_handler.Bind(handler);
- GotoUnless(IsTuple2Map(LoadMap(handler)), &call_handler);
+ GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler);
{
CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
@@ -1677,7 +1810,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// Check megamorphic case.
Comment("KeyedStoreIC_try_megamorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
&try_polymorphic_name);
TailCallStub(
@@ -1689,7 +1822,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedStoreIC_try_polymorphic_name");
- GotoUnless(WordEqual(feedback, p->name), &miss);
+ GotoIfNot(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a FixedArray with
// at least one map/handler pair.
Node* offset = ElementOffsetFromIndex(
@@ -1710,7 +1843,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
//////////////////// Public methods.
-void AccessorAssemblerImpl::GenerateLoadIC() {
+void AccessorAssembler::GenerateLoadIC() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1723,7 +1856,7 @@ void AccessorAssemblerImpl::GenerateLoadIC() {
LoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateLoadICTrampoline() {
+void AccessorAssembler::GenerateLoadICTrampoline() {
typedef LoadDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1736,9 +1869,9 @@ void AccessorAssemblerImpl::GenerateLoadICTrampoline() {
LoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateLoadICProtoArray(
+void AccessorAssembler::GenerateLoadICProtoArray(
bool throw_reference_error_if_nonexistent) {
- typedef LoadICProtoArrayStub::Descriptor Descriptor;
+ typedef LoadICProtoArrayDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
@@ -1751,8 +1884,8 @@ void AccessorAssemblerImpl::GenerateLoadICProtoArray(
LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
}
-void AccessorAssemblerImpl::GenerateLoadField() {
- typedef LoadFieldStub::Descriptor Descriptor;
+void AccessorAssembler::GenerateLoadField() {
+ typedef LoadFieldDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = nullptr;
@@ -1761,11 +1894,13 @@ void AccessorAssemblerImpl::GenerateLoadField() {
Node* context = Parameter(Descriptor::kContext);
LoadICParameters p(context, receiver, name, slot, vector);
+ ExitPoint direct_exit(this);
+
HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
- nullptr, kOnlyProperties);
+ nullptr, &direct_exit, kOnlyProperties);
}
-void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
+void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
typedef LoadGlobalWithVectorDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
@@ -1777,8 +1912,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
LoadGlobalIC(&p, typeof_mode);
}
-void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline(
- TypeofMode typeof_mode) {
+void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
typedef LoadGlobalDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
@@ -1790,7 +1924,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline(
LoadGlobalIC(&p, typeof_mode);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICTF() {
+void AccessorAssembler::GenerateKeyedLoadIC() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1803,7 +1937,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTF() {
KeyedLoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() {
+void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
typedef LoadDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1816,7 +1950,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() {
KeyedLoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() {
+void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1829,7 +1963,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() {
KeyedLoadICGeneric(&p);
}
-void AccessorAssemblerImpl::GenerateStoreIC() {
+void AccessorAssembler::GenerateStoreIC() {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1843,7 +1977,7 @@ void AccessorAssemblerImpl::GenerateStoreIC() {
StoreIC(&p);
}
-void AccessorAssemblerImpl::GenerateStoreICTrampoline() {
+void AccessorAssembler::GenerateStoreICTrampoline() {
typedef StoreDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1857,7 +1991,7 @@ void AccessorAssemblerImpl::GenerateStoreICTrampoline() {
StoreIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) {
+void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1871,7 +2005,7 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) {
KeyedStoreIC(&p, language_mode);
}
-void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF(
+void AccessorAssembler::GenerateKeyedStoreICTrampoline(
LanguageMode language_mode) {
typedef StoreDescriptor Descriptor;
@@ -1886,48 +2020,5 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF(
KeyedStoreIC(&p, language_mode);
}
-//////////////////// AccessorAssembler implementation.
-
-#define DISPATCH_TO_IMPL(Name) \
- void AccessorAssembler::Generate##Name(CodeAssemblerState* state) { \
- AccessorAssemblerImpl assembler(state); \
- assembler.Generate##Name(); \
- }
-
-ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DISPATCH_TO_IMPL)
-#undef DISPATCH_TO_IMPL
-
-void AccessorAssembler::GenerateLoadICProtoArray(
- CodeAssemblerState* state, bool throw_reference_error_if_nonexistent) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadICProtoArray(throw_reference_error_if_nonexistent);
-}
-
-void AccessorAssembler::GenerateLoadGlobalIC(CodeAssemblerState* state,
- TypeofMode typeof_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadGlobalIC(typeof_mode);
-}
-
-void AccessorAssembler::GenerateLoadGlobalICTrampoline(
- CodeAssemblerState* state, TypeofMode typeof_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadGlobalICTrampoline(typeof_mode);
-}
-
-void AccessorAssembler::GenerateKeyedStoreICTF(CodeAssemblerState* state,
- LanguageMode language_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateKeyedStoreICTF(language_mode);
-}
-
-void AccessorAssembler::GenerateKeyedStoreICTrampolineTF(
- CodeAssemblerState* state, LanguageMode language_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateKeyedStoreICTrampolineTF(language_mode);
-}
-
-#undef ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h
index 3b75c2e54d..9bc2873f85 100644
--- a/deps/v8/src/ic/accessor-assembler.h
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -5,7 +5,7 @@
#ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
#define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
-#include "src/globals.h"
+#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
@@ -14,29 +14,268 @@ namespace compiler {
class CodeAssemblerState;
}
-class AccessorAssembler {
+class ExitPoint;
+
+class AccessorAssembler : public CodeStubAssembler {
+ public:
+ typedef compiler::Node Node;
+
+ explicit AccessorAssembler(compiler::CodeAssemblerState* state)
+ : CodeStubAssembler(state) {}
+
+ void GenerateLoadIC();
+ void GenerateLoadField();
+ void GenerateLoadICTrampoline();
+ void GenerateKeyedLoadIC();
+ void GenerateKeyedLoadICTrampoline();
+ void GenerateKeyedLoadIC_Megamorphic();
+ void GenerateStoreIC();
+ void GenerateStoreICTrampoline();
+
+ void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
+
+ void GenerateLoadGlobalIC(TypeofMode typeof_mode);
+ void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
+
+ void GenerateKeyedStoreIC(LanguageMode language_mode);
+ void GenerateKeyedStoreICTrampoline(LanguageMode language_mode);
+
+ void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
+ Label* if_handler, Variable* var_handler,
+ Label* if_miss);
+
+ Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
+ return StubCachePrimaryOffset(name, map);
+ }
+ Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
+ return StubCacheSecondaryOffset(name, map);
+ }
+
+ struct LoadICParameters {
+ LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
+ Node* vector)
+ : context(context),
+ receiver(receiver),
+ name(name),
+ slot(slot),
+ vector(vector) {}
+
+ Node* context;
+ Node* receiver;
+ Node* name;
+ Node* slot;
+ Node* vector;
+ };
+
+ void LoadGlobalIC_TryPropertyCellCase(
+ Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
+ Label* miss, ParameterMode slot_mode = SMI_PARAMETERS);
+ void LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
+ TypeofMode typeof_mode,
+ ExitPoint* exit_point, Label* miss);
+ void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point);
+
+ protected:
+ struct StoreICParameters : public LoadICParameters {
+ StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
+ Node* slot, Node* vector)
+ : LoadICParameters(context, receiver, name, slot, vector),
+ value(value) {}
+ Node* value;
+ };
+
+ enum ElementSupport { kOnlyProperties, kSupportElements };
+ void HandleStoreICHandlerCase(
+ const StoreICParameters* p, Node* handler, Label* miss,
+ ElementSupport support_elements = kOnlyProperties);
+
+ private:
+ // Stub generation entry points.
+
+ void LoadIC(const LoadICParameters* p);
+ void LoadICProtoArray(const LoadICParameters* p, Node* handler,
+ bool throw_reference_error_if_nonexistent);
+ void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
+ void KeyedLoadIC(const LoadICParameters* p);
+ void KeyedLoadICGeneric(const LoadICParameters* p);
+ void StoreIC(const StoreICParameters* p);
+ void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
+
+ // IC dispatcher behavior.
+
+ // Checks monomorphic case. Returns {feedback} entry of the vector.
+ Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map,
+ Label* if_handler, Variable* var_handler,
+ Label* if_miss);
+ void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
+ Label* if_handler, Variable* var_handler,
+ Label* if_miss, int unroll_count);
+ void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback,
+ Label* if_handler, Variable* var_handler,
+ Label* if_transition_handler,
+ Variable* var_transition_map_cell,
+ Label* if_miss);
+
+ // LoadIC implementation.
+
+ void HandleLoadICHandlerCase(
+ const LoadICParameters* p, Node* handler, Label* miss,
+ ElementSupport support_elements = kOnlyProperties);
+
+ void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
+ Node* smi_handler, Label* miss,
+ ExitPoint* exit_point,
+ ElementSupport support_elements);
+
+ void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
+ Variable* var_holder,
+ Variable* var_smi_handler,
+ Label* if_smi_handler, Label* miss,
+ ExitPoint* exit_point,
+ bool throw_reference_error_if_nonexistent);
+
+ Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
+ Node* handler_length, Node* handler_flags,
+ Label* miss,
+ bool throw_reference_error_if_nonexistent);
+
+ // LoadGlobalIC implementation.
+
+ void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
+ Label* miss, ExitPoint* exit_point,
+ bool throw_reference_error_if_nonexistent);
+
+ // StoreIC implementation.
+
+ void HandleStoreICElementHandlerCase(const StoreICParameters* p,
+ Node* handler, Label* miss);
+
+ void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
+ Label* miss);
+ // If |transition| is nullptr then the normal field store is generated or
+ // transitioning store otherwise.
+ void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
+ Node* value, Node* transition, Label* miss);
+ // If |transition| is nullptr then the normal field store is generated or
+ // transitioning store otherwise.
+ void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
+ Representation representation, Node* value,
+ Node* transition, Label* miss);
+
+ // KeyedLoadIC_Generic implementation.
+
+ void GenericElementLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* index, Label* slow);
+
+ void GenericPropertyLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* key,
+ const LoadICParameters* p, Label* slow);
+
+ // Low-level helpers.
+
+ Node* PrepareValueForStore(Node* handler_word, Node* holder,
+ Representation representation, Node* transition,
+ Node* value, Label* bailout);
+
+ // Extends properties backing store by JSObject::kFieldsAdded elements.
+ void ExtendPropertiesBackingStore(Node* object);
+
+ void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
+ Representation representation, Node* value,
+ bool transition_to_field, Label* bailout);
+
+ void EmitFastElementsBoundsCheck(Node* object, Node* elements,
+ Node* intptr_index,
+ Node* is_jsarray_condition, Label* miss);
+ void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
+ Node* key, 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);
+ void CheckPrototype(Node* prototype_cell, Node* name, Label* miss);
+ void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss);
+
+ // Stub cache access helpers.
+
+ // This enum is used here as a replacement for StubCache::Table to avoid
+ // including stub cache header.
+ enum StubCacheTable : int;
+
+ Node* StubCachePrimaryOffset(Node* name, Node* map);
+ Node* StubCacheSecondaryOffset(Node* name, Node* seed);
+
+ void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
+ Node* entry_offset, Node* name, Node* map,
+ Label* if_handler, Variable* var_handler,
+ Label* if_miss);
+};
+
+// Abstraction over direct and indirect exit points. Direct exits correspond to
+// tailcalls and Return, while indirect exits store the result in a variable
+// and then jump to an exit label.
+class ExitPoint {
+ private:
+ typedef compiler::Node Node;
+ typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
+ typedef compiler::CodeAssemblerVariable CodeAssemblerVariable;
+
public:
- static void GenerateLoadIC(compiler::CodeAssemblerState* state);
- static void GenerateLoadICTrampoline(compiler::CodeAssemblerState* state);
- static void GenerateLoadICProtoArray(
- compiler::CodeAssemblerState* state,
- bool throw_reference_error_if_nonexistent);
- static void GenerateLoadGlobalIC(compiler::CodeAssemblerState* state,
- TypeofMode typeof_mode);
- static void GenerateLoadGlobalICTrampoline(
- compiler::CodeAssemblerState* state, TypeofMode typeof_mode);
- static void GenerateKeyedLoadICTF(compiler::CodeAssemblerState* state);
- static void GenerateKeyedLoadICTrampolineTF(
- compiler::CodeAssemblerState* state);
- static void GenerateKeyedLoadICMegamorphic(
- compiler::CodeAssemblerState* state);
- static void GenerateLoadField(compiler::CodeAssemblerState* state);
- static void GenerateStoreIC(compiler::CodeAssemblerState* state);
- static void GenerateStoreICTrampoline(compiler::CodeAssemblerState* state);
- static void GenerateKeyedStoreICTF(compiler::CodeAssemblerState* state,
- LanguageMode language_mode);
- static void GenerateKeyedStoreICTrampolineTF(
- compiler::CodeAssemblerState* state, LanguageMode language_mode);
+ explicit ExitPoint(CodeStubAssembler* assembler)
+ : ExitPoint(assembler, nullptr, nullptr) {}
+ ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
+ CodeAssemblerVariable* var_result)
+ : out_(out), var_result_(var_result), asm_(assembler) {
+ DCHECK_EQ(out != nullptr, var_result != nullptr);
+ }
+
+ template <class... TArgs>
+ void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
+ TArgs... args) {
+ if (IsDirect()) {
+ asm_->TailCallRuntime(function, context, args...);
+ } else {
+ IndirectReturn(asm_->CallRuntime(function, context, args...));
+ }
+ }
+
+ template <class... TArgs>
+ void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
+ if (IsDirect()) {
+ asm_->TailCallStub(callable, context, args...);
+ } else {
+ IndirectReturn(asm_->CallStub(callable, context, args...));
+ }
+ }
+
+ template <class... TArgs>
+ void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
+ Node* context, TArgs... args) {
+ if (IsDirect()) {
+ asm_->TailCallStub(descriptor, target, context, args...);
+ } else {
+ IndirectReturn(asm_->CallStub(descriptor, target, context, args...));
+ }
+ }
+
+ void Return(Node* const result) {
+ if (IsDirect()) {
+ asm_->Return(result);
+ } else {
+ IndirectReturn(result);
+ }
+ }
+
+ bool IsDirect() const { return out_ == nullptr; }
+
+ private:
+ void IndirectReturn(Node* const result) {
+ var_result_->Bind(result);
+ asm_->Goto(out_);
+ }
+
+ CodeAssemblerLabel* const out_;
+ CodeAssemblerVariable* const var_result_;
+ CodeStubAssembler* const asm_;
};
} // namespace internal
diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc
index 3f2d0e42de..ebef63ca66 100644
--- a/deps/v8/src/ic/arm/handler-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc
@@ -181,15 +181,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- __ mov(r0, scratch1);
- __ Ret();
-}
-
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -208,10 +199,12 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ b(ne, miss);
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
@@ -219,15 +212,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
__ push(name);
__ push(receiver);
__ push(holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -530,8 +515,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc
index fad0737a1c..b749027ebe 100644
--- a/deps/v8/src/ic/arm/ic-arm.cc
+++ b/deps/v8/src/ic/arm/ic-arm.cc
@@ -6,45 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -100,9 +67,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(cmp_instruction_address), delta);
+ LOG(isolate, PatchIC(address, cmp_instruction_address, delta));
}
Address patch_address =
diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
index 8c89908f4e..b7dc58974f 100644
--- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
@@ -83,19 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- // TryGetFunctionPrototype can't put the result directly in x0 because the
- // 3 inputs registers can't alias and we call this function from
- // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
- // move the result in x0.
- __ Mov(x0, scratch1);
- __ Ret();
-}
-
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -112,25 +99,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
-
__ Push(name, receiver, holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -566,8 +546,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc
index 04fdff76e1..8c7d4f2241 100644
--- a/deps/v8/src/ic/arm64/ic-arm64.cc
+++ b/deps/v8/src/ic/arm64/ic-arm64.cc
@@ -6,39 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- ASM_LOCATION("KeyedStoreIC::GenerateMiss");
- StoreIC_PushArgs(masm);
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- ASM_LOCATION("KeyedStoreIC::GenerateSlow");
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -86,9 +59,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n",
- static_cast<void*>(address), static_cast<void*>(info_address),
- static_cast<void*>(info.SmiCheck()));
+ LOG(isolate, PatchIC(address, info_address, info.SmiCheckDelta()));
}
// Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi()
diff --git a/deps/v8/src/ic/call-optimization.cc b/deps/v8/src/ic/call-optimization.cc
index f7a1f6982f..6780ac4ca4 100644
--- a/deps/v8/src/ic/call-optimization.cc
+++ b/deps/v8/src/ic/call-optimization.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "src/ic/call-optimization.h"
-
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc
index 16aec0b494..6a9734d5eb 100644
--- a/deps/v8/src/ic/handler-compiler.cc
+++ b/deps/v8/src/ic/handler-compiler.cc
@@ -283,8 +283,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
Handle<Object> smi_handler =
LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex());
__ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler);
- LoadFieldStub stub(isolate());
- GenerateTailCall(masm(), stub.GetCode());
+ GenerateTailCall(masm(), isolate()->builtins()->LoadField());
break;
}
case LookupIterator::ACCESSOR:
@@ -353,7 +352,7 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
}
if (receiver_map->IsStringMap()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
- return LoadIndexedStringStub(isolate).GetCode();
+ return isolate->builtins()->KeyedLoadIC_IndexedString();
}
InstanceType instance_type = receiver_map->instance_type();
if (instance_type < FIRST_JS_RECEIVER_TYPE) {
diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h
index 65f6fbbef3..a37375abfb 100644
--- a/deps/v8/src/ic/handler-compiler.h
+++ b/deps/v8/src/ic/handler-compiler.h
@@ -158,12 +158,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
no_reg);
}
- static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Label* miss_label);
-
// These constants describe the structure of the interceptor arguments on the
// stack. The arguments are pushed by the (platform-specific)
// PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index 8aa887d2b6..437c5288fb 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -103,7 +103,8 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
}
int value_index = DescriptorArray::ToValueIndex(descriptor);
- DCHECK(kind == kStoreField || kind == kTransitionToField);
+ DCHECK(kind == kStoreField || kind == kTransitionToField ||
+ (kind == kStoreConstField && FLAG_track_constant_fields));
DCHECK_IMPLIES(extend_storage, kind == kTransitionToField);
DCHECK_IMPLIES(field_index.is_inobject(), !extend_storage);
@@ -118,9 +119,12 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
+ PropertyConstness constness,
Representation representation) {
- return StoreField(isolate, kStoreField, descriptor, field_index,
- representation, false);
+ DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
+ Kind kind = constness == kMutable ? kStoreField : kStoreConstField;
+ return StoreField(isolate, kind, descriptor, field_index, representation,
+ false);
}
Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
@@ -133,6 +137,7 @@ Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
Handle<Object> StoreHandler::TransitionToConstant(Isolate* isolate,
int descriptor) {
+ DCHECK(!FLAG_track_constant_fields);
int value_index = DescriptorArray::ToValueIndex(descriptor);
int config =
StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) |
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index a5291736dc..539d448008 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -121,8 +121,10 @@ class StoreHandler {
enum Kind {
kStoreElement,
kStoreField,
+ kStoreConstField,
kTransitionToField,
- kTransitionToConstant
+ // TODO(ishell): remove once constant field tracking is done.
+ kTransitionToConstant = kStoreConstField
};
class KindBits : public BitField<Kind, 0, 2> {};
@@ -175,6 +177,7 @@ class StoreHandler {
// Creates a Smi-handler for storing a field to fast object.
static inline Handle<Object> StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
+ PropertyConstness constness,
Representation representation);
// Creates a Smi-handler for transitioning store to a field.
diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
index b63e82b70a..f0f8faddde 100644
--- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
+++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
@@ -122,15 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- // TODO(mvstanton): This isn't used on ia32. Move all the other
- // platform implementations into a code stub so this method can be removed.
- UNREACHABLE();
-}
-
-
// Generate call to api function.
// This function uses push() to generate smaller, faster code than
// the version above. It is an optimization that should will be removed
@@ -302,10 +293,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
}
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
@@ -313,15 +306,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
__ push(name);
__ push(receiver);
__ push(holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -538,10 +523,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
- __ pop(scratch2()); // save old return address
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
- __ push(scratch2()); // restore old return address
+
+ // Stack:
+ // return address
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ push(receiver());
+ __ push(holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ push(slot());
+ __ push(vector());
+ } else {
+ __ push(scratch3()); // slot
+ __ push(scratch2()); // vector
+ }
+ __ push(Operand(esp, 4 * kPointerSize)); // return address
+ __ mov(Operand(esp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/ia32/ic-ia32.cc b/deps/v8/src/ic/ia32/ic-ia32.cc
index 4bf0eaee92..c4b4cdcc2b 100644
--- a/deps/v8/src/ic/ia32/ic-ia32.cc
+++ b/deps/v8/src/ic/ia32/ic-ia32.cc
@@ -6,54 +6,11 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
- Register name = StoreWithVectorDescriptor::NameRegister();
-
- STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
- // Current stack layout:
- // - esp[12] -- value
- // - esp[8] -- slot
- // - esp[4] -- vector
- // - esp[0] -- return address
-
- Register return_address = StoreWithVectorDescriptor::SlotRegister();
- __ pop(return_address);
- __ push(receiver);
- __ push(name);
- __ push(return_address);
-}
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
@@ -104,9 +61,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(test_instruction_address), delta);
+ LOG(isolate, PatchIC(address, test_instruction_address, delta));
}
// Patch with a short conditional jump. Enabling means switching from a short
diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc
deleted file mode 100644
index fcda0c1fa3..0000000000
--- a/deps/v8/src/ic/ic-compiler.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/ic/ic-compiler.h"
-
-#include "src/ic/handler-compiler.h"
-#include "src/ic/ic-inl.h"
-
-namespace v8 {
-namespace internal {
-
-Handle<Object> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
- Isolate* isolate = receiver_map->GetIsolate();
-
- DCHECK(store_mode == STANDARD_STORE ||
- store_mode == STORE_AND_GROW_NO_TRANSITION ||
- store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
- store_mode == STORE_NO_TRANSITION_HANDLE_COW);
-
- PropertyICCompiler compiler(isolate);
- Handle<Object> handler =
- compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
- return handler;
-}
-
-void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
- MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) {
- Isolate* isolate = receiver_maps->at(0)->GetIsolate();
- DCHECK(store_mode == STANDARD_STORE ||
- store_mode == STORE_AND_GROW_NO_TRANSITION ||
- store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
- store_mode == STORE_NO_TRANSITION_HANDLE_COW);
- PropertyICCompiler compiler(isolate);
- compiler.CompileKeyedStorePolymorphicHandlers(
- receiver_maps, transitioned_maps, handlers, store_mode);
-}
-
-void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
- MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) {
- for (int i = 0; i < receiver_maps->length(); ++i) {
- Handle<Map> receiver_map(receiver_maps->at(i));
- Handle<Object> handler;
- Handle<Map> transitioned_map;
- {
- Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
- if (tmap != nullptr) transitioned_map = handle(tmap);
- }
-
- // TODO(mvstanton): The code below is doing pessimistic elements
- // transitions. I would like to stop doing that and rely on Allocation Site
- // Tracking to do a better job of ensuring the data types are what they need
- // to be. Not all the elements are in place yet, pessimistic elements
- // transitions are still important for performance.
- if (!transitioned_map.is_null()) {
- bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
- ElementsKind elements_kind = receiver_map->elements_kind();
- TRACE_HANDLER_STATS(isolate(),
- KeyedStoreIC_ElementsTransitionAndStoreStub);
- Handle<Code> stub =
- ElementsTransitionAndStoreStub(isolate(), elements_kind,
- transitioned_map->elements_kind(),
- is_js_array, store_mode)
- .GetCode();
- Handle<Object> validity_cell =
- Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
- if (validity_cell.is_null()) {
- handler = stub;
- } else {
- handler = isolate()->factory()->NewTuple2(validity_cell, stub);
- }
-
- } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
- // TODO(mvstanton): Consider embedding store_mode in the state of the slow
- // keyed store ic for uniformity.
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
- handler = isolate()->builtins()->KeyedStoreIC_Slow();
- } else {
- handler = CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
- }
- DCHECK(!handler.is_null());
- handlers->Add(handler);
- transitioned_maps->Add(transitioned_map);
- }
-}
-
-
-#define __ ACCESS_MASM(masm())
-
-Handle<Object> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
- ElementsKind elements_kind = receiver_map->elements_kind();
- bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
- Handle<Code> stub;
- if (receiver_map->has_sloppy_arguments_elements()) {
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
- stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
- } else if (receiver_map->has_fast_elements() ||
- receiver_map->has_fixed_typed_array_elements()) {
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
- stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
- store_mode).GetCode();
- } else {
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
- stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
- }
- Handle<Object> validity_cell =
- Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
- if (validity_cell.is_null()) {
- return stub;
- }
- return isolate()->factory()->NewTuple2(validity_cell, stub);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
diff --git a/deps/v8/src/ic/ic-compiler.h b/deps/v8/src/ic/ic-compiler.h
deleted file mode 100644
index b8d6635ae0..0000000000
--- a/deps/v8/src/ic/ic-compiler.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_IC_IC_COMPILER_H_
-#define V8_IC_IC_COMPILER_H_
-
-#include "src/ic/access-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-
-class PropertyICCompiler : public PropertyAccessCompiler {
- public:
- // Keyed
- static Handle<Object> ComputeKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
- static void ComputeKeyedStorePolymorphicHandlers(
- MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode);
-
- private:
- explicit PropertyICCompiler(Isolate* isolate)
- : PropertyAccessCompiler(isolate, Code::KEYED_STORE_IC,
- kCacheOnReceiver) {}
-
- Handle<Object> CompileKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
- void CompileKeyedStorePolymorphicHandlers(MapHandleList* receiver_maps,
- MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers,
- KeyedAccessStoreMode store_mode);
-};
-
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_IC_IC_COMPILER_H_
diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h
index b286315c01..aacb69091e 100644
--- a/deps/v8/src/ic/ic-inl.h
+++ b/deps/v8/src/ic/ic-inl.h
@@ -7,6 +7,7 @@
#include "src/ic/ic.h"
+#include "src/assembler-inl.h"
#include "src/debug/debug.h"
#include "src/macro-assembler.h"
#include "src/prototype.h"
@@ -45,7 +46,10 @@ Code* IC::GetTargetAtAddress(Address address, Address constant_pool) {
// Convert target address to the code object. Code::GetCodeFromTargetAddress
// is safe for use during GC where the map might be marked.
Code* result = Code::GetCodeFromTargetAddress(target);
- DCHECK(result->is_inline_cache_stub());
+ // The result can be an IC dispatcher (for vector-based ICs), an IC handler
+ // (for old-style patching ICs) or CEntryStub (for IC dispatchers inlined to
+ // bytecode handlers).
+ DCHECK(result->is_inline_cache_stub() || result->is_stub());
return result;
}
@@ -54,25 +58,13 @@ void IC::SetTargetAtAddress(Address address, Code* target,
Address constant_pool) {
if (AddressIsDeoptimizedCode(target->GetIsolate(), address)) return;
- DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub());
-
- DCHECK(!target->is_inline_cache_stub() ||
- (target->kind() != Code::LOAD_IC &&
- target->kind() != Code::KEYED_LOAD_IC &&
- target->kind() != Code::CALL_IC && target->kind() != Code::STORE_IC &&
- target->kind() != Code::KEYED_STORE_IC));
+ // Only these three old-style ICs still do code patching.
+ DCHECK(target->is_binary_op_stub() || target->is_compare_ic_stub() ||
+ target->is_to_boolean_ic_stub());
Heap* heap = target->GetHeap();
Code* old_target = GetTargetAtAddress(address, constant_pool);
-#ifdef DEBUG
- // STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark
- // ICs as language mode. The language mode of the IC must be preserved.
- if (old_target->kind() == Code::STORE_IC ||
- old_target->kind() == Code::KEYED_STORE_IC) {
- DCHECK(StoreICState::GetLanguageMode(old_target->extra_ic_state()) ==
- StoreICState::GetLanguageMode(target->extra_ic_state()));
- }
-#endif
+
Assembler::set_target_address_at(heap->isolate(), address, constant_pool,
target->instruction_start());
if (heap->gc_state() == Heap::MARK_COMPACT) {
@@ -132,14 +124,6 @@ Handle<Map> IC::GetICCacheHolder(Handle<Map> map, Isolate* isolate,
}
-Code* IC::get_host() {
- return isolate()
- ->inner_pointer_to_code_cache()
- ->GetCacheEntry(address())
- ->code;
-}
-
-
bool IC::AddressIsDeoptimizedCode() const {
return AddressIsDeoptimizedCode(isolate(), address());
}
diff --git a/deps/v8/src/ic/ic-state.cc b/deps/v8/src/ic/ic-state.cc
index 7439ecd2c0..a217b115fd 100644
--- a/deps/v8/src/ic/ic-state.cc
+++ b/deps/v8/src/ic/ic-state.cc
@@ -4,7 +4,10 @@
#include "src/ic/ic-state.h"
+#include "src/ast/ast-types.h"
+#include "src/feedback-vector.h"
#include "src/ic/ic.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
@@ -16,11 +19,6 @@ void ICUtility::Clear(Isolate* isolate, Address address,
}
-std::ostream& operator<<(std::ostream& os, const CallICState& s) {
- return os << "(" << s.convert_mode() << ", " << s.tail_call_mode() << ")";
-}
-
-
// static
STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::FIRST_TOKEN;
diff --git a/deps/v8/src/ic/ic-state.h b/deps/v8/src/ic/ic-state.h
index 836979c4f0..16651c5623 100644
--- a/deps/v8/src/ic/ic-state.h
+++ b/deps/v8/src/ic/ic-state.h
@@ -11,6 +11,7 @@
namespace v8 {
namespace internal {
+class AstType;
const int kMaxKeyedPolymorphism = 4;
@@ -22,38 +23,6 @@ class ICUtility : public AllStatic {
};
-class CallICState final BASE_EMBEDDED {
- public:
- explicit CallICState(ExtraICState extra_ic_state)
- : bit_field_(extra_ic_state) {}
- CallICState(ConvertReceiverMode convert_mode, TailCallMode tail_call_mode)
- : bit_field_(ConvertModeBits::encode(convert_mode) |
- TailCallModeBits::encode(tail_call_mode)) {}
-
- ExtraICState GetExtraICState() const { return bit_field_; }
-
- static void GenerateAheadOfTime(Isolate*,
- void (*Generate)(Isolate*,
- const CallICState&));
-
- ConvertReceiverMode convert_mode() const {
- return ConvertModeBits::decode(bit_field_);
- }
- TailCallMode tail_call_mode() const {
- return TailCallModeBits::decode(bit_field_);
- }
-
- private:
- typedef BitField<ConvertReceiverMode, 0, 2> ConvertModeBits;
- typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits;
-
- int const bit_field_;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const CallICState& s);
-
-
class BinaryOpICState final BASE_EMBEDDED {
public:
BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
@@ -213,67 +182,6 @@ class CompareICState {
Handle<Object> y);
};
-class LoadGlobalICState final BASE_EMBEDDED {
- private:
- class TypeofModeBits : public BitField<TypeofMode, 0, 1> {};
- STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0);
- const ExtraICState state_;
-
- public:
- static const uint32_t kNextBitFieldOffset = TypeofModeBits::kNext;
-
- explicit LoadGlobalICState(ExtraICState extra_ic_state)
- : state_(extra_ic_state) {}
-
- explicit LoadGlobalICState(TypeofMode typeof_mode)
- : state_(TypeofModeBits::encode(typeof_mode)) {}
-
- ExtraICState GetExtraICState() const { return state_; }
-
- TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); }
-
- static TypeofMode GetTypeofMode(ExtraICState state) {
- return LoadGlobalICState(state).typeof_mode();
- }
-
- // For convenience, a statically declared encoding of typeof mode
- // IC state.
- static const ExtraICState kInsideTypeOfState = INSIDE_TYPEOF
- << TypeofModeBits::kShift;
- static const ExtraICState kNotInsideTypeOfState = NOT_INSIDE_TYPEOF
- << TypeofModeBits::kShift;
-};
-
-
-class StoreICState final BASE_EMBEDDED {
- public:
- explicit StoreICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
-
- explicit StoreICState(LanguageMode mode)
- : state_(LanguageModeState::encode(mode)) {}
-
- ExtraICState GetExtraICState() const { return state_; }
-
- LanguageMode language_mode() const {
- return LanguageModeState::decode(state_);
- }
-
- static LanguageMode GetLanguageMode(ExtraICState state) {
- return StoreICState(state).language_mode();
- }
-
- class LanguageModeState : public BitField<LanguageMode, 1, 1> {};
- STATIC_ASSERT(i::LANGUAGE_END == 2);
-
- // For convenience, a statically declared encoding of strict mode extra
- // IC state.
- static const ExtraICState kStrictModeState = STRICT
- << LanguageModeState::kShift;
-
- private:
- const ExtraICState state_;
-};
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index d328b3cb2c..f11f94a770 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -19,7 +19,6 @@
#include "src/ic/call-optimization.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/handler-configuration-inl.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/ic-inl.h"
#include "src/ic/ic-stats.h"
#include "src/ic/stub-cache.h"
@@ -66,30 +65,7 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
return "";
}
-
-#ifdef DEBUG
-
-#define TRACE_GENERIC_IC(isolate, type, reason) \
- do { \
- if (FLAG_trace_ic) { \
- PrintF("[%s patching generic stub in ", type); \
- JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
- PrintF(" (%s)]\n", reason); \
- } \
- } while (false)
-
-#else
-
-#define TRACE_GENERIC_IC(isolate, type, reason) \
- do { \
- if (FLAG_trace_ic) { \
- PrintF("[%s patching generic stub in ", type); \
- PrintF("(see below) (%s)]\n", reason); \
- } \
- } while (false)
-
-#endif // DEBUG
-
+#define TRACE_GENERIC_IC(reason) set_slow_stub_reason(reason);
void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_ic_stats) {
@@ -100,107 +76,110 @@ void IC::TraceIC(const char* type, Handle<Object> name) {
}
}
+Address IC::GetAbstractPC(int* line, int* column) const {
+ JavaScriptFrameIterator it(isolate());
-void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
- State new_state) {
- if (V8_LIKELY(!FLAG_ic_stats)) return;
+ JavaScriptFrame* frame = it.frame();
+ DCHECK(!frame->is_builtin());
+ int position = frame->position();
- if (FLAG_ic_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
- ICStats::instance()->Begin();
- ICInfo& ic_info = ICStats::instance()->Current();
- ic_info.type = is_keyed() ? "Keyed" : "";
- ic_info.type += type;
+ Object* maybe_script = frame->function()->shared()->script();
+ if (maybe_script->IsScript()) {
+ Handle<Script> script(Script::cast(maybe_script), isolate());
+ Script::PositionInfo info;
+ Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET);
+ *line = info.line + 1;
+ *column = info.column + 1;
} else {
- PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type);
+ *line = position;
+ *column = -1;
}
- // TODO(jkummerow): Add support for "apply". The logic is roughly:
- // marker = [fp_ + kMarkerOffset];
- // if marker is smi and marker.value == INTERNAL and
- // the frame's code == builtin(Builtins::kFunctionApply):
- // then print "apply from" and advance one frame
+ if (frame->is_interpreted()) {
+ InterpretedFrame* iframe = static_cast<InterpretedFrame*>(frame);
+ Address bytecode_start =
+ reinterpret_cast<Address>(iframe->GetBytecodeArray()) - kHeapObjectTag +
+ BytecodeArray::kHeaderSize;
+ return bytecode_start + iframe->GetBytecodeOffset();
+ }
- Object* maybe_function =
- Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
- if (maybe_function->IsJSFunction()) {
- JSFunction* function = JSFunction::cast(maybe_function);
- int code_offset = 0;
- if (function->IsInterpreted()) {
- code_offset = InterpretedFrame::GetBytecodeOffset(fp());
- } else {
- code_offset =
- static_cast<int>(pc() - function->code()->instruction_start());
- }
- if (FLAG_ic_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
- JavaScriptFrame::CollectFunctionAndOffsetForICStats(
- function, function->abstract_code(), code_offset);
- } else {
- JavaScriptFrame::PrintFunctionAndOffset(
- function, function->abstract_code(), code_offset, stdout, true);
- }
+ return frame->pc();
+}
+
+void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
+ State new_state) {
+ if (V8_LIKELY(!FLAG_ic_stats)) return;
+
+ Map* map = nullptr;
+ if (!receiver_map().is_null()) {
+ map = *receiver_map();
}
const char* modifier = "";
- if (kind() == Code::KEYED_STORE_IC) {
+ if (IsKeyedStoreIC()) {
KeyedAccessStoreMode mode =
casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
modifier = GetTransitionMarkModifier(mode);
}
- Map* map = nullptr;
- if (!receiver_map().is_null()) {
- map = *receiver_map();
+
+ if (!(FLAG_ic_stats &
+ v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
+ int line;
+ int column;
+ Address pc = GetAbstractPC(&line, &column);
+ LOG(isolate(), ICEvent(type, is_keyed(), pc, line, column, map, *name,
+ TransitionMarkFromState(old_state),
+ TransitionMarkFromState(new_state), modifier,
+ slow_stub_reason_));
+ return;
}
- if (FLAG_ic_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
- ICInfo& ic_info = ICStats::instance()->Current();
- // Reverse enough space for IC transition state, the longest length is 17.
- ic_info.state.reserve(17);
- ic_info.state = "(";
- ic_info.state += TransitionMarkFromState(old_state);
- ic_info.state += "->";
- ic_info.state += TransitionMarkFromState(new_state);
- ic_info.state += modifier;
- ic_info.state += ")";
- ic_info.map = reinterpret_cast<void*>(map);
+
+ ICStats::instance()->Begin();
+ ICInfo& ic_info = ICStats::instance()->Current();
+ ic_info.type = is_keyed() ? "Keyed" : "";
+ ic_info.type += type;
+
+ Object* maybe_function =
+ Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
+ DCHECK(maybe_function->IsJSFunction());
+ JSFunction* function = JSFunction::cast(maybe_function);
+ int code_offset = 0;
+ if (function->IsInterpreted()) {
+ code_offset = InterpretedFrame::GetBytecodeOffset(fp());
} else {
- PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state),
- TransitionMarkFromState(new_state), modifier,
- reinterpret_cast<void*>(map));
- }
+ code_offset =
+ static_cast<int>(pc() - function->code()->instruction_start());
+ }
+ JavaScriptFrame::CollectFunctionAndOffsetForICStats(
+ function, function->abstract_code(), code_offset);
+
+ // Reserve enough space for IC transition state, the longest length is 17.
+ ic_info.state.reserve(17);
+ ic_info.state = "(";
+ ic_info.state += TransitionMarkFromState(old_state);
+ ic_info.state += "->";
+ ic_info.state += TransitionMarkFromState(new_state);
+ ic_info.state += modifier;
+ ic_info.state += ")";
+ ic_info.map = reinterpret_cast<void*>(map);
if (map != nullptr) {
- if (FLAG_ic_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
- ICInfo& ic_info = ICStats::instance()->Current();
- ic_info.is_dictionary_map = map->is_dictionary_map();
- ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
- ic_info.instance_type = std::to_string(map->instance_type());
- } else {
- PrintF(" dict=%u own=%u type=", map->is_dictionary_map(),
- map->NumberOfOwnDescriptors());
- std::cout << map->instance_type();
- }
- }
- if (FLAG_ic_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
- // TODO(lpy) Add name as key field in ICStats.
- ICStats::instance()->End();
- } else {
- PrintF(") ");
- name->ShortPrint(stdout);
- PrintF("]\n");
+ ic_info.is_dictionary_map = map->is_dictionary_map();
+ ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
+ ic_info.instance_type = std::to_string(map->instance_type());
}
+ // TODO(lpy) Add name as key field in ICStats.
+ ICStats::instance()->End();
}
#define TRACE_IC(type, name) TraceIC(type, name)
-
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
: isolate_(isolate),
vector_set_(false),
+ kind_(FeedbackSlotKind::kInvalid),
target_maps_set_(false),
+ slow_stub_reason_(nullptr),
nexus_(nexus) {
// To improve the performance of the (much used) IC code, we unfold a few
// levels of the stack frame iteration code. This yields a ~35% speedup when
@@ -237,9 +216,9 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
// function's frame. Check if the there is an additional frame, and if there
// is skip this frame. However, the pc should not be updated. The call to
// ICs happen from bytecode handlers.
- Object* frame_type =
- Memory::Object_at(fp + TypedFrameConstants::kFrameTypeOffset);
- if (frame_type == Smi::FromInt(StackFrame::STUB)) {
+ intptr_t frame_marker =
+ Memory::intptr_at(fp + TypedFrameConstants::kFrameTypeOffset);
+ if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
fp = Memory::Address_at(fp + TypedFrameConstants::kCallerFPOffset);
}
fp_ = fp;
@@ -247,18 +226,36 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
constant_pool_address_ = constant_pool;
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
- Code* target = this->target();
- kind_ = target->kind();
- state_ = UseVector() ? nexus->StateFromFeedback() : StateFromCode(target);
+ if (nexus) {
+ kind_ = nexus->kind();
+ DCHECK(UseVector());
+ state_ = nexus->StateFromFeedback();
+ extra_ic_state_ = kNoExtraICState;
+ } else {
+ Code* target = this->target();
+ Code::Kind kind = target->kind();
+ if (kind == Code::BINARY_OP_IC) {
+ kind_ = FeedbackSlotKind::kBinaryOp;
+ } else if (kind == Code::COMPARE_IC) {
+ kind_ = FeedbackSlotKind::kCompareOp;
+ } else if (kind == Code::TO_BOOLEAN_IC) {
+ kind_ = FeedbackSlotKind::kToBoolean;
+ } else {
+ UNREACHABLE();
+ kind_ = FeedbackSlotKind::kInvalid;
+ }
+ DCHECK(!UseVector());
+ state_ = StateFromCode(target);
+ extra_ic_state_ = target->extra_ic_state();
+ }
old_state_ = state_;
- extra_ic_state_ = target->extra_ic_state();
}
// The ICs that don't pass slot and vector through the stack have to
// save/restore them in the dispatcher.
bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
- kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC) {
+ kind == Code::KEYED_LOAD_IC) {
return true;
}
if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
@@ -289,7 +286,7 @@ InlineCacheState IC::StateFromCode(Code* code) {
}
}
-SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
+JSFunction* IC::GetHostFunction() const {
// Compute the JavaScript frame for the frame pointer of this IC
// structure. We need this to be able to find the function
// corresponding to the frame.
@@ -298,16 +295,7 @@ SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
// Find the function on the stack and both the active code for the
// function and the original code.
- JSFunction* function = frame->function();
- return function->shared();
-}
-
-
-Code* IC::GetCode() const {
- HandleScope scope(isolate());
- Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
- Code* code = shared->code();
- return code;
+ return frame->function();
}
static void LookupForRead(LookupIterator* it) {
@@ -350,7 +338,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// This is a contextual access, always just update the handler and stay
// monomorphic.
- if (kind() == Code::LOAD_GLOBAL_IC) return true;
+ if (IsLoadGlobalIC()) return true;
// The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or
@@ -447,12 +435,14 @@ static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
}
// static
-void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
- if (host->kind() != Code::FUNCTION) return;
+void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
+ Code* host = host_function->shared()->code();
- TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
- info->change_own_type_change_checksum();
- host->set_profiler_ticks(0);
+ if (host->kind() == Code::FUNCTION) {
+ TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
+ info->change_own_type_change_checksum();
+ host->set_profiler_ticks(0);
+ }
isolate->runtime_profiler()->NotifyICChanged();
// TODO(2029): When an optimized function is patched, it would
// be nice to propagate the corresponding type information to its
@@ -462,6 +452,7 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
+ // TODO(ishell): DCHECK
if (ICUseVector(target->kind())) return;
DCHECK(old_target->is_inline_cache_stub());
@@ -507,58 +498,6 @@ void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
}
}
-
-void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
- if (IsCleared(nexus)) return;
- // Make sure to also clear the map used in inline fast cases. If we
- // do not clear these maps, cached code can keep objects alive
- // through the embedded maps.
- nexus->ConfigurePremonomorphic();
- OnTypeFeedbackChanged(isolate, host);
-}
-
-
-void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
- // Determine our state.
- Object* feedback = nexus->vector()->Get(nexus->slot());
- State state = nexus->StateFromFeedback();
-
- if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
- nexus->ConfigureUninitialized();
- // The change in state must be processed.
- OnTypeFeedbackChanged(isolate, host);
- }
-}
-
-
-void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
- if (IsCleared(nexus)) return;
- nexus->ConfigurePremonomorphic();
- OnTypeFeedbackChanged(isolate, host);
-}
-
-void LoadGlobalIC::Clear(Isolate* isolate, Code* host,
- LoadGlobalICNexus* nexus) {
- if (IsCleared(nexus)) return;
- nexus->ConfigureUninitialized();
- OnTypeFeedbackChanged(isolate, host);
-}
-
-void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
- if (IsCleared(nexus)) return;
- nexus->ConfigurePremonomorphic();
- OnTypeFeedbackChanged(isolate, host);
-}
-
-
-void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
- KeyedStoreICNexus* nexus) {
- if (IsCleared(nexus)) return;
- nexus->ConfigurePremonomorphic();
- OnTypeFeedbackChanged(isolate, host);
-}
-
-
void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
Address constant_pool) {
DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
@@ -583,13 +522,13 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
if (new_state == PREMONOMORPHIC) {
nexus()->ConfigurePremonomorphic();
} else if (new_state == MEGAMORPHIC) {
- if (kind() == Code::LOAD_IC || kind() == Code::STORE_IC) {
+ if (IsLoadIC() || IsStoreIC() || IsStoreOwnIC()) {
nexus()->ConfigureMegamorphic();
- } else if (kind() == Code::KEYED_LOAD_IC) {
+ } else if (IsKeyedLoadIC()) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
} else {
- DCHECK(kind() == Code::KEYED_STORE_IC);
+ DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
}
@@ -598,66 +537,117 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
}
vector_set_ = true;
- OnTypeFeedbackChanged(isolate(), get_host());
+ OnFeedbackChanged(isolate(), GetHostFunction());
}
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Handle<Object> handler) {
DCHECK(UseVector());
- if (kind() == Code::LOAD_IC) {
- LoadICNexus* nexus = casted_nexus<LoadICNexus>();
- nexus->ConfigureMonomorphic(map, handler);
- } else if (kind() == Code::LOAD_GLOBAL_IC) {
- LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
- nexus->ConfigureHandlerMode(handler);
- } else if (kind() == Code::KEYED_LOAD_IC) {
- KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
- nexus->ConfigureMonomorphic(name, map, handler);
- } else if (kind() == Code::STORE_IC) {
- StoreICNexus* nexus = casted_nexus<StoreICNexus>();
- nexus->ConfigureMonomorphic(map, handler);
- } else {
- DCHECK(kind() == Code::KEYED_STORE_IC);
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigureMonomorphic(name, map, handler);
+ switch (kind_) {
+ case FeedbackSlotKind::kLoadProperty: {
+ LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+ nexus->ConfigureMonomorphic(map, handler);
+ break;
+ }
+ case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
+ case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
+ nexus->ConfigureHandlerMode(handler);
+ break;
+ }
+ case FeedbackSlotKind::kLoadKeyed: {
+ KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+ nexus->ConfigureMonomorphic(name, map, handler);
+ break;
+ }
+ case FeedbackSlotKind::kStoreNamedSloppy:
+ case FeedbackSlotKind::kStoreNamedStrict:
+ case FeedbackSlotKind::kStoreOwnNamed: {
+ StoreICNexus* nexus = casted_nexus<StoreICNexus>();
+ nexus->ConfigureMonomorphic(map, handler);
+ break;
+ }
+ case FeedbackSlotKind::kStoreKeyedSloppy:
+ case FeedbackSlotKind::kStoreKeyedStrict: {
+ KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
+ nexus->ConfigureMonomorphic(name, map, handler);
+ break;
+ }
+ case FeedbackSlotKind::kCall:
+ case FeedbackSlotKind::kBinaryOp:
+ case FeedbackSlotKind::kCompareOp:
+ case FeedbackSlotKind::kToBoolean:
+ case FeedbackSlotKind::kCreateClosure:
+ case FeedbackSlotKind::kLiteral:
+ case FeedbackSlotKind::kGeneral:
+ case FeedbackSlotKind::kStoreDataPropertyInLiteral:
+ case FeedbackSlotKind::kInvalid:
+ case FeedbackSlotKind::kKindsNumber:
+ UNREACHABLE();
+ break;
}
vector_set_ = true;
- OnTypeFeedbackChanged(isolate(), get_host());
+ OnFeedbackChanged(isolate(), GetHostFunction());
}
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers) {
DCHECK(UseVector());
- if (kind() == Code::LOAD_IC) {
- LoadICNexus* nexus = casted_nexus<LoadICNexus>();
- nexus->ConfigurePolymorphic(maps, handlers);
- } else if (kind() == Code::KEYED_LOAD_IC) {
- KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
- nexus->ConfigurePolymorphic(name, maps, handlers);
- } else if (kind() == Code::STORE_IC) {
- StoreICNexus* nexus = casted_nexus<StoreICNexus>();
- nexus->ConfigurePolymorphic(maps, handlers);
- } else {
- DCHECK(kind() == Code::KEYED_STORE_IC);
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigurePolymorphic(name, maps, handlers);
+ switch (kind_) {
+ case FeedbackSlotKind::kLoadProperty: {
+ LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+ nexus->ConfigurePolymorphic(maps, handlers);
+ break;
+ }
+ case FeedbackSlotKind::kLoadKeyed: {
+ KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+ nexus->ConfigurePolymorphic(name, maps, handlers);
+ break;
+ }
+ case FeedbackSlotKind::kStoreNamedSloppy:
+ case FeedbackSlotKind::kStoreNamedStrict:
+ case FeedbackSlotKind::kStoreOwnNamed: {
+ StoreICNexus* nexus = casted_nexus<StoreICNexus>();
+ nexus->ConfigurePolymorphic(maps, handlers);
+ break;
+ }
+ case FeedbackSlotKind::kStoreKeyedSloppy:
+ case FeedbackSlotKind::kStoreKeyedStrict: {
+ KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
+ nexus->ConfigurePolymorphic(name, maps, handlers);
+ break;
+ }
+ case FeedbackSlotKind::kCall:
+ case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
+ case FeedbackSlotKind::kLoadGlobalInsideTypeof:
+ case FeedbackSlotKind::kBinaryOp:
+ case FeedbackSlotKind::kCompareOp:
+ case FeedbackSlotKind::kToBoolean:
+ case FeedbackSlotKind::kCreateClosure:
+ case FeedbackSlotKind::kLiteral:
+ case FeedbackSlotKind::kGeneral:
+ case FeedbackSlotKind::kStoreDataPropertyInLiteral:
+ case FeedbackSlotKind::kInvalid:
+ case FeedbackSlotKind::kKindsNumber:
+ UNREACHABLE();
+ break;
}
vector_set_ = true;
- OnTypeFeedbackChanged(isolate(), get_host());
+ OnFeedbackChanged(isolate(), GetHostFunction());
}
void IC::ConfigureVectorState(MapHandleList* maps,
MapHandleList* transitioned_maps,
List<Handle<Object>>* handlers) {
DCHECK(UseVector());
- DCHECK(kind() == Code::KEYED_STORE_IC);
+ DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
vector_set_ = true;
- OnTypeFeedbackChanged(isolate(), get_host());
+ OnFeedbackChanged(isolate(), GetHostFunction());
}
@@ -843,12 +833,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
DCHECK(IsHandler(*handler));
- // Currently only LoadIC and KeyedLoadIC support non-code handlers.
- DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC ||
- kind() == Code::LOAD_GLOBAL_IC ||
- kind() == Code::KEYED_LOAD_IC ||
- kind() == Code::STORE_IC ||
- kind() == Code::KEYED_STORE_IC);
+ // Currently only load and store ICs support non-code handlers.
+ DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore());
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
@@ -856,7 +842,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
break;
case RECOMPUTE_HANDLER:
case MONOMORPHIC:
- if (kind() == Code::LOAD_GLOBAL_IC) {
+ if (IsLoadGlobalIC()) {
UpdateMonomorphicIC(handler, name);
break;
}
@@ -1101,7 +1087,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
void LoadIC::UpdateCaches(LookupIterator* lookup) {
- if (state() == UNINITIALIZED && kind() != Code::LOAD_GLOBAL_IC) {
+ if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
@@ -1115,15 +1101,10 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsFound()) {
- if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
- code = LoadNonExistent(receiver_map(), lookup->name());
- } else {
- code = slow_stub();
- }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
+ code = LoadNonExistent(receiver_map(), lookup->name());
} else {
- if (kind() == Code::LOAD_GLOBAL_IC &&
- lookup->state() == LookupIterator::DATA &&
+ if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA &&
lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
// Now update the cell in the feedback vector.
@@ -1133,7 +1114,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
return;
} else if (lookup->state() == LookupIterator::ACCESSOR) {
if (!IsCompatibleReceiver(lookup, receiver_map())) {
- TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ TRACE_GENERIC_IC("incompatible receiver type");
code = slow_stub();
}
} else if (lookup->state() == LookupIterator::INTERCEPTOR) {
@@ -1144,7 +1125,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
LookupForRead(&it);
if (it.state() == LookupIterator::ACCESSOR &&
!IsCompatibleReceiver(&it, receiver_map())) {
- TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ TRACE_GENERIC_IC("incompatible receiver type");
code = slow_stub();
}
}
@@ -1156,20 +1137,12 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
}
StubCache* IC::stub_cache() {
- switch (kind()) {
- case Code::LOAD_IC:
- case Code::KEYED_LOAD_IC:
- return isolate()->load_stub_cache();
-
- case Code::STORE_IC:
- case Code::KEYED_STORE_IC:
- return isolate()->store_stub_cache();
-
- default:
- break;
+ if (IsAnyLoad()) {
+ return isolate()->load_stub_cache();
+ } else {
+ DCHECK(IsAnyStore());
+ return isolate()->store_stub_cache();
}
- UNREACHABLE();
- return nullptr;
}
void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
@@ -1179,8 +1152,7 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
if (!FLAG_runtime_call_stats) return;
- if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
- kind() == Code::KEYED_LOAD_IC) {
+ if (IsAnyLoad()) {
switch (lookup->state()) {
case LookupIterator::ACCESS_CHECK:
TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck);
@@ -1207,7 +1179,7 @@ void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition);
break;
}
- } else if (kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC) {
+ } else if (IsAnyStore()) {
switch (lookup->state()) {
case LookupIterator::ACCESS_CHECK:
TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck);
@@ -1254,19 +1226,18 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
CacheHolderFlag flag;
Handle<Map> stub_holder_map;
- if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
- kind() == Code::KEYED_LOAD_IC) {
+ if (IsAnyLoad()) {
stub_holder_map = IC::GetHandlerCacheHolder(
receiver_map(), receiver_is_holder, isolate(), &flag);
} else {
- DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
+ DCHECK(IsAnyStore());
// Store handlers cannot be cached on prototypes.
flag = kCacheOnReceiver;
stub_holder_map = receiver_map();
}
Handle<Object> handler = PropertyHandlerCompiler::Find(
- lookup->name(), stub_holder_map, kind(), flag);
+ lookup->name(), stub_holder_map, handler_kind(), flag);
// Use the cached value if it exists, and if it is different from the
// handler that just missed.
if (!handler.is_null()) {
@@ -1329,8 +1300,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
->has_non_instance_prototype()) {
Handle<Code> stub;
TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
- FunctionPrototypeStub function_prototype_stub(isolate());
- return function_prototype_stub.GetCode();
+ return isolate()->builtins()->LoadIC_FunctionPrototype();
}
Handle<Map> map = receiver_map();
@@ -1359,7 +1329,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
return slow_stub();
}
// When debugging we need to go the slow path to flood the accessor.
- if (GetSharedFunctionInfo()->HasDebugInfo()) {
+ if (GetHostFunction()->shared()->HasDebugInfo()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
@@ -1384,7 +1354,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
return smi_handler;
}
- if (kind() != Code::LOAD_GLOBAL_IC) {
+ if (!IsLoadGlobalIC()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
@@ -1398,7 +1368,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
case LookupIterator::DATA: {
DCHECK_EQ(kData, lookup->property_details().kind());
if (lookup->is_dictionary_holder()) {
- if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) {
+ if (!IsLoadIC() && !IsLoadGlobalIC()) { // IsKeyedLoadIC()?
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
@@ -1505,7 +1475,7 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
return ComputeHandler(lookup);
}
DCHECK(holder->HasFastProperties());
- DCHECK(!GetSharedFunctionInfo()->HasDebugInfo());
+ DCHECK(!GetHostFunction()->shared()->HasDebugInfo());
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
isolate());
CallOptimization call_optimization(getter);
@@ -1542,7 +1512,7 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::DATA: {
DCHECK(lookup->is_dictionary_holder());
- DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
+ DCHECK(IsLoadIC() || IsLoadGlobalIC());
DCHECK(holder->IsJSGlobalObject());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
@@ -1579,6 +1549,8 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
}
} else if (key->IsUndefined(isolate)) {
key = isolate->factory()->undefined_string();
+ } else if (key->IsString()) {
+ key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
}
return key;
}
@@ -1600,11 +1572,11 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
Handle<Map> map = target_receiver_maps.at(i);
if (map.is_null()) continue;
if (map->instance_type() == JS_VALUE_TYPE) {
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSValue");
+ TRACE_GENERIC_IC("JSValue");
return;
}
if (map->instance_type() == JS_PROXY_TYPE) {
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSProxy");
+ TRACE_GENERIC_IC("JSProxy");
return;
}
}
@@ -1632,14 +1604,14 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the generic stub.
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
+ TRACE_GENERIC_IC("same map added twice");
return;
}
// If the maximum number of receiver maps has been exceeded, use the generic
// version of the IC.
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
+ TRACE_GENERIC_IC("max polymorph exceeded");
return;
}
@@ -1686,7 +1658,6 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
if (!is_vector_set()) {
ConfigureVectorState(MEGAMORPHIC, key);
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
TRACE_IC("LoadIC", key);
}
@@ -1852,12 +1823,13 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
return;
}
- bool use_ic = LookupForWrite(lookup, value, store_mode);
- if (!use_ic) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
+ Handle<Object> handler;
+ if (LookupForWrite(lookup, value, store_mode)) {
+ handler = ComputeHandler(lookup, value);
+ } else {
+ TRACE_GENERIC_IC("LookupForWrite said 'false'");
+ handler = slow_stub();
}
- Handle<Object> handler = use_ic ? ComputeHandler(lookup, value)
- : Handle<Object>::cast(slow_stub());
PatchCache(lookup->name(), handler);
TRACE_IC("StoreIC", lookup->name());
@@ -1955,7 +1927,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
}
// Currently not handled by CompileStoreTransition.
if (!holder->HasFastProperties()) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
+ TRACE_GENERIC_IC("transition from slow");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -1975,7 +1947,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
case LookupIterator::ACCESSOR: {
if (!holder->HasFastProperties()) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
+ TRACE_GENERIC_IC("accessor on slow map");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -1983,20 +1955,19 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (accessors->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
if (v8::ToCData<Address>(info->setter()) == nullptr) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == nullptr");
+ TRACE_GENERIC_IC("setter == nullptr");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
!lookup->HolderIsReceiverOrHiddenPrototype()) {
- TRACE_GENERIC_IC(isolate(), "StoreIC",
- "special data property in prototype chain");
+ TRACE_GENERIC_IC("special data property in prototype chain");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
receiver_map())) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
+ TRACE_GENERIC_IC("incompatible receiver type");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -2009,7 +1980,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
isolate());
if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
+ TRACE_GENERIC_IC("setter not a function");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -2018,7 +1989,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
break; // Custom-compiled handler.
}
- TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver");
+ TRACE_GENERIC_IC("incompatible receiver");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -2045,12 +2016,13 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
int descriptor = lookup->GetFieldDescriptorIndex();
FieldIndex index = lookup->GetFieldIndex();
return StoreHandler::StoreField(isolate(), descriptor, index,
+ lookup->constness(),
lookup->representation());
}
// -------------- Constant properties --------------
DCHECK_EQ(kDescriptor, lookup->property_details().location());
- TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
+ TRACE_GENERIC_IC("constant property");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@@ -2106,6 +2078,11 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ // TODO(ishell): don't hard-code language mode into the handler because
+ // this handler can be re-used through megamorphic stub cache for wrong
+ // language mode.
+ // Better pass vector/slot to Runtime::kStoreCallbackProperty and
+ // let it decode the language mode from the IC kind.
Handle<Code> code = compiler.CompileStoreCallback(
receiver, lookup->name(), info, language_mode());
return code;
@@ -2167,16 +2144,14 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
Handle<Map> monomorphic_map =
ComputeTransitionedMap(receiver_map, store_mode);
store_mode = GetNonTransitioningStoreMode(store_mode);
- Handle<Object> handler =
- PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map,
- store_mode);
+ Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
}
for (int i = 0; i < target_receiver_maps.length(); i++) {
if (!target_receiver_maps.at(i).is_null() &&
target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "JSValue");
+ TRACE_GENERIC_IC("JSValue");
return;
}
}
@@ -2202,8 +2177,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// stay MONOMORPHIC and use the map for the most generic ElementsKind.
store_mode = GetNonTransitioningStoreMode(store_mode);
Handle<Object> handler =
- PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- transitioned_receiver_map, store_mode);
+ StoreElementHandler(transitioned_receiver_map, store_mode);
ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
return;
}
@@ -2215,9 +2189,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// A "normal" IC that handles stores can switch to a version that can
// grow at the end of the array, handle OOB accesses or copy COW arrays
// and still stay MONOMORPHIC.
- Handle<Object> handler =
- PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map,
- store_mode);
+ Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
}
@@ -2237,7 +2209,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
if (!map_added) {
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the megamorphic stub which can handle everything.
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
+ TRACE_GENERIC_IC("same map added twice");
return;
}
@@ -2252,7 +2224,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
if (store_mode == STANDARD_STORE) {
store_mode = old_store_mode;
} else if (store_mode != old_store_mode) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
+ TRACE_GENERIC_IC("store mode mismatch");
return;
}
}
@@ -2269,16 +2241,15 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
if (external_arrays != 0 &&
external_arrays != target_receiver_maps.length()) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
- "unsupported combination of external and normal arrays");
+ TRACE_GENERIC_IC("unsupported combination of external and normal arrays");
return;
}
}
MapHandleList transitioned_maps(target_receiver_maps.length());
List<Handle<Object>> handlers(target_receiver_maps.length());
- PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
- &target_receiver_maps, &transitioned_maps, &handlers, store_mode);
+ StoreElementPolymorphicHandlers(&target_receiver_maps, &transitioned_maps,
+ &handlers, store_mode);
ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
}
@@ -2312,6 +2283,91 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
return MaybeHandle<Map>().ToHandleChecked();
}
+Handle<Object> KeyedStoreIC::StoreElementHandler(
+ Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
+ DCHECK(store_mode == STANDARD_STORE ||
+ store_mode == STORE_AND_GROW_NO_TRANSITION ||
+ store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
+ store_mode == STORE_NO_TRANSITION_HANDLE_COW);
+
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ Handle<Code> stub;
+ if (receiver_map->has_sloppy_arguments_elements()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
+ stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
+ } else if (receiver_map->has_fast_elements() ||
+ receiver_map->has_fixed_typed_array_elements()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
+ stub =
+ StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode)
+ .GetCode();
+ } else {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
+ DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
+ stub = StoreSlowElementStub(isolate(), store_mode).GetCode();
+ }
+ Handle<Object> validity_cell =
+ Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
+ if (validity_cell.is_null()) {
+ return stub;
+ }
+ return isolate()->factory()->NewTuple2(validity_cell, stub);
+}
+
+void KeyedStoreIC::StoreElementPolymorphicHandlers(
+ MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
+ List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) {
+ DCHECK(store_mode == STANDARD_STORE ||
+ store_mode == STORE_AND_GROW_NO_TRANSITION ||
+ store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
+ store_mode == STORE_NO_TRANSITION_HANDLE_COW);
+
+ for (int i = 0; i < receiver_maps->length(); ++i) {
+ Handle<Map> receiver_map(receiver_maps->at(i));
+ Handle<Object> handler;
+ Handle<Map> transitioned_map;
+ {
+ Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
+ if (tmap != nullptr) transitioned_map = handle(tmap);
+ }
+
+ // TODO(mvstanton): The code below is doing pessimistic elements
+ // transitions. I would like to stop doing that and rely on Allocation Site
+ // Tracking to do a better job of ensuring the data types are what they need
+ // to be. Not all the elements are in place yet, pessimistic elements
+ // transitions are still important for performance.
+ if (!transitioned_map.is_null()) {
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ TRACE_HANDLER_STATS(isolate(),
+ KeyedStoreIC_ElementsTransitionAndStoreStub);
+ Handle<Code> stub =
+ ElementsTransitionAndStoreStub(isolate(), elements_kind,
+ transitioned_map->elements_kind(),
+ is_js_array, store_mode)
+ .GetCode();
+ Handle<Object> validity_cell =
+ Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
+ if (validity_cell.is_null()) {
+ handler = stub;
+ } else {
+ handler = isolate()->factory()->NewTuple2(validity_cell, stub);
+ }
+
+ } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
+ // TODO(mvstanton): Consider embedding store_mode in the state of the slow
+ // keyed store ic for uniformity.
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
+ handler = isolate()->builtins()->KeyedStoreIC_Slow();
+ } else {
+ handler = StoreElementHandler(receiver_map, store_mode);
+ }
+ DCHECK(!handler.is_null());
+ handlers->Add(handler);
+ transitioned_maps->Add(transitioned_map);
+ }
+}
bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
uint32_t length = 0;
@@ -2404,8 +2460,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
Object);
if (!is_vector_set()) {
ConfigureVectorState(MEGAMORPHIC, key);
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
- "unhandled internalized string key");
+ TRACE_GENERIC_IC("unhandled internalized string key");
TRACE_IC("StoreIC", key);
}
return store_handle;
@@ -2419,7 +2474,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
// the runtime to enable optimization of element hole access.
Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
if (heap_object->map()->IsMapInArrayPrototypeChain()) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
+ TRACE_GENERIC_IC("map in array prototype");
use_ic = false;
}
}
@@ -2450,7 +2505,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
if (use_ic) {
if (!old_receiver_map.is_null()) {
if (is_arguments) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
+ TRACE_GENERIC_IC("arguments receiver");
} else if (key_is_valid_index) {
// We should go generic if receiver isn't a dictionary, but our
// prototype chain does have dictionary elements. This ensures that
@@ -2459,20 +2514,18 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
UpdateStoreElement(old_receiver_map, store_mode);
} else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
- "dictionary or proxy prototype");
+ TRACE_GENERIC_IC("dictionary or proxy prototype");
}
} else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
+ TRACE_GENERIC_IC("non-smi-like key");
}
} else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
+ TRACE_GENERIC_IC("non-JSObject receiver");
}
}
if (!is_vector_set()) {
ConfigureVectorState(MEGAMORPHIC, key);
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
}
TRACE_IC("StoreIC", key);
@@ -2480,48 +2533,6 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
}
-void CallIC::HandleMiss(Handle<Object> function) {
- Handle<Object> name = isolate()->factory()->empty_string();
- CallICNexus* nexus = casted_nexus<CallICNexus>();
- Object* feedback = nexus->GetFeedback();
-
- // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
- DCHECK(!feedback->IsSmi());
-
- if (feedback->IsWeakCell() || !function->IsJSFunction() ||
- feedback->IsAllocationSite()) {
- // We are going generic.
- nexus->ConfigureMegamorphic();
- } else {
- DCHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate()));
- Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
-
- Handle<JSFunction> array_function =
- Handle<JSFunction>(isolate()->native_context()->array_function());
- if (array_function.is_identical_to(js_function)) {
- // Alter the slot.
- nexus->ConfigureMonomorphicArray();
- } else if (js_function->context()->native_context() !=
- *isolate()->native_context()) {
- // Don't collect cross-native context feedback for the CallIC.
- // TODO(bmeurer): We should collect the SharedFunctionInfo as
- // feedback in this case instead.
- nexus->ConfigureMegamorphic();
- } else {
- nexus->ConfigureMonomorphic(js_function);
- }
- }
-
- if (function->IsJSFunction()) {
- Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
- name = handle(js_function->shared()->name(), isolate());
- }
-
- OnTypeFeedbackChanged(isolate(), get_host());
- TRACE_IC("CallIC", name);
-}
-
-
#undef TRACE_IC
@@ -2530,22 +2541,6 @@ void CallIC::HandleMiss(Handle<Object> function) {
//
// Used from ic-<arch>.cc.
-RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
- HandleScope scope(isolate);
- DCHECK_EQ(3, args.length());
- // Runtime functions don't follow the IC's calling convention.
- Handle<Object> function = args.at(0);
- Handle<FeedbackVector> vector = args.at<FeedbackVector>(1);
- Handle<Smi> slot = args.at<Smi>(2);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
- CallICNexus nexus(vector, vector_slot);
- CallIC ic(isolate, &nexus);
- ic.HandleMiss(function);
- return *function;
-}
-
-
-// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
@@ -2554,28 +2549,28 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Handle<Name> key = args.at<Name>(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
// A monomorphic or polymorphic KeyedLoadIC with a string key can call the
// LoadIC miss handler if the handler misses. Since the vector Nexus is
// set up outside the IC, handle that here.
- FeedbackVectorSlotKind kind = vector->GetKind(vector_slot);
- if (kind == FeedbackVectorSlotKind::LOAD_IC) {
+ FeedbackSlotKind kind = vector->GetKind(vector_slot);
+ if (IsLoadICKind(kind)) {
LoadICNexus nexus(vector, vector_slot);
- LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ LoadIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
- } else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
+ } else if (IsLoadGlobalICKind(kind)) {
DCHECK_EQ(*isolate->global_object(), *receiver);
LoadGlobalICNexus nexus(vector, vector_slot);
- LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ LoadGlobalIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
} else {
- DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind);
+ DCHECK(IsKeyedLoadICKind(kind));
KeyedLoadICNexus nexus(vector, vector_slot);
- KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ KeyedLoadIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
@@ -2590,10 +2585,10 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
Handle<String> name = args.at<String>(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
LoadGlobalICNexus nexus(vector, vector_slot);
- LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ LoadGlobalIC ic(isolate, &nexus);
ic.UpdateState(global, name);
Handle<Object> result;
@@ -2603,7 +2598,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
HandleScope scope(isolate);
- DCHECK_EQ(1, args.length());
+ DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
Handle<Context> native_context = isolate->native_context();
@@ -2630,11 +2625,13 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
isolate, result,
Runtime::GetObjectProperty(isolate, global, name, &is_found));
if (!is_found) {
- LoadICNexus nexus(isolate);
- LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ Handle<Smi> slot = args.at<Smi>(1);
+ Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlotKind kind = vector->GetKind(vector_slot);
// It is actually a LoadGlobalICs here but the predicate handles this case
// properly.
- if (ic.ShouldThrowReferenceError()) {
+ if (LoadIC::ShouldThrowReferenceError(kind)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
}
@@ -2651,31 +2648,13 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
Handle<Object> key = args.at(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
- KeyedLoadICNexus nexus(vector, vector_slot);
- KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- ic.UpdateState(receiver, key);
- RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
-}
-
-
-RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
- HandleScope scope(isolate);
- typedef LoadWithVectorDescriptor Descriptor;
- DCHECK_EQ(Descriptor::kParameterCount, args.length());
- Handle<Object> receiver = args.at(Descriptor::kReceiver);
- Handle<Object> key = args.at(Descriptor::kName);
- Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
- Handle<FeedbackVector> vector =
- args.at<FeedbackVector>(Descriptor::kVector);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
KeyedLoadICNexus nexus(vector, vector_slot);
- KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+ KeyedLoadIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
-
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
HandleScope scope(isolate);
@@ -2686,23 +2665,22 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> receiver = args.at(3);
Handle<Name> key = args.at<Name>(4);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
- if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlotKind kind = vector->GetKind(vector_slot);
+ if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
StoreICNexus nexus(vector, vector_slot);
- StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ StoreIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
- DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
- vector->GetKind(vector_slot));
+ DCHECK(IsKeyedStoreICKind(kind));
KeyedStoreICNexus nexus(vector, vector_slot);
- KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ KeyedStoreIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
}
-
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
HandleScope scope(isolate);
@@ -2713,9 +2691,9 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
KeyedStoreICNexus nexus(vector, vector_slot);
- KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ KeyedStoreIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
@@ -2726,13 +2704,12 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
- // slot and vector parameters are not used.
+ Handle<Smi> slot = args.at<Smi>(1);
+ Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> object = args.at(3);
Handle<Object> key = args.at(4);
- LanguageMode language_mode;
- KeyedStoreICNexus nexus(isolate);
- KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- language_mode = ic.language_mode();
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
@@ -2741,15 +2718,16 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
HandleScope scope(isolate);
+ DCHECK_EQ(6, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> object = args.at(0);
Handle<Object> key = args.at(1);
Handle<Object> value = args.at(2);
Handle<Map> map = args.at<Map>(3);
- LanguageMode language_mode;
- KeyedStoreICNexus nexus(isolate);
- KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- language_mode = ic.language_mode();
+ Handle<Smi> slot = args.at<Smi>(4);
+ Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
if (object->IsJSObject()) {
JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
map->elements_kind());
@@ -2867,15 +2845,13 @@ MaybeHandle<Object> BinaryOpIC::Transition(
JavaScriptFrame::CollectTopFrameForICStats(isolate());
ic_stats->End();
} else if (FLAG_ic_stats) {
- // if (FLAG_trace_ic) {
- OFStream os(stdout);
- os << "[BinaryOpIC" << old_state << " => " << state << " @ "
- << static_cast<void*>(*new_target) << " <- ";
- JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
- if (!allocation_site.is_null()) {
- os << " using allocation site " << static_cast<void*>(*allocation_site);
- }
- os << "]" << std::endl;
+ int line;
+ int column;
+ Address pc = GetAbstractPC(&line, &column);
+ LOG(isolate(),
+ BinaryOpIC(pc, line, column, *new_target, old_state.ToString().c_str(),
+ state.ToString().c_str(),
+ allocation_site.is_null() ? nullptr : *allocation_site));
}
// Patch the inlined smi code as necessary.
@@ -2964,17 +2940,17 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
ic_info.state += Token::Name(op_);
ic_stats->End();
} else if (FLAG_ic_stats) {
- // if (FLAG_trace_ic) {
- PrintF("[CompareIC in ");
- JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
- PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
- CompareICState::GetStateName(old_stub.left()),
- CompareICState::GetStateName(old_stub.right()),
- CompareICState::GetStateName(old_stub.state()),
- CompareICState::GetStateName(new_left),
- CompareICState::GetStateName(new_right),
- CompareICState::GetStateName(state), Token::Name(op_),
- static_cast<void*>(*stub.GetCode()));
+ int line;
+ int column;
+ Address pc = GetAbstractPC(&line, &column);
+ LOG(isolate(),
+ CompareIC(pc, line, column, *stub.GetCode(), Token::Name(op_),
+ CompareICState::GetStateName(old_stub.left()),
+ CompareICState::GetStateName(old_stub.right()),
+ CompareICState::GetStateName(old_stub.state()),
+ CompareICState::GetStateName(new_left),
+ CompareICState::GetStateName(new_right),
+ CompareICState::GetStateName(state)));
}
// Activate inlined smi code.
@@ -3004,9 +2980,36 @@ RUNTIME_FUNCTION(Runtime_Unreachable) {
Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
ToBooleanICStub stub(isolate(), extra_ic_state());
+ ToBooleanHints old_hints = stub.hints();
bool to_boolean_value = stub.UpdateStatus(object);
+ ToBooleanHints new_hints = stub.hints();
Handle<Code> code = stub.GetCode();
set_target(*code);
+
+ // Note: Although a no-op transition is semantically OK, it is hinting at a
+ // bug somewhere in our state transition machinery.
+ DCHECK_NE(old_hints, new_hints);
+ if (V8_UNLIKELY(FLAG_ic_stats)) {
+ if (FLAG_ic_stats &
+ v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
+ auto ic_stats = ICStats::instance();
+ ic_stats->Begin();
+ ICInfo& ic_info = ic_stats->Current();
+ ic_info.type = "ToBooleanIC";
+ ic_info.state = ToString(old_hints);
+ ic_info.state += "=>";
+ ic_info.state += ToString(new_hints);
+ ic_stats->End();
+ } else {
+ int line;
+ int column;
+ Address pc = GetAbstractPC(&line, &column);
+ LOG(isolate(),
+ ToBooleanIC(pc, line, column, *code, ToString(old_hints).c_str(),
+ ToString(new_hints).c_str()));
+ }
+ }
+
return isolate()->factory()->ToBoolean(to_boolean_value);
}
@@ -3101,7 +3104,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
*/
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
HandleScope scope(isolate);
- DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
+ DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2);
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
@@ -3140,11 +3143,13 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
if (it.IsFound()) return *result;
- LoadICNexus nexus(isolate);
- LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- // It could actually be any kind of LoadICs here but the predicate handles
- // all the cases properly.
- if (!ic.ShouldThrowReferenceError()) {
+ Handle<Smi> slot = args.at<Smi>(3);
+ Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
+ // It could actually be any kind of load IC slot here but the predicate
+ // handles all the cases properly.
+ if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
return isolate->heap()->undefined_value();
}
@@ -3156,12 +3161,15 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
HandleScope scope(isolate);
- DCHECK(args.length() == 3);
- StoreICNexus nexus(isolate);
- StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- Handle<JSObject> receiver = args.at<JSObject>(0);
- Handle<Name> name = args.at<Name>(1);
- Handle<Object> value = args.at(2);
+ DCHECK_EQ(5, args.length());
+ // 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<JSObject> receiver = args.at<JSObject>(3);
+ Handle<Name> name = args.at<Name>(4);
+ FeedbackSlot vector_slot = vector->ToSlot(slot->value());
+ LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
DCHECK(receiver->HasNamedInterceptor());
InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
@@ -3186,7 +3194,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
it.Next();
- MAYBE_RETURN(Object::SetProperty(&it, value, ic.language_mode(),
+ MAYBE_RETURN(Object::SetProperty(&it, value, language_mode,
JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
isolate->heap()->exception());
return *value;
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index 74a034d0e7..c9818f5a5b 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -5,6 +5,8 @@
#ifndef V8_IC_H_
#define V8_IC_H_
+#include "src/factory.h"
+#include "src/feedback-vector.h"
#include "src/ic/ic-state.h"
#include "src/macro-assembler.h"
#include "src/messages.h"
@@ -45,16 +47,12 @@ class IC {
// Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address, Address constant_pool);
-#ifdef DEBUG
- bool IsLoadStub() const {
- return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC ||
- kind_ == Code::KEYED_LOAD_IC;
+ bool IsAnyLoad() const {
+ return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
}
- bool IsStoreStub() const {
- return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC;
+ bool IsAnyStore() const {
+ return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC();
}
- bool IsCallStub() const { return kind_ == Code::CALL_IC; }
-#endif
static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
bool receiver_is_holder,
@@ -64,15 +62,15 @@ class IC {
Isolate* isolate,
CacheHolderFlag* flag);
- static bool IsCleared(FeedbackNexus* nexus) {
- InlineCacheState state = nexus->StateFromFeedback();
- return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
- }
-
static bool ICUseVector(Code::Kind kind) {
return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
- kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC ||
- kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC;
+ kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC ||
+ kind == Code::KEYED_STORE_IC;
+ }
+ static bool ICUseVector(FeedbackSlotKind kind) {
+ return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) ||
+ IsKeyedLoadICKind(kind) || IsStoreICKind(kind) ||
+ IsStoreOwnICKind(kind) || IsKeyedStoreICKind(kind);
}
// The ICs that don't pass slot and vector through the stack have to
@@ -83,15 +81,20 @@ class IC {
static inline bool IsHandler(Object* object);
+ // Nofity the IC system that a feedback has changed.
+ static void OnFeedbackChanged(Isolate* isolate, JSFunction* host_function);
+
protected:
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
+
+ void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
+
+ Address GetAbstractPC(int* line, int* column) const;
Isolate* isolate() const { return isolate_; }
- // Get the shared function info of the caller.
- SharedFunctionInfo* GetSharedFunctionInfo() const;
- // Get the code object of the caller.
- Code* GetCode() const;
+ // Get the caller function object.
+ JSFunction* GetHostFunction() const;
inline bool AddressIsDeoptimizedCode() const;
inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
@@ -136,8 +139,6 @@ class IC {
Address constant_pool);
static inline void SetTargetAtAddress(Address address, Code* target,
Address constant_pool);
- // As a vector-based IC, type feedback must be updated differently.
- static void OnTypeFeedbackChanged(Isolate* isolate, Code* host);
static void PostPatching(Address address, Code* target, Code* old_target);
void TraceHandlerCacheHitStats(LookupIterator* lookup);
@@ -165,15 +166,18 @@ class IC {
void CopyICToMegamorphicCache(Handle<Name> name);
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
void PatchCache(Handle<Name> name, Handle<Object> code);
- Code::Kind kind() const { return kind_; }
- bool is_keyed() const {
- return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC;
- }
+ FeedbackSlotKind kind() const { return kind_; }
+ bool IsLoadIC() const { return IsLoadICKind(kind_); }
+ bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
+ bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
+ bool IsStoreIC() const { return IsStoreICKind(kind_); }
+ bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
+ bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
+ bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); }
Code::Kind handler_kind() const {
- if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC;
- DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC ||
- kind_ == Code::KEYED_STORE_IC);
- return kind_;
+ if (IsAnyLoad()) return Code::LOAD_IC;
+ DCHECK(IsAnyStore());
+ return Code::STORE_IC;
}
bool ShouldRecomputeHandler(Handle<String> name);
@@ -201,7 +205,7 @@ class IC {
}
Handle<FeedbackVector> vector() const { return nexus()->vector_handle(); }
- FeedbackVectorSlot slot() const { return nexus()->slot(); }
+ FeedbackSlot slot() const { return nexus()->slot(); }
State saved_state() const {
return state() == RECOMPUTE_HANDLER ? old_state_ : state();
}
@@ -212,7 +216,6 @@ class IC {
}
FeedbackNexus* nexus() const { return nexus_; }
- inline Code* get_host();
inline Code* target() const;
private:
@@ -244,7 +247,7 @@ class IC {
bool vector_set_;
State old_state_; // For saving if we marked as prototype failure.
State state_;
- Code::Kind kind_;
+ FeedbackSlotKind kind_;
Handle<Map> receiver_map_;
MaybeHandle<Object> maybe_handler_;
@@ -252,6 +255,8 @@ class IC {
MapHandleList target_maps_;
bool target_maps_set_;
+ const char* slow_stub_reason_;
+
FeedbackNexus* nexus_;
DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
@@ -264,32 +269,28 @@ class CallIC : public IC {
: IC(EXTRA_CALL_FRAME, isolate, nexus) {
DCHECK(nexus != NULL);
}
-
- void HandleMiss(Handle<Object> function);
-
- static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
};
class LoadIC : public IC {
public:
- LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
- : IC(depth, isolate, nexus) {
+ LoadIC(Isolate* isolate, FeedbackNexus* nexus)
+ : IC(NO_EXTRA_FRAME, isolate, nexus) {
DCHECK(nexus != NULL);
- DCHECK(IsLoadStub());
+ DCHECK(IsAnyLoad());
+ }
+
+ static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
+ return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
}
bool ShouldThrowReferenceError() const {
- return kind() == Code::LOAD_GLOBAL_IC &&
- LoadGlobalICState::GetTypeofMode(extra_ic_state()) ==
- NOT_INSIDE_TYPEOF;
+ return ShouldThrowReferenceError(kind());
}
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name);
- static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
-
protected:
virtual Handle<Code> slow_stub() const {
return isolate()->builtins()->LoadIC_Slow();
@@ -324,13 +325,11 @@ class LoadIC : public IC {
class LoadGlobalIC : public LoadIC {
public:
- LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
- : LoadIC(depth, isolate, nexus) {}
+ LoadGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
+ : LoadIC(isolate, nexus) {}
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);
- static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus);
-
protected:
Handle<Code> slow_stub() const override {
return isolate()->builtins()->LoadGlobalIC_Slow();
@@ -339,17 +338,14 @@ class LoadGlobalIC : public LoadIC {
class KeyedLoadIC : public LoadIC {
public:
- KeyedLoadIC(FrameDepth depth, Isolate* isolate,
- KeyedLoadICNexus* nexus = NULL)
- : LoadIC(depth, isolate, nexus) {
+ KeyedLoadIC(Isolate* isolate, KeyedLoadICNexus* nexus)
+ : LoadIC(isolate, nexus) {
DCHECK(nexus != NULL);
}
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Object> key);
- static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
-
protected:
// receiver is HeapObject because it could be a String or a JSObject
void UpdateLoadElement(Handle<HeapObject> receiver);
@@ -361,13 +357,13 @@ class KeyedLoadIC : public LoadIC {
class StoreIC : public IC {
public:
- StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
- : IC(depth, isolate, nexus) {
- DCHECK(IsStoreStub());
+ StoreIC(Isolate* isolate, FeedbackNexus* nexus)
+ : IC(NO_EXTRA_FRAME, isolate, nexus) {
+ DCHECK(IsAnyStore());
}
LanguageMode language_mode() const {
- return StoreICState::GetLanguageMode(extra_ic_state());
+ return nexus()->vector()->GetLanguageMode(nexus()->slot());
}
MUST_USE_RESULT MaybeHandle<Object> Store(
@@ -378,20 +374,11 @@ class StoreIC : public IC {
bool LookupForWrite(LookupIterator* it, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode);
- static void Clear(Isolate* isolate, Code* host, StoreICNexus* nexus);
-
protected:
// Stub accessors.
Handle<Code> slow_stub() const {
- switch (language_mode()) {
- case SLOPPY:
- return isolate()->builtins()->StoreIC_SlowSloppy();
- case STRICT:
- return isolate()->builtins()->StoreIC_SlowStrict();
- default:
- UNREACHABLE();
- return Handle<Code>();
- }
+ // StoreIC and KeyedStoreIC share the same slow stub.
+ return isolate()->builtins()->KeyedStoreIC_Slow();
}
// Update the inline cache and the global stub cache based on the
@@ -423,22 +410,13 @@ class KeyedStoreIC : public StoreIC {
return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
}
- KeyedStoreIC(FrameDepth depth, Isolate* isolate,
- KeyedStoreICNexus* nexus = NULL)
- : StoreIC(depth, isolate, nexus) {}
+ KeyedStoreIC(Isolate* isolate, KeyedStoreICNexus* nexus)
+ : StoreIC(isolate, nexus) {}
MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
Handle<Object> name,
Handle<Object> value);
- // Code generators for stub routines. Only called once at startup.
- static void GenerateMiss(MacroAssembler* masm);
- static void GenerateSlow(MacroAssembler* masm);
- static void GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode);
-
- static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus);
-
protected:
void UpdateStoreElement(Handle<Map> receiver_map,
KeyedAccessStoreMode store_mode);
@@ -447,6 +425,14 @@ class KeyedStoreIC : public StoreIC {
Handle<Map> ComputeTransitionedMap(Handle<Map> map,
KeyedAccessStoreMode store_mode);
+ Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
+ KeyedAccessStoreMode store_mode);
+
+ void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps,
+ MapHandleList* transitioned_maps,
+ List<Handle<Object>>* handlers,
+ KeyedAccessStoreMode store_mode);
+
friend class IC;
};
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index 81ce3a6a1f..8962386c93 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -7,19 +7,20 @@
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/contexts.h"
-#include "src/ic/accessor-assembler-impl.h"
+#include "src/ic/accessor-assembler.h"
#include "src/interface-descriptors.h"
#include "src/isolate.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
using compiler::Node;
-class KeyedStoreGenericAssembler : public AccessorAssemblerImpl {
+class KeyedStoreGenericAssembler : public AccessorAssembler {
public:
explicit KeyedStoreGenericAssembler(compiler::CodeAssemblerState* state)
- : AccessorAssemblerImpl(state) {}
+ : AccessorAssembler(state) {}
void KeyedStoreGeneric(LanguageMode language_mode);
@@ -72,6 +73,13 @@ class KeyedStoreGenericAssembler : public AccessorAssemblerImpl {
Variable* var_accessor_pair,
Variable* var_accessor_holder,
Label* readonly, Label* bailout);
+
+ void CheckFieldType(Node* descriptors, Node* name_index, Node* representation,
+ Node* value, Label* bailout);
+ void OverwriteExistingFastProperty(Node* object, Node* object_map,
+ Node* properties, Node* descriptors,
+ Node* descriptor_name_index, Node* details,
+ Node* value, Label* slow);
};
void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state,
@@ -266,7 +274,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// can always be stored.
{
Label non_smi_value(this);
- GotoUnless(TaggedIsSmi(value), &non_smi_value);
+ GotoIfNot(TaggedIsSmi(value), &non_smi_value);
// If we're about to introduce holes, ensure holey elements.
if (update_length == kBumpLengthWithGap) {
TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context,
@@ -461,6 +469,8 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
// Out-of-capacity accesses (index >= capacity) jump here. Additionally,
// an ElementsKind transition might be necessary.
+ // The index can also be negative at this point! Jump to the runtime in that
+ // case to convert it to a named property.
Bind(&if_grow);
{
Comment("Grow backing store");
@@ -537,16 +547,12 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
{
Node* descriptors = var_meta_storage.value();
Node* name_index = var_entry.value();
- // TODO(jkummerow): Add helper functions for accessing value and
- // details by entry.
- const int kNameToDetailsOffset = (DescriptorArray::kDescriptorDetails -
- DescriptorArray::kDescriptorKey) *
- kPointerSize;
- Node* details = LoadAndUntagToWord32FixedArrayElement(
- descriptors, name_index, kNameToDetailsOffset);
+ Node* details =
+ LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index);
JumpIfDataProperty(details, &ok_to_write, readonly);
// Accessor case.
+ // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
Variable var_details(this, MachineRepresentation::kWord32);
LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
&var_details, var_accessor_pair);
@@ -558,19 +564,13 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
{
Node* dictionary = var_meta_storage.value();
Node* entry = var_entry.value();
- const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
- NameDictionary::kEntryKeyIndex) *
- kPointerSize;
- Node* details = LoadAndUntagToWord32FixedArrayElement(
- dictionary, entry, kNameToDetailsOffset);
+ Node* details =
+ LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry);
JumpIfDataProperty(details, &ok_to_write, readonly);
// Accessor case.
- const int kNameToValueOffset = (NameDictionary::kEntryValueIndex -
- NameDictionary::kEntryKeyIndex) *
- kPointerSize;
var_accessor_pair->Bind(
- LoadFixedArrayElement(dictionary, entry, kNameToValueOffset));
+ LoadValueByKeyIndex<NameDictionary>(dictionary, entry));
var_accessor_holder->Bind(holder);
Goto(accessor);
}
@@ -579,13 +579,8 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
{
Node* dictionary = var_meta_storage.value();
Node* entry = var_entry.value();
- const int kNameToValueOffset = (GlobalDictionary::kEntryValueIndex -
- GlobalDictionary::kEntryKeyIndex) *
- kPointerSize;
-
Node* property_cell =
- LoadFixedArrayElement(dictionary, entry, kNameToValueOffset);
-
+ LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry);
Node* value =
LoadObjectField(property_cell, PropertyCell::kValueOffset);
GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
@@ -613,6 +608,146 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
Bind(&ok_to_write);
}
+void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors,
+ Node* name_index,
+ Node* representation,
+ Node* value, Label* bailout) {
+ Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
+ // Ignore FLAG_track_fields etc. and always emit code for all checks,
+ // because this builtin is part of the snapshot and therefore should
+ // be flag independent.
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)),
+ &r_smi);
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)),
+ &r_double);
+ GotoIf(
+ Word32Equal(representation, Int32Constant(Representation::kHeapObject)),
+ &r_heapobject);
+ GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)),
+ bailout);
+ CSA_ASSERT(this, Word32Equal(representation,
+ Int32Constant(Representation::kTagged)));
+ Goto(&all_fine);
+
+ Bind(&r_smi);
+ { Branch(TaggedIsSmi(value), &all_fine, bailout); }
+
+ Bind(&r_double);
+ {
+ GotoIf(TaggedIsSmi(value), &all_fine);
+ Node* value_map = LoadMap(value);
+ // While supporting mutable HeapNumbers would be straightforward, such
+ // objects should not end up here anyway.
+ CSA_ASSERT(this,
+ WordNotEqual(value_map,
+ LoadRoot(Heap::kMutableHeapNumberMapRootIndex)));
+ Branch(IsHeapNumberMap(value_map), &all_fine, bailout);
+ }
+
+ Bind(&r_heapobject);
+ {
+ GotoIf(TaggedIsSmi(value), bailout);
+ Node* field_type =
+ LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index);
+ intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None());
+ intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any());
+ // FieldType::None can't hold any value.
+ GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout);
+ // FieldType::Any can hold any value.
+ GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine);
+ CSA_ASSERT(this, IsWeakCell(field_type));
+ // Cleared WeakCells count as FieldType::None, which can't hold any value.
+ field_type = LoadWeakCellValue(field_type, bailout);
+ // FieldType::Class(...) performs a map check.
+ CSA_ASSERT(this, IsMap(field_type));
+ Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout);
+ }
+
+ Bind(&all_fine);
+}
+
+void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
+ Node* object, Node* object_map, Node* properties, Node* descriptors,
+ Node* descriptor_name_index, Node* details, Node* value, Label* slow) {
+ // Properties in descriptors can't be overwritten without map transition.
+ GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details),
+ Int32Constant(kField)),
+ slow);
+
+ if (FLAG_track_constant_fields) {
+ // TODO(ishell): Taking the slow path is not necessary if new and old
+ // values are identical.
+ GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details),
+ Int32Constant(kConst)),
+ slow);
+ }
+
+ Label done(this);
+ Node* representation =
+ DecodeWord32<PropertyDetails::RepresentationField>(details);
+
+ CheckFieldType(descriptors, descriptor_name_index, representation, value,
+ slow);
+ Node* field_index =
+ DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
+ Node* inobject_properties = LoadMapInobjectProperties(object_map);
+
+ Label inobject(this), backing_store(this);
+ Branch(UintPtrLessThan(field_index, inobject_properties), &inobject,
+ &backing_store);
+
+ Bind(&inobject);
+ {
+ Node* field_offset =
+ IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map),
+ IntPtrSub(inobject_properties, field_index)),
+ IntPtrConstant(kPointerSize));
+ Label tagged_rep(this), double_rep(this);
+ Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)),
+ &double_rep, &tagged_rep);
+ Bind(&double_rep);
+ {
+ Node* double_value = ChangeNumberToFloat64(value);
+ if (FLAG_unbox_double_fields) {
+ StoreObjectFieldNoWriteBarrier(object, field_offset, double_value,
+ MachineRepresentation::kFloat64);
+ } else {
+ Node* mutable_heap_number = LoadObjectField(object, field_offset);
+ StoreHeapNumberValue(mutable_heap_number, double_value);
+ }
+ Goto(&done);
+ }
+
+ Bind(&tagged_rep);
+ {
+ StoreObjectField(object, field_offset, value);
+ Goto(&done);
+ }
+ }
+
+ Bind(&backing_store);
+ {
+ Node* backing_store_index = IntPtrSub(field_index, inobject_properties);
+ Label tagged_rep(this), double_rep(this);
+ Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)),
+ &double_rep, &tagged_rep);
+ Bind(&double_rep);
+ {
+ Node* double_value = ChangeNumberToFloat64(value);
+ Node* mutable_heap_number =
+ LoadFixedArrayElement(properties, backing_store_index);
+ StoreHeapNumberValue(mutable_heap_number, double_value);
+ Goto(&done);
+ }
+ Bind(&tagged_rep);
+ {
+ StoreFixedArrayElement(properties, backing_store_index, value);
+ Goto(&done);
+ }
+ }
+ Bind(&done);
+}
+
void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow,
LanguageMode language_mode) {
@@ -627,10 +762,40 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Bind(&fast_properties);
{
- // TODO(jkummerow): Does it make sense to support some cases here inline?
- // Maybe overwrite existing writable properties?
- // Maybe support map transitions?
- Goto(&stub_cache);
+ Comment("fast property store");
+ Node* bitfield3 = LoadMapBitField3(receiver_map);
+ Node* descriptors = LoadMapDescriptors(receiver_map);
+ Label descriptor_found(this);
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ // TODO(jkummerow): Maybe look for existing map transitions?
+ Label* notfound = &stub_cache;
+ DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found,
+ &var_name_index, notfound);
+
+ Bind(&descriptor_found);
+ {
+ Node* name_index = var_name_index.value();
+ Node* details =
+ LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index);
+ Label data_property(this);
+ JumpIfDataProperty(details, &data_property, &readonly);
+
+ // Accessor case.
+ // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
+ Variable var_details(this, MachineRepresentation::kWord32);
+ LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
+ name_index, &var_details, &var_accessor_pair);
+ var_accessor_holder.Bind(receiver);
+ Goto(&accessor);
+
+ Bind(&data_property);
+ {
+ OverwriteExistingFastProperty(receiver, receiver_map, properties,
+ descriptors, name_index, details,
+ p->value, slow);
+ Return(p->value);
+ }
+ }
}
Bind(&dictionary_properties);
@@ -646,26 +811,20 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Bind(&dictionary_found);
{
Label overwrite(this);
- const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
- NameDictionary::kEntryKeyIndex) *
- kPointerSize;
- Node* details = LoadAndUntagToWord32FixedArrayElement(
- properties, var_name_index.value(), kNameToDetailsOffset);
+ Node* details = LoadDetailsByKeyIndex<NameDictionary>(
+ properties, var_name_index.value());
JumpIfDataProperty(details, &overwrite, &readonly);
// Accessor case.
- const int kNameToValueOffset =
- (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) *
- kPointerSize;
- var_accessor_pair.Bind(LoadFixedArrayElement(
- properties, var_name_index.value(), kNameToValueOffset));
+ var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>(
+ properties, var_name_index.value()));
var_accessor_holder.Bind(receiver);
Goto(&accessor);
Bind(&overwrite);
{
- StoreFixedArrayElement(properties, var_name_index.value(), p->value,
- UPDATE_WRITE_BARRIER, kNameToValueOffset);
+ StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
+ p->value);
Return(p->value);
}
}
@@ -690,7 +849,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Node* setter_map = LoadMap(setter);
// FunctionTemplateInfo setters are not supported yet.
GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
- GotoUnless(IsCallableMap(setter_map), &not_callable);
+ GotoIfNot(IsCallableMap(setter_map), &not_callable);
Callable callable = CodeFactory::Call(isolate());
CallJS(callable, p->context, setter, receiver, p->value);
@@ -734,7 +893,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Bind(&found_handler);
{
Comment("KeyedStoreGeneric found handler");
- HandleStoreICHandlerCase(p, var_handler.value(), slow);
+ HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss);
}
Bind(&stub_cache_miss);
{
@@ -756,6 +915,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
Node* context = Parameter(Descriptor::kContext);
Variable var_index(this, MachineType::PointerRepresentation());
+ Variable var_unique(this, MachineRepresentation::kTagged);
+ var_unique.Bind(name); // Dummy initialization.
Label if_index(this), if_unique_name(this), slow(this);
GotoIf(TaggedIsSmi(receiver), &slow);
@@ -767,7 +928,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
&slow);
- TryToName(name, &if_index, &var_index, &if_unique_name, &slow);
+ TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, &slow);
Bind(&if_index);
{
@@ -779,8 +940,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
Bind(&if_unique_name);
{
Comment("key is unique name");
- KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name,
- value, slot, vector);
+ StoreICParameters p(context, receiver, var_unique.value(), value, slot,
+ vector);
EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode);
}
diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc
index 43588b707a..c14652cf47 100644
--- a/deps/v8/src/ic/mips/handler-compiler-mips.cc
+++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc
@@ -173,15 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, scratch1);
-}
-
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -199,24 +190,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -512,8 +497,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/mips/ic-mips.cc b/deps/v8/src/ic/mips/ic-mips.cc
index e31aab1d76..fd39972f0e 100644
--- a/deps/v8/src/ic/mips/ic-mips.cc
+++ b/deps/v8/src/ic/mips/ic-mips.cc
@@ -6,45 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -102,9 +69,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(andi_instruction_address), delta);
+ LOG(isolate, PatchIC(address, andi_instruction_address, delta));
}
Address patch_address =
diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
index 06af88d19e..1a38d329e7 100644
--- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
+++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
@@ -173,15 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, scratch1);
-}
-
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -199,24 +190,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -512,8 +497,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/mips64/ic-mips64.cc b/deps/v8/src/ic/mips64/ic-mips64.cc
index fa351ba5a3..0e2032a41d 100644
--- a/deps/v8/src/ic/mips64/ic-mips64.cc
+++ b/deps/v8/src/ic/mips64/ic-mips64.cc
@@ -6,45 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -102,9 +69,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(andi_instruction_address), delta);
+ LOG(isolate, PatchIC(address, andi_instruction_address, delta));
}
Address patch_address =
diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
index d4edcc1ec9..3da558d10e 100644
--- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
+++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
@@ -176,15 +176,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- __ mr(r3, scratch1);
- __ Ret();
-}
-
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -204,25 +195,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(name);
- __ push(receiver);
- __ push(holder);
-}
-
-
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name, receiver, holder);
+
__ CallRuntime(id);
}
@@ -530,8 +514,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/ppc/ic-ppc.cc b/deps/v8/src/ic/ppc/ic-ppc.cc
index 3c325d8f92..0f25846870 100644
--- a/deps/v8/src/ic/ppc/ic-ppc.cc
+++ b/deps/v8/src/ic/ppc/ic-ppc.cc
@@ -6,45 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -103,9 +70,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(cmp_instruction_address), delta);
+ LOG(isolate, PatchIC(address, cmp_instruction_address, delta));
}
Address patch_address =
diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc
index 40a8c310d8..9f087977a1 100644
--- a/deps/v8/src/ic/s390/handler-compiler-s390.cc
+++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc
@@ -169,14 +169,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
- __ LoadRR(r2, scratch1);
- __ Ret();
-}
-
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -194,24 +186,18 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ bne(miss);
}
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name);
- __ Push(receiver);
- __ Push(holder);
-}
-
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name, receiver, holder);
+
__ CallRuntime(id);
}
@@ -508,8 +494,18 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(name(), receiver(), holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot(), vector());
+ } else {
+ __ Push(scratch3(), scratch2()); // slot, vector
+ }
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/s390/ic-s390.cc b/deps/v8/src/ic/s390/ic-s390.cc
index 6438cfca47..494a4cd1d7 100644
--- a/deps/v8/src/ic/s390/ic-s390.cc
+++ b/deps/v8/src/ic/s390/ic-s390.cc
@@ -6,41 +6,11 @@
#include "src/ic/ic.h"
#include "src/codegen.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
@@ -100,9 +70,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(cmp_instruction_address), delta);
+ LOG(isolate, PatchIC(address, cmp_instruction_address, delta));
}
// Expected sequence to enable by changing the following
diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc
index 84dbf48436..5fc8cc318d 100644
--- a/deps/v8/src/ic/stub-cache.cc
+++ b/deps/v8/src/ic/stub-cache.cc
@@ -6,6 +6,8 @@
#include "src/ast/ast.h"
#include "src/base/bits.h"
+#include "src/counters.h"
+#include "src/heap/heap.h"
#include "src/ic/ic-inl.h"
#include "src/type-info.h"
@@ -99,12 +101,12 @@ void StubCache::Clear() {
Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
for (int i = 0; i < kPrimaryTableSize; i++) {
primary_[i].key = isolate()->heap()->empty_string();
- primary_[i].map = NULL;
+ primary_[i].map = nullptr;
primary_[i].value = empty;
}
for (int j = 0; j < kSecondaryTableSize; j++) {
secondary_[j].key = isolate()->heap()->empty_string();
- secondary_[j].map = NULL;
+ secondary_[j].map = nullptr;
secondary_[j].value = empty;
}
}
@@ -116,9 +118,9 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
for (int i = 0; i < kPrimaryTableSize; i++) {
if (primary_[i].key == *name) {
Map* map = primary_[i].map;
- // Map can be NULL, if the stub is constant function call
+ // Map can be nullptr, if the stub is constant function call
// with a primitive receiver.
- if (map == NULL) continue;
+ if (map == nullptr) continue;
int offset = PrimaryOffset(*name, map);
if (entry(primary_, offset) == &primary_[i] &&
@@ -131,9 +133,9 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
for (int i = 0; i < kSecondaryTableSize; i++) {
if (secondary_[i].key == *name) {
Map* map = secondary_[i].map;
- // Map can be NULL, if the stub is constant function call
+ // Map can be nullptr, if the stub is constant function call
// with a primitive receiver.
- if (map == NULL) continue;
+ if (map == nullptr) continue;
// Lookup in primary table and skip duplicates.
int primary_offset = PrimaryOffset(*name, map);
diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h
index e8df26d37b..4054b329d3 100644
--- a/deps/v8/src/ic/stub-cache.h
+++ b/deps/v8/src/ic/stub-cache.h
@@ -74,7 +74,7 @@ class StubCache {
return StubCache::secondary_;
}
UNREACHABLE();
- return NULL;
+ return nullptr;
}
Isolate* isolate() { return isolate_; }
@@ -92,7 +92,7 @@ class StubCache {
// Some magic number used in primary and secondary hash computations.
static const int kPrimaryMagic = 0x3d532433;
- static const int kSecondaryMagic = 0xb16b00b5;
+ static const int kSecondaryMagic = 0xb16ca6e5;
static int PrimaryOffsetForTesting(Name* name, Map* map) {
return PrimaryOffset(name, map);
diff --git a/deps/v8/src/ic/x64/access-compiler-x64.cc b/deps/v8/src/ic/x64/access-compiler-x64.cc
index 9e95b9506c..4bbbba5b5a 100644
--- a/deps/v8/src/ic/x64/access-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/access-compiler-x64.cc
@@ -5,6 +5,7 @@
#if V8_TARGET_ARCH_X64
#include "src/ic/access-compiler.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc
index a89afa8a7e..425ed4762e 100644
--- a/deps/v8/src/ic/x64/handler-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc
@@ -83,18 +83,12 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register result, Register scratch,
- Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, result, miss_label);
- if (!result.is(rax)) __ movp(rax, result);
- __ ret(0);
-}
-
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
@@ -102,15 +96,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
__ Push(name);
__ Push(receiver);
__ Push(holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -524,10 +510,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- __ PopReturnAddressTo(scratch2());
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
- __ PushReturnAddressFrom(scratch2());
+
+ // Stack:
+ // return address
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ Push(receiver());
+ __ Push(holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ Push(slot());
+ __ Push(vector());
+ } else {
+ __ Push(scratch3()); // slot
+ __ Push(scratch2()); // vector
+ }
+ __ Push(Operand(rsp, 4 * kPointerSize)); // return address
+ __ movp(Operand(rsp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/x64/ic-x64.cc b/deps/v8/src/ic/x64/ic-x64.cc
index 587ebd3daa..3b87bc9b6a 100644
--- a/deps/v8/src/ic/x64/ic-x64.cc
+++ b/deps/v8/src/ic/x64/ic-x64.cc
@@ -6,54 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
- Register name = StoreWithVectorDescriptor::NameRegister();
- Register value = StoreWithVectorDescriptor::ValueRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register temp = r11;
- DCHECK(!AreAliased(receiver, name, value, slot, vector, temp));
-
- __ PopReturnAddressTo(temp);
- __ Push(value);
- __ Push(slot);
- __ Push(vector);
- __ Push(receiver);
- __ Push(name);
- __ PushReturnAddressFrom(temp);
-}
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
@@ -104,9 +62,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(test_instruction_address), delta);
+ LOG(isolate, PatchIC(address, test_instruction_address, delta));
}
// Patch with a short conditional jump. Enabling means switching from a short
diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc
index 4a521b76d3..5a61eee163 100644
--- a/deps/v8/src/ic/x87/handler-compiler-x87.cc
+++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc
@@ -122,15 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
- MacroAssembler* masm, Register receiver, Register scratch1,
- Register scratch2, Label* miss_label) {
- // TODO(mvstanton): This isn't used on ia32. Move all the other
- // platform implementations into a code stub so this method can be removed.
- UNREACHABLE();
-}
-
-
// Generate call to api function.
// This function uses push() to generate smaller, faster code than
// the version above. It is an optimization that should will be removed
@@ -302,10 +293,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
}
}
+static void CompileCallLoadPropertyWithInterceptor(
+ MacroAssembler* masm, Register receiver, Register holder, Register name,
+ Handle<JSObject> holder_obj, Runtime::FunctionId id) {
+ DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
+ Runtime::FunctionForId(id)->nargs);
-static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
- Register holder, Register name,
- Handle<JSObject> holder_obj) {
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
@@ -313,15 +306,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
__ push(name);
__ push(receiver);
__ push(holder);
-}
-
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
- PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallRuntime(id);
}
@@ -538,10 +523,26 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
- __ pop(scratch2()); // save old return address
- PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
- holder());
- __ push(scratch2()); // restore old return address
+
+ // Stack:
+ // return address
+
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
+ STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
+ __ push(receiver());
+ __ push(holder_reg);
+ // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
+ if (holder_reg.is(receiver())) {
+ __ push(slot());
+ __ push(vector());
+ } else {
+ __ push(scratch3()); // slot
+ __ push(scratch2()); // vector
+ }
+ __ push(Operand(esp, 4 * kPointerSize)); // return address
+ __ mov(Operand(esp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
diff --git a/deps/v8/src/ic/x87/ic-x87.cc b/deps/v8/src/ic/x87/ic-x87.cc
index 049a85e92e..7564c006b8 100644
--- a/deps/v8/src/ic/x87/ic-x87.cc
+++ b/deps/v8/src/ic/x87/ic-x87.cc
@@ -6,54 +6,11 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#define __ ACCESS_MASM(masm)
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
- Register name = StoreWithVectorDescriptor::NameRegister();
-
- STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
- // Current stack layout:
- // - esp[12] -- value
- // - esp[8] -- slot
- // - esp[4] -- vector
- // - esp[0] -- return address
-
- Register return_address = StoreWithVectorDescriptor::SlotRegister();
- __ pop(return_address);
- __ push(receiver);
- __ push(name);
- __ push(return_address);
-}
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
-}
-
-#undef __
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
@@ -104,9 +61,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(test_instruction_address), delta);
+ LOG(isolate, PatchIC(address, test_instruction_address, delta));
}
// Patch with a short conditional jump. Enabling means switching from a short