summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/accessor-assembler-impl.h203
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc1933
-rw-r--r--deps/v8/src/ic/accessor-assembler.h45
-rw-r--r--deps/v8/src/ic/arm/handler-compiler-arm.cc79
-rw-r--r--deps/v8/src/ic/arm/ic-arm.cc485
-rw-r--r--deps/v8/src/ic/arm/ic-compiler-arm.cc33
-rw-r--r--deps/v8/src/ic/arm/stub-cache-arm.cc157
-rw-r--r--deps/v8/src/ic/arm64/handler-compiler-arm64.cc78
-rw-r--r--deps/v8/src/ic/arm64/ic-arm64.cc450
-rw-r--r--deps/v8/src/ic/arm64/ic-compiler-arm64.cc33
-rw-r--r--deps/v8/src/ic/arm64/stub-cache-arm64.cc156
-rw-r--r--deps/v8/src/ic/handler-compiler.cc320
-rw-r--r--deps/v8/src/ic/handler-compiler.h43
-rw-r--r--deps/v8/src/ic/handler-configuration-inl.h3
-rw-r--r--deps/v8/src/ic/ia32/handler-compiler-ia32.cc82
-rw-r--r--deps/v8/src/ic/ia32/ic-compiler-ia32.cc45
-rw-r--r--deps/v8/src/ic/ia32/ic-ia32.cc478
-rw-r--r--deps/v8/src/ic/ia32/stub-cache-ia32.cc185
-rw-r--r--deps/v8/src/ic/ic-compiler.cc45
-rw-r--r--deps/v8/src/ic/ic-compiler.h15
-rw-r--r--deps/v8/src/ic/ic-inl.h4
-rw-r--r--deps/v8/src/ic/ic-state.cc17
-rw-r--r--deps/v8/src/ic/ic-state.h8
-rw-r--r--deps/v8/src/ic/ic-stats.cc144
-rw-r--r--deps/v8/src/ic/ic-stats.h77
-rw-r--r--deps/v8/src/ic/ic.cc523
-rw-r--r--deps/v8/src/ic/ic.h23
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc355
-rw-r--r--deps/v8/src/ic/keyed-store-generic.h9
-rw-r--r--deps/v8/src/ic/mips/handler-compiler-mips.cc79
-rw-r--r--deps/v8/src/ic/mips/ic-compiler-mips.cc33
-rw-r--r--deps/v8/src/ic/mips/ic-mips.cc483
-rw-r--r--deps/v8/src/ic/mips/stub-cache-mips.cc157
-rw-r--r--deps/v8/src/ic/mips64/handler-compiler-mips64.cc79
-rw-r--r--deps/v8/src/ic/mips64/ic-compiler-mips64.cc33
-rw-r--r--deps/v8/src/ic/mips64/ic-mips64.cc484
-rw-r--r--deps/v8/src/ic/mips64/stub-cache-mips64.cc161
-rw-r--r--deps/v8/src/ic/ppc/handler-compiler-ppc.cc80
-rw-r--r--deps/v8/src/ic/ppc/ic-compiler-ppc.cc31
-rw-r--r--deps/v8/src/ic/ppc/ic-ppc.cc482
-rw-r--r--deps/v8/src/ic/ppc/stub-cache-ppc.cc176
-rw-r--r--deps/v8/src/ic/s390/handler-compiler-s390.cc72
-rw-r--r--deps/v8/src/ic/s390/ic-compiler-s390.cc29
-rw-r--r--deps/v8/src/ic/s390/ic-s390.cc477
-rw-r--r--deps/v8/src/ic/s390/stub-cache-s390.cc173
-rw-r--r--deps/v8/src/ic/stub-cache.h7
-rw-r--r--deps/v8/src/ic/x64/handler-compiler-x64.cc82
-rw-r--r--deps/v8/src/ic/x64/ic-compiler-x64.cc39
-rw-r--r--deps/v8/src/ic/x64/ic-x64.cc476
-rw-r--r--deps/v8/src/ic/x64/stub-cache-x64.cc153
-rw-r--r--deps/v8/src/ic/x87/OWNERS1
-rw-r--r--deps/v8/src/ic/x87/handler-compiler-x87.cc82
-rw-r--r--deps/v8/src/ic/x87/ic-compiler-x87.cc45
-rw-r--r--deps/v8/src/ic/x87/ic-x87.cc478
-rw-r--r--deps/v8/src/ic/x87/stub-cache-x87.cc185
55 files changed, 3036 insertions, 7569 deletions
diff --git a/deps/v8/src/ic/accessor-assembler-impl.h b/deps/v8/src/ic/accessor-assembler-impl.h
new file mode 100644
index 0000000000..1699b5c855
--- /dev/null
+++ b/deps/v8/src/ic/accessor-assembler-impl.h
@@ -0,0 +1,203 @@
+// 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
new file mode 100644
index 0000000000..9c795c1325
--- /dev/null
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -0,0 +1,1933 @@
+// 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.
+
+#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/ic/handler-configuration.h"
+#include "src/ic/stub-cache.h"
+
+namespace v8 {
+namespace internal {
+
+using compiler::CodeAssemblerState;
+
+//////////////////// Private helpers.
+
+Node* AccessorAssemblerImpl::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());
+
+ // TODO(ishell): add helper class that hides offset computations for a series
+ // of loads.
+ int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
+ // Adding |header_size| with a separate IntPtrAdd rather than passing it
+ // into ElementOffsetFromIndex() allows it to be folded into a single
+ // [base, index, offset] indirect memory access on x64.
+ Node* offset =
+ ElementOffsetFromIndex(slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS);
+ Node* feedback = Load(MachineType::AnyTagged(), vector,
+ IntPtrAdd(offset, IntPtrConstant(header_size)));
+
+ // Try to quickly handle the monomorphic case without knowing for sure
+ // if we have a weak cell in feedback. We do know it's safe to look
+ // at WeakCell::kValueOffset.
+ GotoIf(WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback)),
+ if_miss);
+
+ Node* handler =
+ Load(MachineType::AnyTagged(), vector,
+ IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize)));
+
+ var_handler->Bind(handler);
+ Goto(if_handler);
+ return feedback;
+}
+
+void AccessorAssemblerImpl::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());
+
+ // Iterate {feedback} array.
+ const int kEntrySize = 2;
+
+ for (int i = 0; i < unroll_count; i++) {
+ Label next_entry(this);
+ Node* cached_map =
+ LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize));
+ GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
+
+ // Found, now call handler.
+ Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1);
+ var_handler->Bind(handler);
+ Goto(if_handler);
+
+ Bind(&next_entry);
+ }
+
+ // Loop from {unroll_count}*kEntrySize to {length}.
+ Node* init = IntPtrConstant(unroll_count * kEntrySize);
+ Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
+ BuildFastLoop(
+ MachineType::PointerRepresentation(), init, length,
+ [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
+ Node* cached_map =
+ LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
+
+ Label next_entry(this);
+ GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
+
+ // Found, now call handler.
+ Node* handler = LoadFixedArrayElement(feedback, index, kPointerSize);
+ var_handler->Bind(handler);
+ Goto(if_handler);
+
+ Bind(&next_entry);
+ },
+ kEntrySize, IndexAdvanceMode::kPost);
+ // The loop falls through if no handler was found.
+ Goto(if_miss);
+}
+
+void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
+ Node* receiver_map, Node* feedback, Label* if_handler,
+ Variable* var_handler, Label* if_transition_handler,
+ Variable* var_transition_map_cell, Label* if_miss) {
+ DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
+ DCHECK_EQ(MachineRepresentation::kTagged, var_transition_map_cell->rep());
+
+ const int kEntrySize = 3;
+
+ Node* init = IntPtrConstant(0);
+ Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
+ BuildFastLoop(MachineType::PointerRepresentation(), init, length,
+ [this, receiver_map, feedback, if_handler, var_handler,
+ if_transition_handler, var_transition_map_cell](Node* index) {
+ Node* cached_map =
+ LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
+ Label next_entry(this);
+ GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
+
+ Node* maybe_transition_map_cell =
+ LoadFixedArrayElement(feedback, index, kPointerSize);
+
+ var_handler->Bind(
+ LoadFixedArrayElement(feedback, index, 2 * kPointerSize));
+ GotoIf(WordEqual(maybe_transition_map_cell,
+ LoadRoot(Heap::kUndefinedValueRootIndex)),
+ if_handler);
+ var_transition_map_cell->Bind(maybe_transition_map_cell);
+ Goto(if_transition_handler);
+
+ Bind(&next_entry);
+ },
+ kEntrySize, IndexAdvanceMode::kPost);
+ // The loop falls through if no handler was found.
+ Goto(if_miss);
+}
+
+void AccessorAssemblerImpl::HandleLoadICHandlerCase(
+ const LoadICParameters* p, Node* handler, Label* miss,
+ ElementSupport support_elements) {
+ Comment("have_handler");
+ Variable var_holder(this, MachineRepresentation::kTagged);
+ var_holder.Bind(p->receiver);
+ Variable var_smi_handler(this, MachineRepresentation::kTagged);
+ var_smi_handler.Bind(handler);
+
+ Variable* vars[] = {&var_holder, &var_smi_handler};
+ Label if_smi_handler(this, 2, vars);
+ Label try_proto_handler(this), call_handler(this);
+
+ Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
+
+ // |handler| is a Smi, encoding what to do. See SmiHandler methods
+ // for the encoding format.
+ Bind(&if_smi_handler);
+ {
+ HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
+ miss, 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);
+ }
+
+ Bind(&call_handler);
+ {
+ typedef LoadWithVectorDescriptor Descriptor;
+ TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver,
+ p->name, p->slot, p->vector);
+ }
+}
+
+void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
+ const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
+ ElementSupport support_elements) {
+ Variable var_double_value(this, MachineRepresentation::kFloat64);
+ Label rebox_double(this, &var_double_value);
+
+ Node* handler_word = SmiUntag(smi_handler);
+ Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
+ if (support_elements == kSupportElements) {
+ Label property(this);
+ GotoUnless(
+ WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
+ &property);
+
+ Comment("element_load");
+ Node* intptr_index = TryToIntptr(p->name, miss);
+ Node* elements = LoadElements(holder);
+ Node* is_jsarray_condition =
+ IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
+ Node* elements_kind =
+ DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
+ Label if_hole(this), unimplemented_elements_kind(this);
+ Label* out_of_bounds = miss;
+ EmitElementLoad(holder, elements, elements_kind, intptr_index,
+ is_jsarray_condition, &if_hole, &rebox_double,
+ &var_double_value, &unimplemented_elements_kind,
+ out_of_bounds, miss);
+
+ Bind(&unimplemented_elements_kind);
+ {
+ // Smi handlers should only be installed for supported elements kinds.
+ // Crash if we get here.
+ DebugBreak();
+ Goto(miss);
+ }
+
+ Bind(&if_hole);
+ {
+ Comment("convert hole");
+ GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
+ Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
+ DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
+ GotoUnless(
+ WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
+ miss);
+ Return(UndefinedConstant());
+ }
+
+ Bind(&property);
+ Comment("property_load");
+ }
+
+ Label constant(this), field(this);
+ Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)),
+ &field, &constant);
+
+ Bind(&field);
+ {
+ Comment("field_load");
+ Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word);
+
+ Label inobject(this), out_of_object(this);
+ Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
+ &out_of_object);
+
+ Bind(&inobject);
+ {
+ Label is_double(this);
+ GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
+ Return(LoadObjectField(holder, offset));
+
+ Bind(&is_double);
+ if (FLAG_unbox_double_fields) {
+ var_double_value.Bind(
+ LoadObjectField(holder, offset, MachineType::Float64()));
+ } else {
+ Node* mutable_heap_number = LoadObjectField(holder, offset);
+ var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
+ }
+ Goto(&rebox_double);
+ }
+
+ Bind(&out_of_object);
+ {
+ Label is_double(this);
+ Node* properties = LoadProperties(holder);
+ Node* value = LoadObjectField(properties, offset);
+ GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
+ Return(value);
+
+ Bind(&is_double);
+ var_double_value.Bind(LoadHeapNumberValue(value));
+ Goto(&rebox_double);
+ }
+
+ Bind(&rebox_double);
+ Return(AllocateHeapNumberWithValue(var_double_value.value()));
+ }
+
+ Bind(&constant);
+ {
+ Comment("constant_load");
+ Node* descriptors = LoadMapDescriptors(LoadMap(holder));
+ Node* descriptor =
+ DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word);
+ CSA_ASSERT(this,
+ UintPtrLessThan(descriptor,
+ LoadAndUntagFixedArrayBaseLength(descriptors)));
+ Node* value = LoadFixedArrayElement(descriptors, descriptor);
+
+ Label if_accessor_info(this);
+ GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
+ &if_accessor_info);
+ Return(value);
+
+ Bind(&if_accessor_info);
+ Callable callable = CodeFactory::ApiGetter(isolate());
+ TailCallStub(callable, p->context, p->receiver, holder, value);
+ }
+}
+
+void AccessorAssemblerImpl::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) {
+ DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
+ DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
+
+ // IC dispatchers rely on these assumptions to be held.
+ STATIC_ASSERT(FixedArray::kLengthOffset == LoadHandler::kHolderCellOffset);
+ DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kSmiHandlerIndex),
+ LoadHandler::kSmiHandlerOffset);
+ DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kValidityCellIndex),
+ LoadHandler::kValidityCellOffset);
+
+ // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
+ Label validity_cell_check_done(this);
+ Node* validity_cell =
+ LoadObjectField(handler, LoadHandler::kValidityCellOffset);
+ GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
+ &validity_cell_check_done);
+ Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
+ GotoIf(WordNotEqual(cell_value,
+ SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
+ miss);
+ Goto(&validity_cell_check_done);
+
+ Bind(&validity_cell_check_done);
+ Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
+ CSA_ASSERT(this, TaggedIsSmi(smi_handler));
+ Node* handler_flags = SmiUntag(smi_handler);
+
+ Label check_prototypes(this);
+ GotoUnless(
+ IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
+ &check_prototypes);
+ {
+ CSA_ASSERT(this, Word32BinaryNot(
+ HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE)));
+ // We have a dictionary receiver, do a negative lookup check.
+ NameDictionaryNegativeLookup(p->receiver, p->name, miss);
+ Goto(&check_prototypes);
+ }
+
+ Bind(&check_prototypes);
+ Node* maybe_holder_cell =
+ LoadObjectField(handler, LoadHandler::kHolderCellOffset);
+ Label array_handler(this), tuple_handler(this);
+ Branch(TaggedIsSmi(maybe_holder_cell), &array_handler, &tuple_handler);
+
+ Bind(&tuple_handler);
+ {
+ Label load_existent(this);
+ 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);
+ } else {
+ Return(UndefinedConstant());
+ }
+
+ Bind(&load_existent);
+ Node* holder = LoadWeakCellValue(maybe_holder_cell);
+ // The |holder| is guaranteed to be alive at this point since we passed
+ // both the receiver map check and the validity cell check.
+ CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
+
+ var_holder->Bind(holder);
+ var_smi_handler->Bind(smi_handler);
+ Goto(if_smi_handler);
+ }
+
+ 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);
+ }
+}
+
+Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
+ const LoadICParameters* p, Node* handler, Node* handler_length,
+ Node* handler_flags, Label* miss,
+ bool throw_reference_error_if_nonexistent) {
+ Variable start_index(this, MachineType::PointerRepresentation());
+ start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
+
+ Label can_access(this);
+ GotoUnless(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
+ &can_access);
+ {
+ // Skip this entry of a handler.
+ start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
+
+ int offset =
+ FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex);
+ Node* expected_native_context =
+ LoadWeakCellValue(LoadObjectField(handler, offset), miss);
+ CSA_ASSERT(this, IsNativeContext(expected_native_context));
+
+ 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);
+ // For JSGlobalProxy receiver try to compare security tokens of current
+ // and expected native contexts.
+ Node* expected_token = LoadContextElement(expected_native_context,
+ Context::SECURITY_TOKEN_INDEX);
+ Node* current_token =
+ LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
+ Branch(WordEqual(expected_token, current_token), &can_access, miss);
+ }
+ 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);
+
+ Node* maybe_holder_cell =
+ LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
+ Label load_existent(this);
+ 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);
+ } else {
+ Return(UndefinedConstant());
+ }
+
+ Bind(&load_existent);
+ Node* holder = LoadWeakCellValue(maybe_holder_cell);
+ // The |holder| is guaranteed to be alive at this point since we passed
+ // the receiver map check, the validity cell check and the prototype chain
+ // check.
+ CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
+ return holder;
+}
+
+void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase(
+ const LoadICParameters* pp, Node* handler, Label* miss,
+ bool throw_reference_error_if_nonexistent) {
+ LoadICParameters p = *pp;
+ DCHECK_NULL(p.receiver);
+ Node* native_context = LoadNativeContext(p.context);
+ p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX);
+
+ Variable var_holder(this, MachineRepresentation::kTagged);
+ Variable var_smi_handler(this, MachineRepresentation::kTagged);
+ Label if_smi_handler(this);
+ HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
+ &if_smi_handler, miss,
+ throw_reference_error_if_nonexistent);
+ Bind(&if_smi_handler);
+ HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
+ miss, kOnlyProperties);
+}
+
+void AccessorAssemblerImpl::HandleStoreICHandlerCase(
+ const StoreICParameters* p, Node* handler, Label* miss,
+ ElementSupport support_elements) {
+ Label if_smi_handler(this), if_nonsmi_handler(this);
+ Label if_proto_handler(this), if_element_handler(this), call_handler(this);
+
+ Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
+
+ // |handler| is a Smi, encoding what to do. See SmiHandler methods
+ // for the encoding format.
+ Bind(&if_smi_handler);
+ {
+ Node* holder = p->receiver;
+ Node* handler_word = SmiUntag(handler);
+
+ // Handle non-transitioning field stores.
+ HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
+ }
+
+ Bind(&if_nonsmi_handler);
+ {
+ Node* handler_map = LoadMap(handler);
+ if (support_elements == kSupportElements) {
+ GotoIf(IsTuple2Map(handler_map), &if_element_handler);
+ }
+ Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
+ }
+
+ if (support_elements == kSupportElements) {
+ Bind(&if_element_handler);
+ { HandleStoreICElementHandlerCase(p, handler, miss); }
+ }
+
+ Bind(&if_proto_handler);
+ {
+ HandleStoreICProtoHandler(p, handler, miss);
+ }
+
+ // |handler| is a heap object. Must be code, call it.
+ Bind(&call_handler);
+ {
+ StoreWithVectorDescriptor descriptor(isolate());
+ TailCallStub(descriptor, handler, p->context, p->receiver, p->name,
+ p->value, p->slot, p->vector);
+ }
+}
+
+void AccessorAssemblerImpl::HandleStoreICElementHandlerCase(
+ const StoreICParameters* p, Node* handler, Label* miss) {
+ Comment("HandleStoreICElementHandlerCase");
+ Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
+ Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
+ GotoIf(WordNotEqual(cell_value,
+ SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
+ miss);
+
+ Node* code_handler = LoadObjectField(handler, Tuple2::kValue2Offset);
+ CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
+
+ StoreWithVectorDescriptor descriptor(isolate());
+ TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name,
+ p->value, p->slot, p->vector);
+}
+
+void AccessorAssemblerImpl::HandleStoreICProtoHandler(
+ const StoreICParameters* p, Node* handler, Label* miss) {
+ // IC dispatchers rely on these assumptions to be held.
+ STATIC_ASSERT(FixedArray::kLengthOffset ==
+ StoreHandler::kTransitionCellOffset);
+ DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
+ StoreHandler::kSmiHandlerOffset);
+ DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
+ StoreHandler::kValidityCellOffset);
+
+ // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
+ Label validity_cell_check_done(this);
+ Node* validity_cell =
+ LoadObjectField(handler, StoreHandler::kValidityCellOffset);
+ GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
+ &validity_cell_check_done);
+ Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
+ GotoIf(WordNotEqual(cell_value,
+ SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
+ miss);
+ Goto(&validity_cell_check_done);
+
+ Bind(&validity_cell_check_done);
+ Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
+ CSA_ASSERT(this, TaggedIsSmi(smi_handler));
+
+ Node* maybe_transition_cell =
+ LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
+ Label array_handler(this), tuple_handler(this);
+ Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
+
+ Variable var_transition(this, MachineRepresentation::kTagged);
+ Label if_transition(this), if_transition_to_constant(this);
+ Bind(&tuple_handler);
+ {
+ Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
+ var_transition.Bind(transition);
+ Goto(&if_transition);
+ }
+
+ Bind(&array_handler);
+ {
+ Node* length = SmiUntag(maybe_transition_cell);
+ BuildFastLoop(MachineType::PointerRepresentation(),
+ 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);
+
+ Node* maybe_transition_cell =
+ LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
+ Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
+ var_transition.Bind(transition);
+ Goto(&if_transition);
+ }
+
+ Bind(&if_transition);
+ {
+ Node* holder = p->receiver;
+ Node* transition = var_transition.value();
+ Node* handler_word = SmiUntag(smi_handler);
+
+ GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
+
+ Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ GotoIf(WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kTransitionToConstant)),
+ &if_transition_to_constant);
+
+ // Handle transitioning field stores.
+ HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
+ miss);
+
+ Bind(&if_transition_to_constant);
+ {
+ // Check that constant matches value.
+ Node* value_index_in_descriptor =
+ DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
+ Node* descriptors = LoadMapDescriptors(transition);
+ Node* constant =
+ LoadFixedArrayElement(descriptors, value_index_in_descriptor);
+ GotoIf(WordNotEqual(p->value, constant), miss);
+
+ StoreMap(p->receiver, transition);
+ Return(p->value);
+ }
+ }
+}
+
+void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
+ Node* holder,
+ Node* value,
+ Node* transition,
+ Label* miss) {
+ Comment(transition ? "transitioning field store" : "field store");
+
+#ifdef DEBUG
+ Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ if (transition) {
+ CSA_ASSERT(
+ this,
+ Word32Or(
+ WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kTransitionToField)),
+ WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kTransitionToConstant))));
+ } else {
+ CSA_ASSERT(this, WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreField)));
+ }
+#endif
+
+ Node* field_representation =
+ DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
+
+ Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
+ if_tagged_field(this);
+
+ GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
+ &if_tagged_field);
+ GotoIf(WordEqual(field_representation,
+ IntPtrConstant(StoreHandler::kHeapObject)),
+ &if_heap_object_field);
+ GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
+ &if_double_field);
+ CSA_ASSERT(this, WordEqual(field_representation,
+ IntPtrConstant(StoreHandler::kSmi)));
+ Goto(&if_smi_field);
+
+ Bind(&if_tagged_field);
+ {
+ Comment("store tagged field");
+ HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
+ value, transition, miss);
+ }
+
+ Bind(&if_double_field);
+ {
+ Comment("store double field");
+ HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
+ value, transition, miss);
+ }
+
+ Bind(&if_heap_object_field);
+ {
+ Comment("store heap object field");
+ HandleStoreFieldAndReturn(handler_word, holder,
+ Representation::HeapObject(), value, transition,
+ miss);
+ }
+
+ Bind(&if_smi_field);
+ {
+ Comment("store smi field");
+ HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
+ value, transition, miss);
+ }
+}
+
+void AccessorAssemblerImpl::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);
+
+ Label if_inobject(this), if_out_of_object(this);
+ Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
+ &if_out_of_object);
+
+ Bind(&if_inobject);
+ {
+ StoreNamedField(handler_word, holder, true, representation, prepared_value,
+ transition_to_field);
+ if (transition_to_field) {
+ StoreMap(holder, transition);
+ }
+ Return(value);
+ }
+
+ Bind(&if_out_of_object);
+ {
+ if (transition_to_field) {
+ Label storage_extended(this);
+ GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
+ &storage_extended);
+ Comment("[ Extend storage");
+ ExtendPropertiesBackingStore(holder);
+ Comment("] Extend storage");
+ Goto(&storage_extended);
+
+ Bind(&storage_extended);
+ }
+
+ StoreNamedField(handler_word, holder, false, representation, prepared_value,
+ transition_to_field);
+ if (transition_to_field) {
+ StoreMap(holder, transition);
+ }
+ Return(value);
+ }
+}
+
+Node* AccessorAssemblerImpl::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);
+ Node* value_index_in_descriptor =
+ DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
+ Node* descriptors =
+ LoadMapDescriptors(transition ? transition : LoadMap(holder));
+ 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.
+ {
+ Node* field_type = LoadWeakCellValue(maybe_field_type, bailout);
+ Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
+ }
+ Bind(&done);
+
+ } else if (representation.IsSmi()) {
+ GotoUnless(TaggedIsSmi(value), bailout);
+
+ } else {
+ DCHECK(representation.IsTagged());
+ }
+ return value;
+}
+
+void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) {
+ Node* properties = LoadProperties(object);
+ Node* length = LoadFixedArrayBaseLength(properties);
+
+ ParameterMode mode = OptimalParameterMode();
+ length = TaggedToParameter(length, mode);
+
+ Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
+ Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
+
+ // Grow properties array.
+ ElementsKind kind = FAST_ELEMENTS;
+ DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
+ FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind));
+ // The size of a new properties backing store is guaranteed to be small
+ // enough that the new backing store will be allocated in new space.
+ CSA_ASSERT(this,
+ UintPtrOrSmiLessThan(
+ new_capacity,
+ IntPtrOrSmiConstant(
+ kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode),
+ mode));
+
+ Node* new_properties = AllocateFixedArray(kind, new_capacity, mode);
+
+ FillFixedArrayWithValue(kind, new_properties, length, new_capacity,
+ Heap::kUndefinedValueRootIndex, mode);
+
+ // |new_properties| is guaranteed to be in new space, so we can skip
+ // the write barrier.
+ CopyFixedArrayElements(kind, properties, new_properties, length,
+ SKIP_WRITE_BARRIER, mode);
+
+ 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) {
+ bool store_value_as_double = representation.IsDouble();
+ Node* property_storage = object;
+ if (!is_inobject) {
+ property_storage = LoadProperties(object);
+ }
+
+ Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word);
+ if (representation.IsDouble()) {
+ if (!FLAG_unbox_double_fields || !is_inobject) {
+ if (transition_to_field) {
+ Node* heap_number = AllocateHeapNumberWithValue(value, MUTABLE);
+ // Store the new mutable heap number into the object.
+ value = heap_number;
+ store_value_as_double = false;
+ } else {
+ // Load the heap number.
+ property_storage = LoadObjectField(property_storage, offset);
+ // Store the double value into it.
+ offset = IntPtrConstant(HeapNumber::kValueOffset);
+ }
+ }
+ }
+
+ if (store_value_as_double) {
+ StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
+ MachineRepresentation::kFloat64);
+ } else if (representation.IsSmi()) {
+ StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
+ } else {
+ StoreObjectField(property_storage, offset, value);
+ }
+}
+
+void AccessorAssemblerImpl::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);
+ GotoIf(is_jsarray_condition, &if_array);
+ {
+ var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
+ Goto(&length_loaded);
+ }
+ Bind(&if_array);
+ {
+ var_length.Bind(SmiUntag(LoadJSArrayLength(object)));
+ Goto(&length_loaded);
+ }
+ Bind(&length_loaded);
+ GotoUnless(UintPtrLessThan(intptr_index, var_length.value()), miss);
+}
+
+void AccessorAssemblerImpl::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 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);
+ GotoIf(
+ Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
+ &if_nonfast);
+
+ EmitFastElementsBoundsCheck(object, elements, intptr_index,
+ is_jsarray_condition, out_of_bounds);
+ int32_t kinds[] = {// Handled by if_fast_packed.
+ FAST_SMI_ELEMENTS, FAST_ELEMENTS,
+ // Handled by if_fast_holey.
+ FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS,
+ // Handled by if_fast_double.
+ FAST_DOUBLE_ELEMENTS,
+ // Handled by if_fast_holey_double.
+ FAST_HOLEY_DOUBLE_ELEMENTS};
+ Label* labels[] = {// FAST_{SMI,}_ELEMENTS
+ &if_fast_packed, &if_fast_packed,
+ // FAST_HOLEY_{SMI,}_ELEMENTS
+ &if_fast_holey, &if_fast_holey,
+ // FAST_DOUBLE_ELEMENTS
+ &if_fast_double,
+ // FAST_HOLEY_DOUBLE_ELEMENTS
+ &if_fast_holey_double};
+ Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
+ arraysize(kinds));
+
+ Bind(&if_fast_packed);
+ {
+ Comment("fast packed elements");
+ Return(LoadFixedArrayElement(elements, intptr_index));
+ }
+
+ Bind(&if_fast_holey);
+ {
+ Comment("fast holey elements");
+ Node* element = LoadFixedArrayElement(elements, intptr_index);
+ GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
+ Return(element);
+ }
+
+ Bind(&if_fast_double);
+ {
+ Comment("packed double elements");
+ var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
+ MachineType::Float64()));
+ Goto(rebox_double);
+ }
+
+ Bind(&if_fast_holey_double);
+ {
+ Comment("holey double elements");
+ Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
+ MachineType::Float64(), 0,
+ INTPTR_PARAMETERS, if_hole);
+ var_double_value->Bind(value);
+ Goto(rebox_double);
+ }
+
+ Bind(&if_nonfast);
+ {
+ STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
+ GotoIf(Int32GreaterThanOrEqual(
+ elements_kind,
+ Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
+ &if_typed_array);
+ GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
+ &if_dictionary);
+ Goto(unimplemented_elements_kind);
+ }
+
+ Bind(&if_dictionary);
+ {
+ Comment("dictionary elements");
+ GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
+ Variable var_entry(this, MachineType::PointerRepresentation());
+ Label if_found(this);
+ NumberDictionaryLookup<SeededNumberDictionary>(
+ 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* kind = DecodeWord32<PropertyDetails::KindField>(details);
+ // TODO(jkummerow): Support accessors without missing?
+ GotoUnless(Word32Equal(kind, Int32Constant(kData)), miss);
+ // Finally, load the value.
+ Node* value_index = EntryToIndex<SeededNumberDictionary>(
+ var_entry.value(), SeededNumberDictionary::kEntryValueIndex);
+ Return(LoadFixedArrayElement(elements, value_index));
+ }
+
+ Bind(&if_typed_array);
+ {
+ Comment("typed elements");
+ // Check if buffer has been neutered.
+ Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
+ GotoIf(IsDetachedBuffer(buffer), miss);
+
+ // Bounds check.
+ Node* length =
+ SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
+ GotoUnless(UintPtrLessThan(intptr_index, length), out_of_bounds);
+
+ // Backing store = external_pointer + base_pointer.
+ Node* external_pointer =
+ LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
+ MachineType::Pointer());
+ Node* base_pointer =
+ LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
+ Node* backing_store =
+ IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer));
+
+ Label uint8_elements(this), int8_elements(this), uint16_elements(this),
+ int16_elements(this), uint32_elements(this), int32_elements(this),
+ float32_elements(this), float64_elements(this);
+ Label* elements_kind_labels[] = {
+ &uint8_elements, &uint8_elements, &int8_elements,
+ &uint16_elements, &int16_elements, &uint32_elements,
+ &int32_elements, &float32_elements, &float64_elements};
+ int32_t elements_kinds[] = {
+ UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
+ UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
+ INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS};
+ const size_t kTypedElementsKindCount =
+ LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
+ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
+ DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
+ DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
+ Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
+ kTypedElementsKindCount);
+ Bind(&uint8_elements);
+ {
+ Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
+ Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
+ Return(SmiFromWord32(element));
+ }
+ Bind(&int8_elements);
+ {
+ Comment("INT8_ELEMENTS");
+ Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
+ 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));
+ }
+ Bind(&int16_elements);
+ {
+ Comment("INT16_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(1));
+ Node* element = Load(MachineType::Int16(), backing_store, index);
+ 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));
+ }
+ Bind(&int32_elements);
+ {
+ Comment("INT32_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ Node* element = Load(MachineType::Int32(), backing_store, index);
+ Return(ChangeInt32ToTagged(element));
+ }
+ Bind(&float32_elements);
+ {
+ Comment("FLOAT32_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ Node* element = Load(MachineType::Float32(), backing_store, index);
+ var_double_value->Bind(ChangeFloat32ToFloat64(element));
+ Goto(rebox_double);
+ }
+ Bind(&float64_elements);
+ {
+ Comment("FLOAT64_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(3));
+ Node* element = Load(MachineType::Float64(), backing_store, index);
+ var_double_value->Bind(element);
+ Goto(rebox_double);
+ }
+ }
+}
+
+void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name,
+ Label* miss) {
+ Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss);
+
+ Label done(this);
+ Label if_property_cell(this), if_dictionary_object(this);
+
+ // |maybe_prototype| is either a PropertyCell or a slow-mode prototype.
+ Branch(WordEqual(LoadMap(maybe_prototype),
+ LoadRoot(Heap::kGlobalPropertyCellMapRootIndex)),
+ &if_property_cell, &if_dictionary_object);
+
+ Bind(&if_dictionary_object);
+ {
+ CSA_ASSERT(this, IsDictionaryMap(LoadMap(maybe_prototype)));
+ NameDictionaryNegativeLookup(maybe_prototype, name, miss);
+ Goto(&done);
+ }
+
+ Bind(&if_property_cell);
+ {
+ // Ensure the property cell still contains the hole.
+ Node* value = LoadObjectField(maybe_prototype, PropertyCell::kValueOffset);
+ GotoIf(WordNotEqual(value, LoadRoot(Heap::kTheHoleValueRootIndex)), miss);
+ Goto(&done);
+ }
+
+ Bind(&done);
+}
+
+void AccessorAssemblerImpl::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.
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ Label done(this);
+ NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
+ &done);
+ Bind(&done);
+}
+
+//////////////////// Stub cache access helpers.
+
+enum AccessorAssemblerImpl::StubCacheTable : int {
+ kPrimary = static_cast<int>(StubCache::kPrimary),
+ kSecondary = static_cast<int>(StubCache::kSecondary)
+};
+
+Node* AccessorAssemblerImpl::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).
+ Node* hash_field = LoadNameHashField(name);
+ CSA_ASSERT(this,
+ Word32Equal(Word32And(hash_field,
+ Int32Constant(Name::kHashNotComputedMask)),
+ Int32Constant(0)));
+
+ // Using only the low bits in 64-bit mode is unlikely to increase the
+ // risk of collision even if the heap is spread over an area larger than
+ // 4Gb (and not at all if it isn't).
+ Node* map32 = TruncateWordToWord32(BitcastTaggedToWord(map));
+ Node* hash = Int32Add(hash_field, map32);
+ // Base the offset on a simple combination of name and map.
+ hash = Word32Xor(hash, Int32Constant(StubCache::kPrimaryMagic));
+ uint32_t mask = (StubCache::kPrimaryTableSize - 1)
+ << StubCache::kCacheIndexShift;
+ return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
+}
+
+Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) {
+ // See v8::internal::StubCache::SecondaryOffset().
+
+ // Use the seed from the primary cache in the secondary cache.
+ Node* name32 = TruncateWordToWord32(BitcastTaggedToWord(name));
+ Node* hash = Int32Sub(TruncateWordToWord32(seed), name32);
+ hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
+ int32_t mask = (StubCache::kSecondaryTableSize - 1)
+ << StubCache::kCacheIndexShift;
+ 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) {
+ StubCache::Table table = static_cast<StubCache::Table>(table_id);
+#ifdef DEBUG
+ if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
+ Goto(if_miss);
+ return;
+ } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
+ Goto(if_miss);
+ return;
+ }
+#endif
+ // The {table_offset} holds the entry offset times four (due to masking
+ // and shifting optimizations).
+ const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
+ entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
+
+ // Check that the key in the entry matches the name.
+ Node* key_base =
+ ExternalConstant(ExternalReference(stub_cache->key_reference(table)));
+ Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
+ GotoIf(WordNotEqual(name, entry_key), if_miss);
+
+ // Get the map entry from the cache.
+ DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
+ stub_cache->key_reference(table).address());
+ Node* entry_map =
+ Load(MachineType::Pointer(), key_base,
+ IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize * 2)));
+ GotoIf(WordNotEqual(map, entry_map), if_miss);
+
+ DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
+ stub_cache->key_reference(table).address());
+ Node* handler = Load(MachineType::TaggedPointer(), key_base,
+ IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize)));
+
+ // We found the handler.
+ var_handler->Bind(handler);
+ Goto(if_handler);
+}
+
+void AccessorAssemblerImpl::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();
+ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
+
+ // Check that the {receiver} isn't a smi.
+ GotoIf(TaggedIsSmi(receiver), &miss);
+
+ Node* receiver_map = LoadMap(receiver);
+
+ // Probe the primary table.
+ Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
+ TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
+ receiver_map, if_handler, var_handler, &try_secondary);
+
+ Bind(&try_secondary);
+ {
+ // Probe the secondary table.
+ Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
+ TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
+ receiver_map, if_handler, var_handler, &miss);
+ }
+
+ Bind(&miss);
+ {
+ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
+ Goto(if_miss);
+ }
+}
+
+//////////////////// Entry points into private implementation (one per stub).
+
+void AccessorAssemblerImpl::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),
+ try_megamorphic(this /*, Label::kDeferred*/),
+ miss(this /*, Label::kDeferred*/);
+
+ Node* receiver_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+
+ // Check monomorphic case.
+ Node* feedback =
+ TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
+ &var_handler, &try_polymorphic);
+ Bind(&if_handler);
+ { HandleLoadICHandlerCase(p, var_handler.value(), &miss); }
+
+ Bind(&try_polymorphic);
+ {
+ // Check polymorphic case.
+ Comment("LoadIC_try_polymorphic");
+ GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
+ HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
+ &miss, 2);
+ }
+
+ Bind(&try_megamorphic);
+ {
+ // Check megamorphic case.
+ GotoUnless(
+ WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
+
+ TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
+ &if_handler, &var_handler, &miss);
+ }
+ Bind(&miss);
+ {
+ TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
+ p->slot, p->vector);
+ }
+}
+
+void AccessorAssemblerImpl::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)));
+
+ Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
+ Node* handler_flags = SmiUntag(smi_handler);
+
+ Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler);
+
+ Node* holder =
+ EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
+ &miss, throw_reference_error_if_nonexistent);
+
+ HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, kOnlyProperties);
+
+ Bind(&miss);
+ {
+ TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
+ p->slot, p->vector);
+ }
+}
+
+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);
+ 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);
+ CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
+
+ Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
+ GotoIf(WordEqual(value, TheHoleConstant()), &miss);
+ 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);
+
+ bool throw_reference_error_if_nonexistent =
+ typeof_mode == NOT_INSIDE_TYPEOF;
+ HandleLoadGlobalICHandlerCase(p, handler, &miss,
+ throw_reference_error_if_nonexistent);
+ }
+
+ Bind(&call_handler);
+ {
+ LoadWithVectorDescriptor descriptor(isolate());
+ 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);
+ }
+ Bind(&miss);
+ {
+ TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->name, p->slot,
+ p->vector);
+ }
+}
+
+void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
+ Variable var_handler(this, MachineRepresentation::kTagged);
+ // TODO(ishell): defer blocks when it works.
+ Label if_handler(this, &var_handler), try_polymorphic(this),
+ try_megamorphic(this /*, Label::kDeferred*/),
+ try_polymorphic_name(this /*, Label::kDeferred*/),
+ miss(this /*, Label::kDeferred*/);
+
+ Node* receiver_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+
+ // Check monomorphic case.
+ Node* feedback =
+ TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
+ &var_handler, &try_polymorphic);
+ Bind(&if_handler);
+ { HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); }
+
+ Bind(&try_polymorphic);
+ {
+ // Check polymorphic case.
+ Comment("KeyedLoadIC_try_polymorphic");
+ GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
+ HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
+ &miss, 2);
+ }
+
+ Bind(&try_megamorphic);
+ {
+ // Check megamorphic case.
+ Comment("KeyedLoadIC_try_megamorphic");
+ GotoUnless(
+ WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &try_polymorphic_name);
+ // TODO(jkummerow): Inline this? Or some of it?
+ TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
+ p->receiver, p->name, p->slot, p->vector);
+ }
+ Bind(&try_polymorphic_name);
+ {
+ // We might have a name in feedback, and a fixed array in the next slot.
+ Comment("KeyedLoadIC_try_polymorphic_name");
+ GotoUnless(WordEqual(feedback, p->name), &miss);
+ // If the name comparison succeeded, we know we have a fixed array with
+ // at least one map/handler pair.
+ Node* offset = ElementOffsetFromIndex(
+ p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
+ FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
+ Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
+ HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
+ 1);
+ }
+ Bind(&miss);
+ {
+ Comment("KeyedLoadIC_miss");
+ TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
+ p->name, p->slot, p->vector);
+ }
+}
+
+void AccessorAssemblerImpl::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);
+
+ 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);
+
+ 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());
+ }
+
+ 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);
+ }
+
+ Bind(&slow);
+ {
+ Comment("KeyedLoadGeneric_slow");
+ IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
+ // TODO(jkummerow): Should we use the GetProperty TF stub instead?
+ TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver,
+ p->name);
+ }
+}
+
+void AccessorAssemblerImpl::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),
+ try_megamorphic(this /*, Label::kDeferred*/),
+ miss(this /*, Label::kDeferred*/);
+
+ Node* receiver_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+
+ // Check monomorphic case.
+ Node* feedback =
+ TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
+ &var_handler, &try_polymorphic);
+ Bind(&if_handler);
+ {
+ Comment("StoreIC_if_handler");
+ HandleStoreICHandlerCase(p, var_handler.value(), &miss);
+ }
+
+ Bind(&try_polymorphic);
+ {
+ // Check polymorphic case.
+ Comment("StoreIC_try_polymorphic");
+ GotoUnless(
+ WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
+ &try_megamorphic);
+ HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
+ &miss, 2);
+ }
+
+ Bind(&try_megamorphic);
+ {
+ // Check megamorphic case.
+ GotoUnless(
+ WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
+
+ TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
+ &if_handler, &var_handler, &miss);
+ }
+ Bind(&miss);
+ {
+ TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
+ p->vector, p->receiver, p->name);
+ }
+}
+
+void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
+ LanguageMode language_mode) {
+ // TODO(ishell): defer blocks when it works.
+ Label miss(this /*, Label::kDeferred*/);
+ {
+ Variable var_handler(this, MachineRepresentation::kTagged);
+
+ // TODO(ishell): defer blocks when it works.
+ Label if_handler(this, &var_handler), try_polymorphic(this),
+ try_megamorphic(this /*, Label::kDeferred*/),
+ try_polymorphic_name(this /*, Label::kDeferred*/);
+
+ Node* receiver_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+
+ // Check monomorphic case.
+ Node* feedback =
+ TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
+ &var_handler, &try_polymorphic);
+ Bind(&if_handler);
+ {
+ Comment("KeyedStoreIC_if_handler");
+ HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
+ }
+
+ Bind(&try_polymorphic);
+ {
+ // CheckPolymorphic case.
+ Comment("KeyedStoreIC_try_polymorphic");
+ GotoUnless(
+ WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
+ &try_megamorphic);
+ Label if_transition_handler(this);
+ Variable var_transition_map_cell(this, MachineRepresentation::kTagged);
+ HandleKeyedStorePolymorphicCase(receiver_map, feedback, &if_handler,
+ &var_handler, &if_transition_handler,
+ &var_transition_map_cell, &miss);
+ Bind(&if_transition_handler);
+ Comment("KeyedStoreIC_polymorphic_transition");
+ {
+ Node* handler = var_handler.value();
+
+ Label call_handler(this);
+ Variable var_code_handler(this, MachineRepresentation::kTagged);
+ var_code_handler.Bind(handler);
+ GotoUnless(IsTuple2Map(LoadMap(handler)), &call_handler);
+ {
+ CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
+
+ // Check validity cell.
+ Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
+ Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
+ GotoIf(
+ WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
+ &miss);
+
+ var_code_handler.Bind(
+ LoadObjectField(handler, Tuple2::kValue2Offset));
+ Goto(&call_handler);
+ }
+
+ Bind(&call_handler);
+ {
+ Node* code_handler = var_code_handler.value();
+ CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
+
+ Node* transition_map =
+ LoadWeakCellValue(var_transition_map_cell.value(), &miss);
+ StoreTransitionDescriptor descriptor(isolate());
+ TailCallStub(descriptor, code_handler, p->context, p->receiver,
+ p->name, transition_map, p->value, p->slot, p->vector);
+ }
+ }
+ }
+
+ Bind(&try_megamorphic);
+ {
+ // Check megamorphic case.
+ Comment("KeyedStoreIC_try_megamorphic");
+ GotoUnless(
+ WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &try_polymorphic_name);
+ TailCallStub(
+ CodeFactory::KeyedStoreIC_Megamorphic(isolate(), language_mode),
+ p->context, p->receiver, p->name, p->value, p->slot, p->vector);
+ }
+
+ Bind(&try_polymorphic_name);
+ {
+ // 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);
+ // If the name comparison succeeded, we know we have a FixedArray with
+ // at least one map/handler pair.
+ Node* offset = ElementOffsetFromIndex(
+ p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
+ FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
+ Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
+ HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
+ &miss, 1);
+ }
+ }
+ Bind(&miss);
+ {
+ Comment("KeyedStoreIC_miss");
+ TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
+ p->vector, p->receiver, p->name);
+ }
+}
+
+//////////////////// Public methods.
+
+void AccessorAssemblerImpl::GenerateLoadIC() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ LoadIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateLoadICTrampoline() {
+ typedef LoadDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* context = Parameter(Descriptor::kContext);
+ Node* vector = LoadTypeFeedbackVectorForStub();
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ LoadIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateLoadICProtoArray(
+ bool throw_reference_error_if_nonexistent) {
+ typedef LoadICProtoArrayStub::Descriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* handler = Parameter(Descriptor::kHandler);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
+}
+
+void AccessorAssemblerImpl::GenerateLoadField() {
+ typedef LoadFieldStub::Descriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = nullptr;
+ Node* slot = nullptr;
+ Node* vector = nullptr;
+ Node* context = Parameter(Descriptor::kContext);
+ LoadICParameters p(context, receiver, name, slot, vector);
+
+ HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
+ nullptr, kOnlyProperties);
+}
+
+void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
+ typedef LoadGlobalWithVectorDescriptor Descriptor;
+
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, nullptr, name, slot, vector);
+ LoadGlobalIC(&p, typeof_mode);
+}
+
+void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline(
+ TypeofMode typeof_mode) {
+ typedef LoadGlobalDescriptor Descriptor;
+
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* context = Parameter(Descriptor::kContext);
+ Node* vector = LoadTypeFeedbackVectorForStub();
+
+ LoadICParameters p(context, nullptr, name, slot, vector);
+ LoadGlobalIC(&p, typeof_mode);
+}
+
+void AccessorAssemblerImpl::GenerateKeyedLoadICTF() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ KeyedLoadIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() {
+ typedef LoadDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* context = Parameter(Descriptor::kContext);
+ Node* vector = LoadTypeFeedbackVectorForStub();
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ KeyedLoadIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ KeyedLoadICGeneric(&p);
+}
+
+void AccessorAssemblerImpl::GenerateStoreIC() {
+ typedef StoreWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ StoreIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateStoreICTrampoline() {
+ typedef StoreDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* context = Parameter(Descriptor::kContext);
+ Node* vector = LoadTypeFeedbackVectorForStub();
+
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ StoreIC(&p);
+}
+
+void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) {
+ typedef StoreWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ KeyedStoreIC(&p, language_mode);
+}
+
+void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF(
+ LanguageMode language_mode) {
+ typedef StoreDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* context = Parameter(Descriptor::kContext);
+ Node* vector = LoadTypeFeedbackVectorForStub();
+
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ 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
new file mode 100644
index 0000000000..3b75c2e54d
--- /dev/null
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -0,0 +1,45 @@
+// 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_H_
+#define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
+
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+namespace compiler {
+class CodeAssemblerState;
+}
+
+class AccessorAssembler {
+ 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);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc
index 6145d43641..3f2d0e42de 100644
--- a/deps/v8/src/ic/arm/handler-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc
@@ -135,14 +135,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ add(sp, sp, Operand(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -189,18 +181,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ ldr(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -355,58 +335,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ mov(this->name(), Operand(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ ldr(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ tst(scratch, Operand(Map::Deprecated::kMask));
- __ b(ne, miss);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ ldr(scratch,
- FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ cmp(value_reg, scratch);
- __ b(ne, miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ b(ne, miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -538,13 +466,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ Move(r0, value);
- __ Ret();
-}
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc
index babf497a5b..fad0737a1c 100644
--- a/deps/v8/src/ic/arm/ic-arm.cc
+++ b/deps/v8/src/ic/arm/ic-arm.cc
@@ -19,183 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as elements or name clobbering
-// one of these in the case of not jumping to the miss label.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal
- // property.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
- __ b(ne, miss);
-
- // Get the value at the masked, scaled index and return.
- __ ldr(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- (PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY))
- << kSmiTagSize;
- __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
- __ b(ne, miss);
-
- // Store the value at the masked, scaled index and return.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
- __ str(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ mov(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = r0;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), r0, r3, r4);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return r3; }
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r4, r5, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, r4, r5);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
- __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r4, r5, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, r4, r5);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Perform tail call to the entry.
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -219,314 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = r4;
- Register address = r5;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, address));
-
- if (check_map == kCheckMap) {
- __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- __ b(ne, fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ ldr(scratch, MemOperand::PointerAddressFromSmiKey(address, key, PreIndex));
- __ cmp(scratch, Operand(masm->isolate()->factory()->the_hole_value()));
- __ b(ne, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(scratch, key, Operand(Smi::FromInt(1)));
- __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ str(value, MemOperand::PointerAddressFromSmiKey(address, key));
- __ Ret();
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(scratch, key, Operand(Smi::FromInt(1)));
- __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ add(address, address, Operand::PointerOffsetFromSmiKey(key));
- __ str(value, MemOperand(address));
- // Update write barrier for the elements array address.
- __ mov(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kLRHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret();
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ b(ne, slow);
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- __ add(address, elements,
- Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32)) -
- kHeapObjectTag));
- __ ldr(scratch, MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex));
- __ cmp(scratch, Operand(kHoleNanUpper32));
- __ b(ne, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, d0,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(scratch, key, Operand(Smi::FromInt(1)));
- __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret();
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- __ b(ne, &non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(receiver.is(r1));
- DCHECK(key.is(r2));
- DCHECK(value.is(r0));
- Register receiver_map = r3;
- Register elements_map = r6;
- Register elements = r9; // Elements array of the receiver.
- // r4 and r5 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
- __ b(ne, &slow);
- // Check if the object is a JS array or not.
- __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ cmp(r4, Operand(JS_ARRAY_TYPE));
- __ b(eq, &array);
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ cmp(r4, Operand(JS_OBJECT_TYPE));
- __ b(lo, &slow);
-
- // Object case: Check key against length in the elements array.
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ cmp(key, Operand(ip));
- __ b(lo, &fast_object);
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // r0: value.
- // r1: key.
- // r2: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ ldr(r4, FieldMemOperand(key, HeapObject::kMapOffset));
- __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(r4, &slow);
-
- // We use register r8, because otherwise probing the megamorphic stub cache
- // would require pushing temporaries on the stack.
- // TODO(mvstanton): quit using register r8 when
- // FLAG_enable_embedded_constant_pool is turned on.
- DCHECK(!FLAG_enable_embedded_constant_pool);
- Register temporary2 = r8;
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
-
- DCHECK(!AreAliased(vector, slot, r5, temporary2, r6, r9));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ mov(slot, Operand(Smi::FromInt(slot_index)));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r5,
- temporary2, r6, r9);
- // Cache miss.
- __ b(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- __ b(ne, &slow); // Only support writing to writing to array[array.length].
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ cmp(key, Operand(ip));
- __ b(hs, &slow);
- __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ cmp(elements_map, Operand(masm->isolate()->factory()->fixed_array_map()));
- __ b(ne, &check_if_double_array);
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_double_array_map()));
- __ b(ne, &slow);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ cmp(key, Operand(ip));
- __ b(hs, &extra);
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = r5;
- DCHECK(receiver.is(r1));
- DCHECK(name.is(r2));
- DCHECK(value.is(r0));
- DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r3));
- DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r4));
-
- __ ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, r6, r9);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, r6, r9);
- __ Ret();
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, r6, r9);
- GenerateMiss(masm);
-}
-
-
#undef __
diff --git a/deps/v8/src/ic/arm/ic-compiler-arm.cc b/deps/v8/src/ic/arm/ic-compiler-arm.cc
deleted file mode 100644
index 318523199a..0000000000
--- a/deps/v8/src/ic/arm/ic-compiler-arm.cc
+++ /dev/null
@@ -1,33 +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.
-
-#if V8_TARGET_ARCH_ARM
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister());
-
- __ mov(r0, Operand(Smi::FromInt(language_mode)));
- __ Push(r0);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_ARM
diff --git a/deps/v8/src/ic/arm/stub-cache-arm.cc b/deps/v8/src/ic/arm/stub-cache-arm.cc
deleted file mode 100644
index b0f93e32dc..0000000000
--- a/deps/v8/src/ic/arm/stub-cache-arm.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_ARM
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register offset_scratch) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
- uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
- uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
-
- // Check the relative positions of the address fields.
- DCHECK(value_off_addr > key_off_addr);
- DCHECK((value_off_addr - key_off_addr) % 4 == 0);
- DCHECK((value_off_addr - key_off_addr) < (256 * 4));
- DCHECK(map_off_addr > key_off_addr);
- DCHECK((map_off_addr - key_off_addr) % 4 == 0);
- DCHECK((map_off_addr - key_off_addr) < (256 * 4));
-
- Label miss;
- Register base_addr = scratch;
- scratch = no_reg;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ add(offset_scratch, offset, Operand(offset, LSL, 1));
-
- // Calculate the base address of the entry.
- __ add(base_addr, offset_scratch, Operand(key_offset));
-
- // Check that the key in the entry matches the name.
- __ ldr(ip, MemOperand(base_addr, 0));
- __ cmp(name, ip);
- __ b(ne, &miss);
-
- // Check the map matches.
- __ ldr(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
- __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ cmp(ip, scratch2);
- __ b(ne, &miss);
-
- // Get the code entry from the cache.
- Register code = scratch2;
- scratch2 = no_reg;
- __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Miss: fall through.
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 12.
- DCHECK(sizeof(Entry) == 12);
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Check scratch, extra and extra2 registers are valid.
- DCHECK(!scratch.is(no_reg));
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
- __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ add(scratch, scratch, Operand(ip));
- __ eor(scratch, scratch, Operand(kPrimaryMagic));
- __ mov(ip, Operand(kPrimaryTableSize - 1));
- __ and_(scratch, scratch, Operand(ip, LSL, kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary probe.
- __ sub(scratch, scratch, Operand(name));
- __ add(scratch, scratch, Operand(kSecondaryMagic));
- __ mov(ip, Operand(kSecondaryTableSize - 1));
- __ and_(scratch, scratch, Operand(ip, LSL, kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_ARM
diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
index 58d0bb7446..8c89908f4e 100644
--- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
@@ -44,14 +44,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ Drop(2);
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -91,18 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ Ldr(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -386,57 +366,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ Mov(this->name(), Operand(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ Ldr(scratch,
- FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ Cmp(value_reg, scratch);
- __ B(ne, miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ B(ne, miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -572,13 +501,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ LoadObject(x0, value);
- __ Ret();
-}
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc
index 0ced207d8a..04fdff76e1 100644
--- a/deps/v8/src/ic/arm64/ic-arm64.cc
+++ b/deps/v8/src/ic/arm64/ic-arm64.cc
@@ -15,164 +15,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done.
-// The scratch registers need to be different from elements, name and result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- DCHECK(!AreAliased(elements, name, scratch1, scratch2));
- DCHECK(!AreAliased(result, scratch1, scratch2));
-
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal property.
- __ Bind(&done);
-
- static const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask));
- __ B(ne, miss);
-
- // Get the value at the masked, scaled index and return.
- __ Ldr(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store (never clobbered).
-//
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- DCHECK(!AreAliased(elements, name, value, scratch1, scratch2));
-
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ Bind(&done);
-
- static const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- static const int kTypeAndReadOnlyMask =
- PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY);
- __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
- __ Tst(scratch1, kTypeAndReadOnlyMask);
- __ B(ne, miss);
-
- // Store the value at the masked, scaled index and return.
- static const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag);
- __ Str(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ Mov(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = x0;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
- Label slow;
-
- __ Ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), x0, x3, x4);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ Bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
- ASM_LOCATION("LoadIC::GenerateMiss");
-
- DCHECK(!AreAliased(x4, x5, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, x4, x5);
-
- // Perform tail call to the entry.
- __ Push(LoadWithVectorDescriptor::ReceiverRegister(),
- LoadWithVectorDescriptor::NameRegister(),
- LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister());
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(x10, x11, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, x10, x11);
-
- __ Push(LoadWithVectorDescriptor::ReceiverRegister(),
- LoadWithVectorDescriptor::NameRegister(),
- LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister());
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -197,298 +39,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- x10, x11));
-
- Label transition_smi_elements;
- Label transition_double_elements;
- Label fast_double_without_map_check;
- Label non_double_value;
- Label finish_store;
-
- __ Bind(fast_object);
- if (check_map == kCheckMap) {
- __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- __ B(ne, fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because there
- // may be a callback on the element.
- Label holecheck_passed;
- __ Add(x10, elements, FixedArray::kHeaderSize - kHeapObjectTag);
- __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
- __ Ldr(x11, MemOperand(x10));
- __ JumpIfNotRoot(x11, Heap::kTheHoleValueRootIndex, &holecheck_passed);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow);
- __ bind(&holecheck_passed);
-
- // Smi stores don't require further checks.
- __ JumpIfSmi(value, &finish_store);
-
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, x10, &transition_smi_elements);
-
- __ Bind(&finish_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Add(x10, key, Smi::FromInt(1));
- __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
-
- Register address = x11;
- __ Add(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
- __ Add(address, address, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
- __ Str(value, MemOperand(address));
-
- Label dont_record_write;
- __ JumpIfSmi(value, &dont_record_write);
-
- // Update write barrier for the elements array address.
- __ Mov(x10, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, x10, kLRHasNotBeenSaved, kDontSaveFPRegs,
- EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
-
- __ Bind(&dont_record_write);
- __ Ret();
-
-
- __ Bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ JumpIfNotRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex, slow);
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so go to
- // the runtime.
- __ Add(x10, elements, FixedDoubleArray::kHeaderSize - kHeapObjectTag);
- __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
- __ Ldr(x11, MemOperand(x10));
- __ CompareAndBranch(x11, kHoleNanInt64, ne, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow);
-
- __ Bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, x10, d0,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Add(x10, key, Smi::FromInt(1));
- __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret();
-
-
- __ Bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset));
- __ JumpIfNotRoot(x10, Heap::kHeapNumberMapRootIndex, &non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, x10, x11, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ B(&fast_double_without_map_check);
-
- __ Bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, x10, x11, slow);
-
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
-
- __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ B(&finish_store);
-
- __ Bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, x10, x11, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ B(&finish_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- ASM_LOCATION("KeyedStoreIC::GenerateMegamorphic");
- Label slow;
- Label array;
- Label fast_object;
- Label extra;
- Label fast_object_grow;
- Label fast_double_grow;
- Label fast_double;
- Label maybe_name_key;
- Label miss;
-
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(receiver.is(x1));
- DCHECK(key.is(x2));
- DCHECK(value.is(x0));
-
- Register receiver_map = x3;
- Register elements = x4;
- Register elements_map = x5;
-
- __ JumpIfNotSmi(key, &maybe_name_key);
- __ JumpIfSmi(receiver, &slow);
- __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
-
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ Ldrb(x10, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ TestAndBranchIfAnySet(x10, (1 << Map::kIsAccessCheckNeeded), &slow);
-
- // Check if the object is a JS array or not.
- Register instance_type = x10;
- __ CompareInstanceType(receiver_map, instance_type, JS_ARRAY_TYPE);
- __ B(eq, &array);
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ Cmp(instance_type, JS_OBJECT_TYPE);
- __ B(lo, &slow);
-
- // Object case: Check key against length in the elements array.
- __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Cmp(x10, Operand::UntagSmi(key));
- __ B(hi, &fast_object);
-
-
- __ Bind(&slow);
- // Slow case, handle jump to runtime.
- // Live values:
- // x0: value
- // x1: key
- // x2: receiver
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ Ldr(x10, FieldMemOperand(key, HeapObject::kMapOffset));
- __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(x10, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, x5, x6, x7, x8));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ Mov(slot, Operand(Smi::FromInt(slot_index)));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, x5,
- x6, x7, x8);
- // Cache miss.
- __ B(&miss);
-
- __ Bind(&extra);
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
-
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Cmp(x10, Operand::UntagSmi(key));
- __ B(ls, &slow);
-
- __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Cmp(elements_map, Operand(masm->isolate()->factory()->fixed_array_map()));
- __ B(eq, &fast_object_grow);
- __ Cmp(elements_map,
- Operand(masm->isolate()->factory()->fixed_double_array_map()));
- __ B(eq, &fast_double_grow);
- __ B(&slow);
-
-
- __ Bind(&array);
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
-
- __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ Ldrsw(x10, UntagSmiFieldMemOperand(receiver, JSArray::kLengthOffset));
- __ Cmp(x10, Operand::UntagSmi(key));
- __ B(eq, &extra); // We can handle the case where we are appending 1 element.
- __ B(lo, &slow);
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register value = StoreDescriptor::ValueRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register dictionary = x5;
- DCHECK(!AreAliased(value, receiver, name,
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(), x5, x6, x7));
-
- __ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, x6, x7);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, x6, x7);
- __ Ret();
-
- // Cache miss: Jump to runtime.
- __ Bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, x6, x7);
- GenerateMiss(masm);
-}
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
diff --git a/deps/v8/src/ic/arm64/ic-compiler-arm64.cc b/deps/v8/src/ic/arm64/ic-compiler-arm64.cc
deleted file mode 100644
index c99c637ab1..0000000000
--- a/deps/v8/src/ic/arm64/ic-compiler-arm64.cc
+++ /dev/null
@@ -1,33 +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.
-
-#if V8_TARGET_ARCH_ARM64
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- ASM_LOCATION("PropertyICCompiler::GenerateRuntimeSetProperty");
-
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister());
-
- __ Mov(x10, Smi::FromInt(language_mode));
- __ Push(x10);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_ARM64
diff --git a/deps/v8/src/ic/arm64/stub-cache-arm64.cc b/deps/v8/src/ic/arm64/stub-cache-arm64.cc
deleted file mode 100644
index 81c820725a..0000000000
--- a/deps/v8/src/ic/arm64/stub-cache-arm64.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2013 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.
-
-#if V8_TARGET_ARCH_ARM64
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-
-#define __ ACCESS_MASM(masm)
-
-
-// Probe primary or secondary table.
-// If the entry is found in the cache, the generated code jump to the first
-// instruction of the stub in the cache.
-// If there is a miss the code fall trough.
-//
-// 'receiver', 'name' and 'offset' registers are preserved on miss.
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register scratch3) {
- // Some code below relies on the fact that the Entry struct contains
- // 3 pointers (name, code, map).
- STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
-
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
- uintptr_t value_off_addr =
- reinterpret_cast<uintptr_t>(value_offset.address());
- uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address());
-
- Label miss;
-
- DCHECK(!AreAliased(name, offset, scratch, scratch2, scratch3));
-
- // Multiply by 3 because there are 3 fields per entry.
- __ Add(scratch3, offset, Operand(offset, LSL, 1));
-
- // Calculate the base address of the entry.
- __ Mov(scratch, key_offset);
- __ Add(
- scratch, scratch,
- Operand(scratch3, LSL, kPointerSizeLog2 - StubCache::kCacheIndexShift));
-
- // Check that the key in the entry matches the name.
- __ Ldr(scratch2, MemOperand(scratch));
- __ Cmp(name, scratch2);
- __ B(ne, &miss);
-
- // Check the map matches.
- __ Ldr(scratch2, MemOperand(scratch, map_off_addr - key_off_addr));
- __ Ldr(scratch3, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Cmp(scratch2, scratch3);
- __ B(ne, &miss);
-
- // Get the code entry from the cache.
- __ Ldr(scratch, MemOperand(scratch, value_off_addr - key_off_addr));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ B(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ B(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
- __ Br(scratch);
-
- // Miss: fall through.
- __ Bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Make sure extra and extra2 registers are valid.
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Compute the hash for primary table.
- __ Ldr(scratch.W(), FieldMemOperand(name, Name::kHashFieldOffset));
- __ Ldr(extra, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Add(scratch, scratch, extra);
- __ Eor(scratch, scratch, kPrimaryMagic);
- __ And(scratch, scratch,
- Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary table.
- __ Sub(scratch, scratch, Operand(name));
- __ Add(scratch, scratch, Operand(kSecondaryMagic));
- __ And(scratch, scratch,
- Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ Bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_ARM64
diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc
index 05e9031915..16aec0b494 100644
--- a/deps/v8/src/ic/handler-compiler.cc
+++ b/deps/v8/src/ic/handler-compiler.cc
@@ -24,60 +24,6 @@ Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
return handle(code);
}
-
-Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
- Handle<Name> name, Handle<Map> receiver_map) {
- Isolate* isolate = name->GetIsolate();
- if (receiver_map->prototype()->IsNull(isolate)) {
- // TODO(jkummerow/verwaest): If there is no prototype and the property
- // is nonexistent, introduce a builtin to handle this (fast properties
- // -> return undefined, dictionary properties -> do negative lookup).
- return Handle<Code>();
- }
- CacheHolderFlag flag;
- Handle<Map> stub_holder_map =
- IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
-
- // If no dictionary mode objects are present in the prototype chain, the load
- // nonexistent IC stub can be shared for all names for a given map and we use
- // the empty string for the map cache in that case. If there are dictionary
- // mode objects involved, we need to do negative lookups in the stub and
- // therefore the stub will be specific to the name.
- Handle<Name> cache_name =
- receiver_map->is_dictionary_map()
- ? name
- : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
- Handle<Map> current_map = stub_holder_map;
- Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
- while (true) {
- if (current_map->is_dictionary_map()) cache_name = name;
- if (current_map->prototype()->IsNull(isolate)) break;
- if (name->IsPrivate()) {
- // TODO(verwaest): Use nonexistent_private_symbol.
- cache_name = name;
- if (!current_map->has_hidden_prototype()) break;
- }
-
- last = handle(JSObject::cast(current_map->prototype()));
- current_map = handle(last->map());
- }
- // Compile the stub that is either shared for all names or
- // name specific if there are global objects involved.
- Handle<Code> handler = PropertyHandlerCompiler::Find(
- cache_name, stub_holder_map, Code::LOAD_IC, flag);
- if (!handler.is_null()) {
- TRACE_HANDLER_STATS(isolate, LoadIC_HandlerCacheHit_NonExistent);
- return handler;
- }
-
- TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
- NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
- handler = compiler.CompileLoadNonexistent(cache_name);
- Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
- return handler;
-}
-
-
Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
Handle<Name> name) {
Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
@@ -149,87 +95,6 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
return reg;
}
-
-void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
- Label* miss,
- Register scratch1,
- Register scratch2) {
- Register holder_reg;
- Handle<Map> last_map;
- if (holder().is_null()) {
- holder_reg = receiver();
- last_map = map();
- // If |type| has null as its prototype, |holder()| is
- // Handle<JSObject>::null().
- DCHECK(last_map->prototype() == isolate()->heap()->null_value());
- } else {
- last_map = handle(holder()->map());
- // This condition matches the branches below.
- bool need_holder =
- last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
- holder_reg =
- FrontendHeader(receiver(), name, miss,
- need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
- }
-
- if (last_map->is_dictionary_map()) {
- if (last_map->IsJSGlobalObjectMap()) {
- Handle<JSGlobalObject> global =
- holder().is_null()
- ? Handle<JSGlobalObject>::cast(isolate()->global_object())
- : Handle<JSGlobalObject>::cast(holder());
- GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
- } else {
- if (!name->IsUniqueName()) {
- DCHECK(name->IsString());
- name = factory()->InternalizeString(Handle<String>::cast(name));
- }
- DCHECK(holder().is_null() ||
- holder()->property_dictionary()->FindEntry(name) ==
- NameDictionary::kNotFound);
- GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
- scratch2);
- }
- }
-}
-
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
- FieldIndex field) {
- Register reg = Frontend(name);
- __ Move(receiver(), reg);
- LoadFieldStub stub(isolate(), field);
- GenerateTailCall(masm(), stub.GetCode());
- return GetCode(kind(), name);
-}
-
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
- int constant_index) {
- Register reg = Frontend(name);
- __ Move(receiver(), reg);
- LoadConstantStub stub(isolate(), constant_index);
- GenerateTailCall(masm(), stub.GetCode());
- return GetCode(kind(), name);
-}
-
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
- Handle<Name> name) {
- Label miss;
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PushVectorAndSlot();
- }
- NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- DiscardVectorAndSlot();
- }
- GenerateLoadConstant(isolate()->factory()->undefined_value());
- FrontendFooter(name, &miss);
- return GetCode(kind(), name);
-}
-
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) {
if (V8_UNLIKELY(FLAG_runtime_stats)) {
@@ -298,10 +163,13 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
case LookupIterator::NOT_FOUND:
case LookupIterator::INTEGER_INDEXED_EXOTIC:
break;
- case LookupIterator::DATA:
- inline_followup =
- it->property_details().type() == DATA && !it->is_dictionary_holder();
+ case LookupIterator::DATA: {
+ PropertyDetails details = it->property_details();
+ inline_followup = details.kind() == kData &&
+ details.location() == kField &&
+ !it->is_dictionary_holder();
break;
+ }
case LookupIterator::ACCESSOR: {
Handle<Object> accessors = it->GetAccessors();
if (accessors->IsAccessorInfo()) {
@@ -409,9 +277,13 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::DATA: {
- DCHECK_EQ(DATA, it->property_details().type());
- __ Move(receiver(), reg);
- LoadFieldStub stub(isolate(), it->GetFieldIndex());
+ DCHECK_EQ(kData, it->property_details().kind());
+ DCHECK_EQ(kField, it->property_details().location());
+ __ Move(LoadFieldDescriptor::ReceiverRegister(), reg);
+ Handle<Object> smi_handler =
+ LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex());
+ __ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler);
+ LoadFieldStub stub(isolate());
GenerateTailCall(masm(), stub.GetCode());
break;
}
@@ -440,150 +312,6 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
return GetCode(kind(), name);
}
-
-// TODO(verwaest): Cleanup. holder() is actually the receiver.
-Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
- Handle<Map> transition, Handle<Name> name) {
- Label miss;
-
- // Ensure that the StoreTransitionStub we are going to call has the same
- // number of stack arguments. This means that we don't have to adapt them
- // if we decide to call the transition or miss stub.
- STATIC_ASSERT(Descriptor::kStackArgumentsCount ==
- StoreTransitionDescriptor::kStackArgumentsCount);
- STATIC_ASSERT(Descriptor::kStackArgumentsCount == 0 ||
- Descriptor::kStackArgumentsCount == 3);
- STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kValue ==
- StoreTransitionDescriptor::kParameterCount -
- StoreTransitionDescriptor::kValue);
- STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kSlot ==
- StoreTransitionDescriptor::kParameterCount -
- StoreTransitionDescriptor::kSlot);
- STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kVector ==
- StoreTransitionDescriptor::kParameterCount -
- StoreTransitionDescriptor::kVector);
-
- if (Descriptor::kPassLastArgsOnStack) {
- __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
- }
-
- bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
- if (need_save_restore) {
- PushVectorAndSlot();
- }
-
- // Check that we are allowed to write this.
- bool is_nonexistent = holder()->map() == transition->GetBackPointer();
- if (is_nonexistent) {
- // Find the top object.
- Handle<JSObject> last;
- PrototypeIterator::WhereToEnd end =
- name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
- : PrototypeIterator::END_AT_NULL;
- PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
- while (!iter.IsAtEnd()) {
- last = PrototypeIterator::GetCurrent<JSObject>(iter);
- iter.Advance();
- }
- if (!last.is_null()) set_holder(last);
- NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
- } else {
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
- DCHECK(holder()->HasFastProperties());
- }
-
- int descriptor = transition->LastAdded();
- Handle<DescriptorArray> descriptors(transition->instance_descriptors());
- PropertyDetails details = descriptors->GetDetails(descriptor);
- Representation representation = details.representation();
- DCHECK(!representation.IsNone());
-
- // Stub is never generated for objects that require access checks.
- DCHECK(!transition->is_access_check_needed());
-
- // Call to respective StoreTransitionStub.
- Register map_reg = StoreTransitionDescriptor::MapRegister();
-
- if (details.type() == DATA_CONSTANT) {
- DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
- GenerateRestoreMap(transition, map_reg, scratch1(), &miss);
- GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss);
- if (need_save_restore) {
- PopVectorAndSlot();
- }
- GenerateRestoreName(name);
- StoreMapStub stub(isolate());
- GenerateTailCall(masm(), stub.GetCode());
-
- } else {
- if (representation.IsHeapObject()) {
- GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
- &miss);
- }
- StoreTransitionStub::StoreMode store_mode =
- Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
- ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
- : StoreTransitionStub::StoreMapAndValue;
- GenerateRestoreMap(transition, map_reg, scratch1(), &miss);
- if (need_save_restore) {
- PopVectorAndSlot();
- }
- // We need to pass name on the stack.
- PopReturnAddress(this->name());
- __ Push(name);
- PushReturnAddress(this->name());
-
- FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
- __ Move(StoreNamedTransitionDescriptor::FieldOffsetRegister(),
- Smi::FromInt(index.index() << kPointerSizeLog2));
-
- StoreTransitionStub stub(isolate(), index.is_inobject(), representation,
- store_mode);
- GenerateTailCall(masm(), stub.GetCode());
- }
-
- __ bind(&miss);
- if (need_save_restore) {
- PopVectorAndSlot();
- }
- GenerateRestoreName(name);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
- return GetCode(kind(), name);
-}
-
-bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
- FieldType* field_type) const {
- return field_type->IsClass();
-}
-
-
-Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
- Label miss;
- DCHECK(it->representation().IsHeapObject());
-
- FieldType* field_type = *it->GetFieldType();
- bool need_save_restore = false;
- if (RequiresFieldTypeChecks(field_type)) {
- need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
- if (Descriptor::kPassLastArgsOnStack) {
- __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
- }
- if (need_save_restore) PushVectorAndSlot();
- GenerateFieldTypeChecks(field_type, value(), &miss);
- if (need_save_restore) PopVectorAndSlot();
- }
-
- StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
- GenerateTailCall(masm(), stub.GetCode());
-
- __ bind(&miss);
- if (need_save_restore) PopVectorAndSlot();
- TailCallBuiltin(masm(), MissBuiltin(kind()));
- return GetCode(kind(), it->name());
-}
-
-
Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Handle<JSObject> object, Handle<Name> name, int accessor_index,
int expected_arguments) {
@@ -640,13 +368,8 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
}
bool is_js_array = instance_type == JS_ARRAY_TYPE;
if (elements_kind == DICTIONARY_ELEMENTS) {
- if (FLAG_tf_load_ic_stub) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
- return LoadHandler::LoadElement(isolate, elements_kind, false,
- is_js_array);
- }
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
- return LoadDictionaryElementStub(isolate).GetCode();
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
+ return LoadHandler::LoadElement(isolate, elements_kind, false, is_js_array);
}
DCHECK(IsFastElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind));
@@ -654,16 +377,9 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
bool convert_hole_to_undefined =
is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
*receiver_map == isolate->get_initial_js_array_map(elements_kind);
- if (FLAG_tf_load_ic_stub) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
- return LoadHandler::LoadElement(isolate, elements_kind,
- convert_hole_to_undefined, is_js_array);
- } else {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
- return LoadFastElementStub(isolate, is_js_array, elements_kind,
- convert_hole_to_undefined)
- .GetCode();
- }
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
+ return LoadHandler::LoadElement(isolate, elements_kind,
+ convert_hole_to_undefined, is_js_array);
}
void ElementHandlerCompiler::CompileElementHandlers(
diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h
index 0dec36af2f..65f6fbbef3 100644
--- a/deps/v8/src/ic/handler-compiler.h
+++ b/deps/v8/src/ic/handler-compiler.h
@@ -40,8 +40,6 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
// Frontend loads from receiver(), returns holder register which may be
// different.
Register Frontend(Handle<Name> name);
- void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
- Register scratch1, Register scratch2);
// When FLAG_vector_ics is true, handlers that have the possibility of missing
// will need to save and pass these to miss handlers.
@@ -52,9 +50,6 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
void DiscardVectorAndSlot();
- void PushReturnAddress(Register tmp);
- void PopReturnAddress(Register tmp);
-
// TODO(verwaest): Make non-static.
static void GenerateApiAccessorCall(MacroAssembler* masm,
const CallOptimization& optimization,
@@ -134,8 +129,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
virtual ~NamedLoadHandlerCompiler() {}
- Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index);
-
Handle<Code> CompileLoadCallback(Handle<Name> name,
Handle<AccessorInfo> callback,
Handle<Code> slow_stub);
@@ -144,8 +137,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
const CallOptimization& call_optimization,
int accessor_index, Handle<Code> slow_stub);
- Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
-
// The LookupIterator is used to perform a lookup behind the interceptor. If
// the iterator points to a LookupIterator::PROPERTY, its access will be
// inlined.
@@ -157,10 +148,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
bool is_configurable);
- // Static interface
- static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
- Handle<Map> map);
-
static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map,
Register receiver, Register holder,
int accessor_index, int expected_arguments,
@@ -193,11 +180,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
virtual void FrontendFooter(Handle<Name> name, Label* miss);
private:
- Handle<Code> CompileLoadNonexistent(Handle<Name> name);
- void GenerateLoadConstant(Handle<Object> value);
void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback);
- void GenerateLoadCallback(const CallOptimization& call_optimization,
- Handle<Map> receiver_map);
// Helper emits no code if vector-ics are disabled.
void InterceptorVectorSlotPush(Register holder_reg);
@@ -209,17 +192,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Register holder_reg);
void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
- // Generates prototype loading code that uses the objects from the
- // context we were in when this function was called. If the context
- // has changed, a jump to miss is performed. This ties the generated
- // code to a particular context and so must not be used in cases
- // where the generated code is not allowed to have references to
- // objects from a context.
- static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
- int index,
- Register prototype,
- Label* miss);
-
Register scratch3() { return registers_[4]; }
};
@@ -244,9 +216,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
void ZapStackArgumentsRegisterAliases();
- Handle<Code> CompileStoreTransition(Handle<Map> transition,
- Handle<Name> name);
- Handle<Code> CompileStoreField(LookupIterator* it);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
Handle<AccessorInfo> callback,
LanguageMode language_mode);
@@ -275,18 +244,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
void GenerateRestoreName(Label* label, Handle<Name> name);
private:
- void GenerateRestoreName(Handle<Name> name);
- void GenerateRestoreMap(Handle<Map> transition, Register map_reg,
- Register scratch, Label* miss);
-
- void GenerateConstantCheck(Register map_reg, int descriptor,
- Register value_reg, Register scratch,
- Label* miss_label);
-
- bool RequiresFieldTypeChecks(FieldType* field_type) const;
- void GenerateFieldTypeChecks(FieldType* field_type, Register value_reg,
- Label* miss_label);
-
static Register value();
};
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index 505d67cf42..8aa887d2b6 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -104,7 +104,8 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int value_index = DescriptorArray::ToValueIndex(descriptor);
DCHECK(kind == kStoreField || kind == kTransitionToField);
- DCHECK_IMPLIES(kind == kStoreField, !extend_storage);
+ DCHECK_IMPLIES(extend_storage, kind == kTransitionToField);
+ DCHECK_IMPLIES(field_index.is_inobject(), !extend_storage);
int config = StoreHandler::KindBits::encode(kind) |
StoreHandler::ExtendStorageBits::encode(extend_storage) |
diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
index 68fd1b9d98..b63e82b70a 100644
--- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
+++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
@@ -83,16 +83,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ add(esp, Immediate(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ push(tmp);
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ pop(tmp);
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -132,18 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadGlobalFunction(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ mov(result,
- FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -359,58 +337,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ mov(this->name(), Immediate(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
- __ and_(scratch, Immediate(Map::Deprecated::kMask));
- __ j(not_zero, miss);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ mov(scratch,
- FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ cmp(value_reg, scratch);
- __ j(not_equal, miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ j(not_equal, miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -540,14 +466,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ LoadObject(eax, value);
- __ ret(0);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/ia32/ic-compiler-ia32.cc b/deps/v8/src/ic/ia32/ic-compiler-ia32.cc
deleted file mode 100644
index a52f04689a..0000000000
--- a/deps/v8/src/ic/ia32/ic-compiler-ia32.cc
+++ /dev/null
@@ -1,45 +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.
-
-#if V8_TARGET_ARCH_IA32
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- typedef StoreWithVectorDescriptor Descriptor;
- STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
- // ----------- S t a t e -------------
- // -- esp[12] : value
- // -- esp[8] : slot
- // -- esp[4] : vector
- // -- esp[0] : return address
- // -----------------------------------
- __ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
- Descriptor::kValue);
-
- __ mov(Operand(esp, 12), Descriptor::ReceiverRegister());
- __ mov(Operand(esp, 8), Descriptor::NameRegister());
- __ mov(Operand(esp, 4), Descriptor::ValueRegister());
- __ pop(ebx);
- __ push(Immediate(Smi::FromInt(language_mode)));
- __ push(ebx); // return address
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_IA32
diff --git a/deps/v8/src/ic/ia32/ic-ia32.cc b/deps/v8/src/ic/ia32/ic-ia32.cc
index 44a5b9f531..4bf0eaee92 100644
--- a/deps/v8/src/ic/ia32/ic-ia32.cc
+++ b/deps/v8/src/ic/ia32/ic-ia32.cc
@@ -18,440 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used to load a property from a dictionary backing
-// storage. This function may fail to load a property even though it is
-// in the dictionary, so code at miss_label must always call a backup
-// property load that is complete. This function is safe to call if
-// name is not internalized, and will jump to the miss_label in that
-// case. The generated code assumes that the receiver has slow
-// properties, is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register r0, Register r1, Register result) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is unchanged.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // Scratch registers:
- //
- // r0 - used for the index into the property dictionary
- //
- // r1 - used to hold the capacity of the property dictionary.
- //
- // result - holds the result on exit.
-
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
- elements, name, r0, r1);
-
- // If probing finds an entry in the dictionary, r0 contains the
- // index into the dictionary. Check that the value is a normal
- // property.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
- __ j(not_zero, miss_label);
-
- // Get the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
-}
-
-
-// Helper function used to store a property to a dictionary backing
-// storage. This function may fail to store a property eventhough it
-// is in the dictionary, so code at miss_label must always call a
-// backup property store that is complete. This function is safe to
-// call if name is not internalized, and will jump to the miss_label in
-// that case. The generated code assumes that the receiver has slow
-// properties, is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register value, Register r0, Register r1) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is clobbered.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // value - holds the value to store and is unchanged.
- //
- // r0 - used for index into the property dictionary and is clobbered.
- //
- // r1 - used to hold the capacity of the property dictionary and is clobbered.
- Label done;
-
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
- elements, name, r0, r1);
-
- // If probing finds an entry in the dictionary, r0 contains the
- // index into the dictionary. Check that the value is a normal
- // property that is not read only.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- (PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY))
- << kSmiTagSize;
- __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(kTypeAndReadOnlyMask));
- __ j(not_zero, miss_label);
-
- // Store the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
- __ mov(Operand(r0, 0), value);
-
- // Update write barrier. Make sure not to clobber the value.
- __ mov(r1, value);
- __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register key = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- DCHECK(receiver.is(edx));
- DCHECK(key.is(ecx));
- DCHECK(value.is(eax));
- // key is a smi.
- // ebx: FixedArray receiver->elements
- // edi: receiver map
- // Fast case: Do the store, could either Object or double.
- __ bind(fast_object);
- if (check_map == kCheckMap) {
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
- __ j(not_equal, fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- __ cmp(FixedArrayElementOperand(ebx, key),
- masm->isolate()->factory()->the_hole_value());
- __ j(not_equal, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ mov(FixedArrayElementOperand(ebx, key), value);
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- __ CheckFastObjectElements(edi, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- __ mov(FixedArrayElementOperand(ebx, key), value);
- // Update write barrier for the elements array address.
- __ mov(edx, value); // Preserve the value which is returned.
- __ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
- __ j(not_equal, slow);
- // If the value is a number, store it as a double in the FastDoubleElements
- // array.
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmp(FieldOperand(ebx, key, times_4, offset), Immediate(kHoleNanUpper32));
- __ j(not_equal, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, ebx, key, edi, xmm0,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&transition_smi_elements);
- __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
-
- // Transition the array appropriately depending on the value type.
- __ CheckMap(value, masm->isolate()->factory()->heap_number_map(),
- &non_double_value, DONT_DO_SMI_CHECK);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
- // and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS, ebx, edi, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, ebx,
- edi, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- ebx, edi, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, receiver, key,
- value, ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- typedef StoreWithVectorDescriptor Descriptor;
- // Return address is on the stack.
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
- Register receiver = Descriptor::ReceiverRegister();
- Register key = Descriptor::NameRegister();
- DCHECK(receiver.is(edx));
- DCHECK(key.is(ecx));
-
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map from the receiver.
- __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &slow);
-
- __ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
- Descriptor::kValue);
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- __ CmpInstanceType(edi, JS_ARRAY_TYPE);
- __ j(equal, &array);
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ CmpInstanceType(edi, JS_OBJECT_TYPE);
- __ j(below, &slow);
-
- // Object case: Check key against length in the elements array.
- // Key is a smi.
- // edi: receiver map
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
- __ j(below, &fast_object);
-
- // Slow case: call runtime.
- __ bind(&slow);
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ mov(ebx, FieldOperand(key, HeapObject::kMapOffset));
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(ebx, &slow);
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
- no_reg);
-
- // Cache miss.
- __ jmp(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // receiver is a JSArray.
- // key is a smi.
- // ebx: receiver->elements, a FixedArray
- // edi: receiver map
- // flags: compare (key, receiver.length())
- // do not leave holes in the array:
- __ j(not_equal, &slow);
- __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
- __ j(above_equal, &slow);
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
- __ j(not_equal, &check_if_double_array);
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
- __ j(not_equal, &slow);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- // receiver is a JSArray.
- // key is a smi.
- // edi: receiver map
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array and fall through to the
- // common store code.
- __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset)); // Compare smis.
- __ j(above_equal, &extra);
-
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
- kCheckMap, kDontIncrementLength);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = eax;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), edi, ebx, eax);
- __ ret(0);
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
-
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
- DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) &&
- !edi.is(vector));
-
- __ pop(edi);
- __ push(receiver);
- __ push(name);
- __ push(slot);
- __ push(vector);
- __ push(edi);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- __ IncrementCounter(masm->isolate()->counters()->ic_load_miss(), 1);
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // Return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(!ebx.is(receiver) && !ebx.is(name));
-
- __ pop(ebx);
- __ push(receiver);
- __ push(name);
- __ push(ebx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- __ IncrementCounter(masm->isolate()->counters()->ic_keyed_load_miss(), 1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // Return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(!ebx.is(receiver) && !ebx.is(name));
-
- __ pop(ebx);
- __ push(receiver);
- __ push(name);
- __ push(ebx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@@ -470,50 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ push(return_address);
}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- typedef StoreWithVectorDescriptor Descriptor;
- Label restore_miss;
- Register receiver = Descriptor::ReceiverRegister();
- Register name = Descriptor::NameRegister();
- Register value = Descriptor::ValueRegister();
- // Since the slot and vector values are passed on the stack we can use
- // respective registers as scratch registers.
- Register scratch1 = Descriptor::VectorRegister();
- Register scratch2 = Descriptor::SlotRegister();
-
- __ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
-
- // A lot of registers are needed for storing to slow case objects.
- // Push and restore receiver but rely on GenerateDictionaryStore preserving
- // the value and name.
- __ push(receiver);
-
- Register dictionary = receiver;
- __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
- GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
- scratch1, scratch2);
- __ Drop(1);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1);
- __ ret(Descriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&restore_miss);
- __ pop(receiver);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1);
- GenerateMiss(masm);
-}
-
-
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
diff --git a/deps/v8/src/ic/ia32/stub-cache-ia32.cc b/deps/v8/src/ic/ia32/stub-cache-ia32.cc
deleted file mode 100644
index 82700d34a7..0000000000
--- a/deps/v8/src/ic/ia32/stub-cache-ia32.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_IA32
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register name, Register receiver,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register extra) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- Label miss;
- Code::Kind ic_kind = stub_cache->ic_kind();
- bool is_vector_store =
- IC::ICUseVector(ic_kind) &&
- (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ lea(offset, Operand(offset, offset, times_2, 0));
-
- if (extra.is_valid()) {
- // Get the code entry from the cache.
- __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
-
- // Check that the key in the entry matches the name.
- __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
- __ j(not_equal, &miss);
-
- // Check the map matches.
- __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
- __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ j(not_equal, &miss);
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- if (is_vector_store) {
- // The value, vector and slot were passed to the IC on the stack and
- // they are still there. So we can just jump to the handler.
- DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
- __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(extra);
- } else {
- // The vector and slot were pushed onto the stack before starting the
- // probe, and need to be dropped before calling the handler.
- __ pop(LoadWithVectorDescriptor::VectorRegister());
- __ pop(LoadDescriptor::SlotRegister());
- __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(extra);
- }
-
- __ bind(&miss);
- } else {
- DCHECK(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
-
- // Save the offset on the stack.
- __ push(offset);
-
- // Check that the key in the entry matches the name.
- __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
- __ j(not_equal, &miss);
-
- // Check the map matches.
- __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
- __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ j(not_equal, &miss);
-
- // Restore offset register.
- __ mov(offset, Operand(esp, 0));
-
- // Get the code entry from the cache.
- __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Restore offset and re-load code entry from cache.
- __ pop(offset);
- __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
-
- // Jump to the first instruction in the code stub.
- if (is_vector_store) {
- DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
- }
- __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(offset);
-
- // Pop at miss.
- __ bind(&miss);
- __ pop(offset);
- }
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Assert that code is valid. The multiplying code relies on the entry size
- // being 12.
- DCHECK(sizeof(Entry) == 12);
-
- // Assert that there are no register conflicts.
- DCHECK(!scratch.is(receiver));
- DCHECK(!scratch.is(name));
- DCHECK(!extra.is(receiver));
- DCHECK(!extra.is(name));
- DCHECK(!extra.is(scratch));
-
- // Assert scratch and extra registers are valid, and extra2/3 are unused.
- DCHECK(!scratch.is(no_reg));
- DCHECK(extra2.is(no_reg));
- DCHECK(extra3.is(no_reg));
-
- Register offset = scratch;
- scratch = no_reg;
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
- __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, kPrimaryMagic);
- // We mask out the last two bits because they are not part of the hash and
- // they are always 01 for maps. Also in the two 'and' instructions below.
- __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
- // ProbeTable expects the offset to be pointer scaled, which it is, because
- // the heap object tag size is 2 and the pointer size log 2 is also 2.
- DCHECK(kCacheIndexShift == kPointerSizeLog2);
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, name, receiver, offset, extra);
-
- // Primary miss: Compute hash for secondary probe.
- __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
- __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, kPrimaryMagic);
- __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
- __ sub(offset, name);
- __ add(offset, Immediate(kSecondaryMagic));
- __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, name, receiver, offset, extra);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_IA32
diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc
index 750c88daa9..fcda0c1fa3 100644
--- a/deps/v8/src/ic/ic-compiler.cc
+++ b/deps/v8/src/ic/ic-compiler.cc
@@ -10,7 +10,7 @@
namespace v8 {
namespace internal {
-Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
+Handle<Object> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
Isolate* isolate = receiver_map->GetIsolate();
@@ -20,14 +20,14 @@ Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
PropertyICCompiler compiler(isolate);
- Handle<Code> code =
+ Handle<Object> handler =
compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
- return code;
+ return handler;
}
void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
+ 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 ||
@@ -38,13 +38,12 @@ void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
receiver_maps, transitioned_maps, handlers, store_mode);
}
-
void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
+ 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<Code> cached_stub;
+ Handle<Object> handler;
Handle<Map> transitioned_map;
{
Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
@@ -61,21 +60,29 @@ void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
ElementsKind elements_kind = receiver_map->elements_kind();
TRACE_HANDLER_STATS(isolate(),
KeyedStoreIC_ElementsTransitionAndStoreStub);
- cached_stub =
+ Handle<Code> stub =
ElementsTransitionAndStoreStub(isolate(), elements_kind,
transitioned_map->elements_kind(),
- is_js_array, store_mode).GetCode();
+ 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);
- cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
+ handler = isolate()->builtins()->KeyedStoreIC_Slow();
} else {
- cached_stub =
- CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
+ handler = CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
}
- DCHECK(!cached_stub.is_null());
- handlers->Add(cached_stub);
+ DCHECK(!handler.is_null());
+ handlers->Add(handler);
transitioned_maps->Add(transitioned_map);
}
}
@@ -83,8 +90,7 @@ void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
#define __ ACCESS_MASM(masm())
-
-Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
+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;
@@ -101,7 +107,12 @@ Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
}
- return stub;
+ Handle<Object> validity_cell =
+ Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
+ if (validity_cell.is_null()) {
+ return stub;
+ }
+ return isolate()->factory()->NewTuple2(validity_cell, stub);
}
diff --git a/deps/v8/src/ic/ic-compiler.h b/deps/v8/src/ic/ic-compiler.h
index fa3ba15af2..b8d6635ae0 100644
--- a/deps/v8/src/ic/ic-compiler.h
+++ b/deps/v8/src/ic/ic-compiler.h
@@ -14,29 +14,22 @@ namespace internal {
class PropertyICCompiler : public PropertyAccessCompiler {
public:
// Keyed
- static Handle<Code> ComputeKeyedStoreMonomorphicHandler(
+ static Handle<Object> ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
static void ComputeKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- CodeHandleList* handlers, KeyedAccessStoreMode store_mode);
-
- // Helpers
- // TODO(verwaest): Move all uses of these helpers to the PropertyICCompiler
- // and make the helpers private.
- static void GenerateRuntimeSetProperty(MacroAssembler* masm,
- LanguageMode language_mode);
-
+ List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode);
private:
explicit PropertyICCompiler(Isolate* isolate)
: PropertyAccessCompiler(isolate, Code::KEYED_STORE_IC,
kCacheOnReceiver) {}
- Handle<Code> CompileKeyedStoreMonomorphicHandler(
+ Handle<Object> CompileKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
void CompileKeyedStorePolymorphicHandlers(MapHandleList* receiver_maps,
MapHandleList* transitioned_maps,
- CodeHandleList* handlers,
+ List<Handle<Object>>* handlers,
KeyedAccessStoreMode store_mode);
};
diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h
index 1b5d063270..b286315c01 100644
--- a/deps/v8/src/ic/ic-inl.h
+++ b/deps/v8/src/ic/ic-inl.h
@@ -93,8 +93,8 @@ Code* IC::target() const {
}
bool IC::IsHandler(Object* object) {
- return (object->IsSmi() && (object != nullptr)) || object->IsTuple3() ||
- object->IsFixedArray() ||
+ return (object->IsSmi() && (object != nullptr)) || object->IsTuple2() ||
+ object->IsTuple3() || object->IsFixedArray() ||
(object->IsCode() && Code::cast(object)->is_handler());
}
diff --git a/deps/v8/src/ic/ic-state.cc b/deps/v8/src/ic/ic-state.cc
index f94803681b..7439ecd2c0 100644
--- a/deps/v8/src/ic/ic-state.cc
+++ b/deps/v8/src/ic/ic-state.cc
@@ -61,6 +61,23 @@ ExtraICState BinaryOpICState::GetExtraICState() const {
return extra_ic_state;
}
+std::string BinaryOpICState::ToString() const {
+ std::string ret = "(";
+ ret += Token::Name(op_);
+ if (CouldCreateAllocationMementos()) ret += "_CreateAllocationMementos";
+ ret += ":";
+ ret += BinaryOpICState::KindToString(left_kind_);
+ ret += "*";
+ if (fixed_right_arg_.IsJust()) {
+ ret += fixed_right_arg_.FromJust();
+ } else {
+ ret += BinaryOpICState::KindToString(right_kind_);
+ }
+ ret += "->";
+ ret += BinaryOpICState::KindToString(result_kind_);
+ ret += ")";
+ return ret;
+}
// static
void BinaryOpICState::GenerateAheadOfTime(
diff --git a/deps/v8/src/ic/ic-state.h b/deps/v8/src/ic/ic-state.h
index 1ba37b99db..836979c4f0 100644
--- a/deps/v8/src/ic/ic-state.h
+++ b/deps/v8/src/ic/ic-state.h
@@ -82,6 +82,7 @@ class BinaryOpICState final BASE_EMBEDDED {
}
ExtraICState GetExtraICState() const;
+ std::string ToString() const;
static void GenerateAheadOfTime(Isolate*,
void (*Generate)(Isolate*,
@@ -234,6 +235,13 @@ class LoadGlobalICState final BASE_EMBEDDED {
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;
};
diff --git a/deps/v8/src/ic/ic-stats.cc b/deps/v8/src/ic/ic-stats.cc
new file mode 100644
index 0000000000..de2529fcd9
--- /dev/null
+++ b/deps/v8/src/ic/ic-stats.cc
@@ -0,0 +1,144 @@
+// 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.
+
+#include "src/ic/ic-stats.h"
+
+#include "src/flags.h"
+#include "src/objects-inl.h"
+#include "src/tracing/trace-event.h"
+#include "src/tracing/traced-value.h"
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+base::LazyInstance<ICStats>::type ICStats::instance_ =
+ LAZY_INSTANCE_INITIALIZER;
+
+ICStats::ICStats() : ic_infos_(MAX_IC_INFO), pos_(0) {
+ base::NoBarrier_Store(&enabled_, 0);
+}
+
+void ICStats::Begin() {
+ if (V8_LIKELY(!FLAG_ic_stats)) return;
+ base::NoBarrier_Store(&enabled_, 1);
+}
+
+void ICStats::End() {
+ if (base::NoBarrier_Load(&enabled_) != 1) return;
+ ++pos_;
+ if (pos_ == MAX_IC_INFO) {
+ Dump();
+ }
+ base::NoBarrier_Store(&enabled_, 0);
+}
+
+void ICStats::Reset() {
+ for (auto ic_info : ic_infos_) {
+ ic_info.Reset();
+ }
+ pos_ = 0;
+}
+
+void ICStats::Dump() {
+ auto value = v8::tracing::TracedValue::Create();
+ value->BeginArray("data");
+ for (int i = 0; i < pos_; ++i) {
+ ic_infos_[i].AppendToTracedValue(value.get());
+ }
+ value->EndArray();
+
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.ic_stats"), "V8.ICStats",
+ TRACE_EVENT_SCOPE_THREAD, "ic-stats", std::move(value));
+ Reset();
+}
+
+const char* ICStats::GetOrCacheScriptName(Script* script) {
+ if (script_name_map_.find(script) != script_name_map_.end()) {
+ return script_name_map_[script].get();
+ }
+ Object* script_name_raw = script->name();
+ if (script_name_raw->IsString()) {
+ String* script_name = String::cast(script_name_raw);
+ char* c_script_name =
+ script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
+ .release();
+ script_name_map_.insert(
+ std::make_pair(script, std::unique_ptr<char[]>(c_script_name)));
+ return c_script_name;
+ } else {
+ script_name_map_.insert(
+ std::make_pair(script, std::unique_ptr<char[]>(nullptr)));
+ return nullptr;
+ }
+ return nullptr;
+}
+
+const char* ICStats::GetOrCacheFunctionName(JSFunction* function) {
+ if (function_name_map_.find(function) != function_name_map_.end()) {
+ return function_name_map_[function].get();
+ }
+ SharedFunctionInfo* shared = function->shared();
+ ic_infos_[pos_].is_optimized = function->IsOptimized();
+ char* function_name = shared->DebugName()->ToCString().release();
+ function_name_map_.insert(
+ std::make_pair(function, std::unique_ptr<char[]>(function_name)));
+ return function_name;
+}
+
+ICInfo::ICInfo()
+ : function_name(nullptr),
+ script_offset(0),
+ script_name(nullptr),
+ line_num(-1),
+ is_constructor(false),
+ is_optimized(false),
+ map(nullptr),
+ is_dictionary_map(0),
+ number_of_own_descriptors(0) {}
+
+void ICInfo::Reset() {
+ type.clear();
+ function_name = nullptr;
+ script_offset = 0;
+ script_name = nullptr;
+ line_num = -1;
+ is_constructor = false;
+ is_optimized = false;
+ state.clear();
+ map = nullptr;
+ is_dictionary_map = false;
+ number_of_own_descriptors = 0;
+ instance_type.clear();
+}
+
+void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const {
+ value->BeginDictionary();
+ value->SetString("type", type);
+ if (function_name) {
+ value->SetString("functionName", function_name);
+ if (is_optimized) {
+ value->SetInteger("optimized", is_optimized);
+ }
+ }
+ if (script_offset) value->SetInteger("offset", script_offset);
+ if (script_name) value->SetString("scriptName", script_name);
+ if (line_num != -1) value->SetInteger("lineNum", line_num);
+ if (is_constructor) value->SetInteger("constructor", is_constructor);
+ if (!state.empty()) value->SetString("state", state);
+ if (map) {
+ // V8 cannot represent integer above 2^53 - 1 in JavaScript from JSON,
+ // thus `map` should be converted to a string rather than an integer.
+ std::stringstream ss;
+ ss << map;
+ value->SetString("map", ss.str());
+ }
+ if (map) value->SetInteger("dict", is_dictionary_map);
+ if (map) value->SetInteger("own", number_of_own_descriptors);
+ if (!instance_type.empty()) value->SetString("instanceType", instance_type);
+ value->EndDictionary();
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ic/ic-stats.h b/deps/v8/src/ic/ic-stats.h
new file mode 100644
index 0000000000..a3015d0a6a
--- /dev/null
+++ b/deps/v8/src/ic/ic-stats.h
@@ -0,0 +1,77 @@
+// 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_IC_IC_STATS_H_
+#define V8_IC_IC_STATS_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "src/base/atomicops.h"
+#include "src/base/lazy-instance.h"
+
+namespace v8 {
+
+namespace tracing {
+class TracedValue;
+}
+
+namespace internal {
+
+class JSFunction;
+class Script;
+
+struct ICInfo {
+ ICInfo();
+ void Reset();
+ void AppendToTracedValue(v8::tracing::TracedValue* value) const;
+ std::string type;
+ const char* function_name;
+ int script_offset;
+ const char* script_name;
+ int line_num;
+ bool is_constructor;
+ bool is_optimized;
+ std::string state;
+ // Address of the map.
+ void* map;
+ // Whether map is a dictionary map.
+ bool is_dictionary_map;
+ // Number of own descriptors.
+ unsigned number_of_own_descriptors;
+ std::string instance_type;
+};
+
+class ICStats {
+ public:
+ const int MAX_IC_INFO = 4096;
+
+ ICStats();
+ void Dump();
+ void Begin();
+ void End();
+ void Reset();
+ V8_INLINE ICInfo& Current() {
+ DCHECK(pos_ >= 0 && pos_ < MAX_IC_INFO);
+ return ic_infos_[pos_];
+ }
+ const char* GetOrCacheScriptName(Script* script);
+ const char* GetOrCacheFunctionName(JSFunction* function);
+ V8_INLINE static ICStats* instance() { return instance_.Pointer(); }
+
+ private:
+ static base::LazyInstance<ICStats>::type instance_;
+ base::Atomic32 enabled_;
+ std::vector<ICInfo> ic_infos_;
+ std::unordered_map<Script*, std::unique_ptr<char[]>> script_name_map_;
+ std::unordered_map<JSFunction*, std::unique_ptr<char[]>> function_name_map_;
+ int pos_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_IC_IC_STATS_H_
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index 7e0cefdca9..fa04e0fca0 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -21,6 +21,7 @@
#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"
#include "src/isolate-inl.h"
#include "src/macro-assembler.h"
@@ -29,6 +30,7 @@
#include "src/runtime/runtime-utils.h"
#include "src/runtime/runtime.h"
#include "src/tracing/trace-event.h"
+#include "src/tracing/tracing-category-observer.h"
namespace v8 {
namespace internal {
@@ -90,7 +92,7 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
void IC::TraceIC(const char* type, Handle<Object> name) {
- if (FLAG_trace_ic) {
+ if (FLAG_ic_stats) {
if (AddressIsDeoptimizedCode()) return;
DCHECK(UseVector());
State new_state = nexus()->StateFromFeedback();
@@ -101,8 +103,17 @@ void IC::TraceIC(const char* type, Handle<Object> name) {
void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
State new_state) {
- if (!FLAG_trace_ic) return;
- PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type);
+ if (V8_LIKELY(!FLAG_ic_stats)) return;
+
+ 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;
+ } else {
+ PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type);
+ }
// TODO(jkummerow): Add support for "apply". The logic is roughly:
// marker = [fp_ + kMarkerOffset];
@@ -121,8 +132,14 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
code_offset =
static_cast<int>(pc() - function->code()->instruction_start());
}
- JavaScriptFrame::PrintFunctionAndOffset(function, function->abstract_code(),
- code_offset, stdout, true);
+ 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);
+ }
}
const char* modifier = "";
@@ -135,17 +152,45 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
if (!receiver_map().is_null()) {
map = *receiver_map();
}
- PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state),
- TransitionMarkFromState(new_state), modifier,
- reinterpret_cast<void*>(map));
+ 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);
+ } else {
+ PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state),
+ TransitionMarkFromState(new_state), modifier,
+ reinterpret_cast<void*>(map));
+ }
if (map != nullptr) {
- 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) {
+ 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");
}
- PrintF(") ");
- name->ShortPrint(stdout);
- PrintF("]\n");
}
@@ -342,7 +387,7 @@ void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
update_receiver_map(receiver);
if (!name->IsString()) return;
if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
- if (receiver->IsUndefined(isolate()) || receiver->IsNull(isolate())) return;
+ if (receiver->IsNullOrUndefined(isolate())) return;
// Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it
@@ -564,7 +609,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
nexus->ConfigureMonomorphic(map, handler);
} else if (kind() == Code::LOAD_GLOBAL_IC) {
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
- nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
+ nexus->ConfigureHandlerMode(handler);
} else if (kind() == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, handler);
@@ -603,10 +648,9 @@ void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
OnTypeFeedbackChanged(isolate(), get_host());
}
-
void IC::ConfigureVectorState(MapHandleList* maps,
MapHandleList* transitioned_maps,
- CodeHandleList* handlers) {
+ List<Handle<Object>>* handlers) {
DCHECK(UseVector());
DCHECK(kind() == Code::KEYED_STORE_IC);
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
@@ -620,7 +664,14 @@ void IC::ConfigureVectorState(MapHandleList* maps,
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// If the object is undefined or null it's illegal to try to get any
// of its properties; throw a TypeError in that case.
- if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
+ if (object->IsNullOrUndefined(isolate())) {
+ if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
+ // Ensure the IC state progresses.
+ TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
+ update_receiver_map(object);
+ PatchCache(name, slow_stub());
+ TRACE_IC("LoadIC", name);
+ }
return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
}
@@ -794,6 +845,7 @@ 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);
@@ -831,23 +883,9 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
}
}
-Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
- ExtraICState extra_state) {
- DCHECK(!FLAG_tf_store_ic_stub);
- LanguageMode mode = StoreICState::GetLanguageMode(extra_state);
- return is_strict(mode)
- ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
- : isolate->builtins()->KeyedStoreIC_Megamorphic();
-}
-
-Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
- if (FLAG_tf_load_ic_stub) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
- return LoadHandler::LoadField(isolate(), index);
- }
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
- LoadFieldStub stub(isolate(), index);
- return stub.GetCode();
+Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
+ TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH);
+ return LoadHandler::LoadField(isolate, index);
}
namespace {
@@ -1044,7 +1082,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
if (holder->HasFastProperties()) {
if (getter->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
- if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() &&
+ if (!receiver->IsJSObject() && function->shared()->IsUserJavaScript() &&
is_sloppy(function->shared()->language_mode())) {
// Calling sloppy non-builtins with a value as the receiver
// requires boxing.
@@ -1077,26 +1115,17 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsFound()) {
- if (kind() == Code::LOAD_IC) {
+ if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
code = LoadNonExistent(receiver_map(), lookup->name());
- } else if (kind() == Code::LOAD_GLOBAL_IC) {
- code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
- receiver_map());
- // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
- if (code.is_null()) code = slow_stub();
} else {
code = slow_stub();
}
} else {
if (kind() == Code::LOAD_GLOBAL_IC &&
lookup->state() == LookupIterator::DATA &&
- lookup->GetHolder<Object>()->IsJSGlobalObject()) {
-#if DEBUG
- Handle<Object> holder = lookup->GetHolder<Object>();
- Handle<Object> receiver = lookup->GetReceiver();
- DCHECK_EQ(*receiver, *holder);
-#endif
+ lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
+ DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
// Now update the cell in the feedback vector.
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
@@ -1108,22 +1137,15 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub();
}
} else if (lookup->state() == LookupIterator::INTERCEPTOR) {
- if (kind() == Code::LOAD_GLOBAL_IC) {
- // The interceptor handler requires name but it is not passed explicitly
- // to LoadGlobalIC and the LoadGlobalIC dispatcher also does not load
- // it so we will just use slow stub.
+ // Perform a lookup behind the interceptor. Copy the LookupIterator
+ // since the original iterator will be used to fetch the value.
+ LookupIterator it = *lookup;
+ it.Next();
+ LookupForRead(&it);
+ if (it.state() == LookupIterator::ACCESSOR &&
+ !IsCompatibleReceiver(&it, receiver_map())) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
code = slow_stub();
- } else {
- // Perform a lookup behind the interceptor. Copy the LookupIterator
- // since the original iterator will be used to fetch the value.
- LookupIterator it = *lookup;
- it.Next();
- LookupForRead(&it);
- if (it.state() == LookupIterator::ACCESSOR &&
- !IsCompatibleReceiver(&it, receiver_map())) {
- TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
- code = slow_stub();
- }
}
}
if (code.is_null()) code = ComputeHandler(lookup);
@@ -1288,7 +1310,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (receiver->IsString() &&
Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
- return SimpleFieldLoad(index);
+ return SimpleFieldLoad(isolate(), index);
}
if (receiver->IsStringWrapper() &&
@@ -1326,7 +1348,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
&object_offset)) {
FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
- return SimpleFieldLoad(index);
+ return SimpleFieldLoad(isolate(), index);
}
if (IsCompatibleReceiver(lookup, map)) {
@@ -1356,26 +1378,15 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
- if (FLAG_tf_load_ic_stub) {
- Handle<Object> smi_handler = LoadHandler::LoadApiGetter(
- isolate(), lookup->GetAccessorIndex());
- if (receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
- return smi_handler;
- }
- if (kind() != Code::LOAD_GLOBAL_IC) {
- TRACE_HANDLER_STATS(isolate(),
- LoadIC_LoadApiGetterFromPrototypeDH);
- return LoadFromPrototype(map, holder, lookup->name(),
- smi_handler);
- }
- } else {
- if (receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub);
- int index = lookup->GetAccessorIndex();
- LoadApiGetterStub stub(isolate(), true, index);
- return stub.GetCode();
- }
+ Handle<Object> smi_handler =
+ LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
+ if (receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
+ return smi_handler;
+ }
+ if (kind() != Code::LOAD_GLOBAL_IC) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
break; // Custom-compiled handler.
}
@@ -1385,6 +1396,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) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
@@ -1406,40 +1418,26 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
}
// -------------- Fields --------------
- if (lookup->property_details().type() == DATA) {
+ if (lookup->property_details().location() == kField) {
FieldIndex field = lookup->GetFieldIndex();
- Handle<Object> smi_handler = SimpleFieldLoad(field);
+ Handle<Object> smi_handler = SimpleFieldLoad(isolate(), field);
if (receiver_is_holder) {
return smi_handler;
}
- if (FLAG_tf_load_ic_stub && kind() != Code::LOAD_GLOBAL_IC) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
- return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
- }
- break; // Custom-compiled handler.
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
// -------------- Constant properties --------------
- DCHECK(lookup->property_details().type() == DATA_CONSTANT);
- if (FLAG_tf_load_ic_stub) {
- Handle<Object> smi_handler =
- LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
- if (receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
- return smi_handler;
- }
- if (kind() != Code::LOAD_GLOBAL_IC) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
- return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
- }
- } else {
- if (receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub);
- LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
- return stub.GetCode();
- }
+ DCHECK_EQ(kDescriptor, lookup->property_details().location());
+ Handle<Object> smi_handler =
+ LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
+ if (receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
+ return smi_handler;
}
- break; // Custom-compiled handler.
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -1543,33 +1541,15 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
}
case LookupIterator::DATA: {
- if (lookup->is_dictionary_holder()) {
- DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
- DCHECK(holder->IsJSGlobalObject());
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- Handle<PropertyCell> cell = lookup->GetPropertyCell();
- Handle<Code> code = compiler.CompileLoadGlobal(
- cell, lookup->name(), lookup->IsConfigurable());
- return code;
- }
-
- // -------------- Fields --------------
- if (lookup->property_details().type() == DATA) {
- FieldIndex field = lookup->GetFieldIndex();
- DCHECK(!receiver_is_holder);
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- return compiler.CompileLoadField(lookup->name(), field);
- }
-
- // -------------- Constant properties --------------
- DCHECK(lookup->property_details().type() == DATA_CONSTANT);
- DCHECK(!receiver_is_holder);
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant);
+ DCHECK(lookup->is_dictionary_holder());
+ DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
+ DCHECK(holder->IsJSGlobalObject());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- return compiler.CompileLoadConstant(lookup->name(),
- lookup->GetConstantIndex());
+ Handle<PropertyCell> cell = lookup->GetPropertyCell();
+ Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(),
+ lookup->IsConfigurable());
+ return code;
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -1839,7 +1819,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
- if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
+ if (object->IsNullOrUndefined(isolate())) {
+ if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
+ // Ensure the IC state progresses.
+ TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
+ update_receiver_map(object);
+ PatchCache(name, slow_stub());
+ TRACE_IC("StoreIC", name);
+ }
return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
}
@@ -1890,11 +1877,12 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
DCHECK(!transition->is_access_check_needed());
Handle<Object> smi_handler;
- if (details.type() == DATA_CONSTANT) {
+ DCHECK_EQ(kData, details.kind());
+ if (details.location() == kDescriptor) {
smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
} else {
- DCHECK_EQ(DATA, details.type());
+ DCHECK_EQ(kField, details.location());
bool extend_storage =
Map::cast(transition->GetBackPointer())->unused_property_fields() == 0;
@@ -1972,13 +1960,10 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
return slow_stub();
}
DCHECK(lookup->IsCacheableTransition());
- if (FLAG_tf_store_ic_stub) {
- Handle<Map> transition = lookup->transition_map();
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
- return StoreTransition(receiver_map(), holder, transition,
- lookup->name());
- }
- break; // Custom-compiled handler.
+ Handle<Map> transition = lookup->transition_map();
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
+ return StoreTransition(receiver_map(), holder, transition,
+ lookup->name());
}
case LookupIterator::INTERCEPTOR: {
@@ -2044,6 +2029,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
}
case LookupIterator::DATA: {
+ DCHECK_EQ(kData, lookup->property_details().kind());
if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) {
break; // Custom-compiled handler.
@@ -2054,32 +2040,16 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
}
// -------------- Fields --------------
- if (lookup->property_details().type() == DATA) {
- if (FLAG_tf_store_ic_stub) {
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
- int descriptor = lookup->GetFieldDescriptorIndex();
- FieldIndex index = lookup->GetFieldIndex();
- return StoreHandler::StoreField(isolate(), descriptor, index,
- lookup->representation());
- } else {
- bool use_stub = true;
- if (lookup->representation().IsHeapObject()) {
- // Only use a generic stub if no types need to be tracked.
- Handle<FieldType> field_type = lookup->GetFieldType();
- use_stub = !field_type->IsClass();
- }
- if (use_stub) {
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldStub);
- StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
- lookup->representation());
- return stub.GetCode();
- }
- }
- break; // Custom-compiled handler.
+ if (lookup->property_details().location() == kField) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
+ int descriptor = lookup->GetFieldDescriptorIndex();
+ FieldIndex index = lookup->GetFieldIndex();
+ return StoreHandler::StoreField(isolate(), descriptor, index,
+ lookup->representation());
}
// -------------- Constant properties --------------
- DCHECK(lookup->property_details().type() == DATA_CONSTANT);
+ DCHECK_EQ(kDescriptor, lookup->property_details().location());
TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
@@ -2117,15 +2087,7 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
cell->set_value(isolate()->heap()->the_hole_value());
return code;
}
- DCHECK(!FLAG_tf_store_ic_stub);
- Handle<Map> transition = lookup->transition_map();
- // Currently not handled by CompileStoreTransition.
- DCHECK(holder->HasFastProperties());
-
- DCHECK(lookup->IsCacheableTransition());
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- return compiler.CompileStoreTransition(transition, lookup->name());
+ UNREACHABLE();
}
case LookupIterator::INTERCEPTOR:
@@ -2173,40 +2135,18 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
}
case LookupIterator::DATA: {
- if (lookup->is_dictionary_holder()) {
- DCHECK(holder->IsJSGlobalObject());
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
- DCHECK(holder.is_identical_to(receiver) ||
- receiver->map()->prototype() == *holder);
- auto cell = lookup->GetPropertyCell();
- auto updated_type =
- PropertyCell::UpdatedType(cell, value, lookup->property_details());
- auto code = PropertyCellStoreHandler(
- isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
- lookup->name(), cell, updated_type);
- return code;
- }
-
- // -------------- Fields --------------
- if (lookup->property_details().type() == DATA) {
- DCHECK(!FLAG_tf_store_ic_stub);
-#ifdef DEBUG
- bool use_stub = true;
- if (lookup->representation().IsHeapObject()) {
- // Only use a generic stub if no types need to be tracked.
- Handle<FieldType> field_type = lookup->GetFieldType();
- use_stub = !field_type->IsClass();
- }
- DCHECK(!use_stub);
-#endif
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField);
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- return compiler.CompileStoreField(lookup);
- }
-
- // -------------- Constant properties --------------
- DCHECK(lookup->property_details().type() == DATA_CONSTANT);
- UNREACHABLE();
+ DCHECK(lookup->is_dictionary_holder());
+ DCHECK(holder->IsJSGlobalObject());
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
+ DCHECK(holder.is_identical_to(receiver) ||
+ receiver->map()->prototype() == *holder);
+ auto cell = lookup->GetPropertyCell();
+ auto updated_type =
+ PropertyCell::UpdatedType(cell, value, lookup->property_details());
+ auto code = PropertyCellStoreHandler(isolate(), receiver,
+ Handle<JSGlobalObject>::cast(holder),
+ lookup->name(), cell, updated_type);
+ return code;
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -2227,7 +2167,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
Handle<Map> monomorphic_map =
ComputeTransitionedMap(receiver_map, store_mode);
store_mode = GetNonTransitioningStoreMode(store_mode);
- Handle<Code> handler =
+ Handle<Object> handler =
PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map,
store_mode);
return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
@@ -2261,7 +2201,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// if they at least come from the same origin for a transitioning store,
// stay MONOMORPHIC and use the map for the most generic ElementsKind.
store_mode = GetNonTransitioningStoreMode(store_mode);
- Handle<Code> handler =
+ Handle<Object> handler =
PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
transitioned_receiver_map, store_mode);
ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
@@ -2275,7 +2215,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<Code> handler =
+ Handle<Object> handler =
PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map,
store_mode);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
@@ -2336,7 +2276,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
MapHandleList transitioned_maps(target_receiver_maps.length());
- CodeHandleList handlers(target_receiver_maps.length());
+ List<Handle<Object>> handlers(target_receiver_maps.length());
PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
&target_receiver_maps, &transitioned_maps, &handlers, store_mode);
ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
@@ -2485,17 +2425,14 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
}
Handle<Map> old_receiver_map;
- bool sloppy_arguments_elements = false;
+ bool is_arguments = false;
bool key_is_valid_index = false;
KeyedAccessStoreMode store_mode = STANDARD_STORE;
if (use_ic && object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
old_receiver_map = handle(receiver->map(), isolate());
- sloppy_arguments_elements =
- !is_sloppy(language_mode()) &&
- receiver->elements()->map() ==
- isolate()->heap()->sloppy_arguments_elements_map();
- if (!sloppy_arguments_elements) {
+ is_arguments = receiver->IsJSArgumentsObject();
+ if (!is_arguments) {
key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
if (key_is_valid_index) {
uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
@@ -2512,7 +2449,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
if (use_ic) {
if (!old_receiver_map.is_null()) {
- if (sloppy_arguments_elements) {
+ if (is_arguments) {
TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
} else if (key_is_valid_index) {
// We should go generic if receiver isn't a dictionary, but our
@@ -2597,7 +2534,7 @@ 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<Object>(0);
+ Handle<Object> function = args.at(0);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
Handle<Smi> slot = args.at<Smi>(2);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
@@ -2613,7 +2550,8 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> receiver = args.at<Object>(0);
+ Handle<Object> receiver = args.at(0);
+ Handle<Name> key = args.at<Name>(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
@@ -2622,15 +2560,12 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
// set up outside the IC, handle that here.
FeedbackVectorSlotKind kind = vector->GetKind(vector_slot);
if (kind == FeedbackVectorSlotKind::LOAD_IC) {
- Handle<Name> key = args.at<Name>(1);
LoadICNexus nexus(vector, vector_slot);
LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
} else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
- Handle<Name> key(vector->GetName(vector_slot), isolate);
- DCHECK_NE(*key, isolate->heap()->empty_string());
DCHECK_EQ(*isolate->global_object(), *receiver);
LoadGlobalICNexus nexus(vector, vector_slot);
LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
@@ -2638,7 +2573,6 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
} else {
- Handle<Name> key = args.at<Name>(1);
DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind);
KeyedLoadICNexus nexus(vector, vector_slot);
KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
@@ -2650,16 +2584,13 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
HandleScope scope(isolate);
- DCHECK_EQ(2, args.length());
+ DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<JSGlobalObject> global = isolate->global_object();
- Handle<Smi> slot = args.at<Smi>(0);
- Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
+ Handle<String> name = args.at<String>(0);
+ Handle<Smi> slot = args.at<Smi>(1);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
- DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
- vector->GetKind(vector_slot));
- Handle<String> name(vector->GetName(vector_slot), isolate);
- DCHECK_NE(*name, isolate->heap()->empty_string());
LoadGlobalICNexus nexus(vector, vector_slot);
LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
@@ -2672,20 +2603,12 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
HandleScope scope(isolate);
- DCHECK_EQ(2, args.length());
- CONVERT_SMI_ARG_CHECKED(slot, 0);
- CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
-
- FeedbackVectorSlot vector_slot = vector->ToSlot(slot);
- DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
- vector->GetKind(vector_slot));
- Handle<String> name(vector->GetName(vector_slot), isolate);
- DCHECK_NE(*name, isolate->heap()->empty_string());
-
- Handle<JSGlobalObject> global = isolate->global_object();
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+ Handle<Context> native_context = isolate->native_context();
Handle<ScriptContextTable> script_contexts(
- global->native_context()->script_context_table());
+ native_context->script_context_table());
ScriptContextTable::LookupResult lookup_result;
if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
@@ -2700,6 +2623,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
return *result;
}
+ Handle<JSGlobalObject> global(native_context->global_object(), isolate);
Handle<Object> result;
bool is_found = false;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -2723,8 +2647,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> receiver = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
+ Handle<Object> receiver = args.at(0);
+ Handle<Object> key = args.at(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
@@ -2739,8 +2663,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
HandleScope scope(isolate);
typedef LoadWithVectorDescriptor Descriptor;
DCHECK_EQ(Descriptor::kParameterCount, args.length());
- Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
- Handle<Object> key = args.at<Object>(Descriptor::kName);
+ Handle<Object> receiver = args.at(Descriptor::kReceiver);
+ Handle<Object> key = args.at(Descriptor::kName);
Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
Handle<TypeFeedbackVector> vector =
args.at<TypeFeedbackVector>(Descriptor::kVector);
@@ -2757,10 +2681,10 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> value = args.at<Object>(0);
+ Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
- Handle<Object> receiver = args.at<Object>(3);
+ 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) {
@@ -2784,11 +2708,11 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> value = args.at<Object>(0);
+ Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
- Handle<Object> receiver = args.at<Object>(3);
- Handle<Object> key = args.at<Object>(4);
+ Handle<Object> receiver = args.at(3);
+ Handle<Object> key = args.at(4);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
@@ -2801,10 +2725,10 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> value = args.at<Object>(0);
+ Handle<Object> value = args.at(0);
// slot and vector parameters are not used.
- Handle<Object> object = args.at<Object>(3);
- Handle<Object> key = args.at<Object>(4);
+ 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);
@@ -2818,9 +2742,9 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
HandleScope scope(isolate);
// Runtime functions don't follow the IC's calling convention.
- Handle<Object> object = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
- Handle<Object> value = args.at<Object>(2);
+ 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);
@@ -2931,7 +2855,19 @@ MaybeHandle<Object> BinaryOpIC::Transition(
}
set_target(*new_target);
- if (FLAG_trace_ic) {
+ 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 = "BinaryOpIC";
+ ic_info.state = old_state.ToString();
+ ic_info.state += " => ";
+ ic_info.state += state.ToString();
+ 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) << " <- ";
@@ -2957,8 +2893,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
typedef BinaryOpDescriptor Descriptor;
- Handle<Object> left = args.at<Object>(Descriptor::kLeft);
- Handle<Object> right = args.at<Object>(Descriptor::kRight);
+ Handle<Object> left = args.at(Descriptor::kLeft);
+ Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(
isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
@@ -2971,8 +2907,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
Handle<AllocationSite> allocation_site =
args.at<AllocationSite>(Descriptor::kAllocationSite);
- Handle<Object> left = args.at<Object>(Descriptor::kLeft);
- Handle<Object> right = args.at<Object>(Descriptor::kRight);
+ Handle<Object> left = args.at(Descriptor::kLeft);
+ Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(isolate,
ic.Transition(allocation_site, left, right));
@@ -3005,7 +2941,30 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
Handle<Code> new_target = stub.GetCode();
set_target(*new_target);
- if (FLAG_trace_ic) {
+ 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 = "CompareIC";
+ JavaScriptFrame::CollectTopFrameForICStats(isolate());
+ ic_info.state = "((";
+ ic_info.state += CompareICState::GetStateName(old_stub.left());
+ ic_info.state += "+";
+ ic_info.state += CompareICState::GetStateName(old_stub.right());
+ ic_info.state += "=";
+ ic_info.state += CompareICState::GetStateName(old_stub.state());
+ ic_info.state += ")->(";
+ ic_info.state += CompareICState::GetStateName(new_left);
+ ic_info.state += "+";
+ ic_info.state += CompareICState::GetStateName(new_right);
+ ic_info.state += "=";
+ ic_info.state += CompareICState::GetStateName(state);
+ ic_info.state += "))#";
+ 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",
@@ -3032,7 +2991,7 @@ RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
- return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
+ return ic.UpdateCaches(args.at(0), args.at(1));
}
@@ -3055,7 +3014,7 @@ Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
DCHECK(args.length() == 1);
HandleScope scope(isolate);
- Handle<Object> object = args.at<Object>(0);
+ Handle<Object> object = args.at(0);
ToBooleanIC ic(isolate);
return *ic.ToBoolean(object);
}
@@ -3066,7 +3025,7 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Handle<JSObject> holder = args.at<JSObject>(1);
Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
Handle<Name> name = args.at<Name>(3);
- Handle<Object> value = args.at<Object>(4);
+ Handle<Object> value = args.at(4);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
HandleScope scope(isolate);
@@ -3110,7 +3069,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
- args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
+ args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
HandleScope scope(isolate);
@@ -3146,7 +3105,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
- args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
+ args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
@@ -3181,15 +3140,17 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
if (it.IsFound()) return *result;
-#ifdef DEBUG
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.
- DCHECK(!ic.ShouldThrowReferenceError());
-#endif
+ if (!ic.ShouldThrowReferenceError()) {
+ return isolate->heap()->undefined_value();
+ }
- return isolate->heap()->undefined_value();
+ // Throw a reference error.
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
}
@@ -3200,7 +3161,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
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<Object>(2);
+ Handle<Object> value = args.at(2);
DCHECK(receiver->HasNamedInterceptor());
InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index 9e69cc85d0..c86fd713a2 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -120,7 +120,7 @@ class IC {
// keyed stores).
void ConfigureVectorState(MapHandleList* maps,
MapHandleList* transitioned_maps,
- CodeHandleList* handlers);
+ List<Handle<Object>>* handlers);
char TransitionMarkFromState(IC::State state);
void TraceIC(const char* type, Handle<Object> name);
@@ -285,12 +285,6 @@ class LoadIC : public IC {
NOT_INSIDE_TYPEOF;
}
- // Code generator routines.
-
- static void GenerateMiss(MacroAssembler* masm);
- static void GenerateRuntimeGetProperty(MacroAssembler* masm);
- static void GenerateNormal(MacroAssembler* masm);
-
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name);
@@ -312,7 +306,7 @@ class LoadIC : public IC {
private:
// Creates a data handler that represents a load of a field by given index.
- Handle<Object> SimpleFieldLoad(FieldIndex index);
+ static Handle<Object> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
// Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder.
@@ -325,6 +319,7 @@ class LoadIC : public IC {
Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name);
friend class IC;
+ friend class NamedLoadHandlerCompiler;
};
class LoadGlobalIC : public LoadIC {
@@ -353,10 +348,6 @@ class KeyedLoadIC : public LoadIC {
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Object> key);
- // Code generator routines.
- static void GenerateMiss(MacroAssembler* masm);
- static void GenerateRuntimeGetProperty(MacroAssembler* masm);
-
static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
protected:
@@ -379,11 +370,6 @@ class StoreIC : public IC {
return StoreICState::GetLanguageMode(extra_ic_state());
}
- // Code generators for stub routines. Only called once at startup.
- static void GenerateSlow(MacroAssembler* masm);
- static void GenerateMiss(MacroAssembler* masm);
- static void GenerateNormal(MacroAssembler* masm);
-
MUST_USE_RESULT MaybeHandle<Object> Store(
Handle<Object> object, Handle<Name> name, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode =
@@ -451,9 +437,6 @@ class KeyedStoreIC : public StoreIC {
static void GenerateMegamorphic(MacroAssembler* masm,
LanguageMode language_mode);
- static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
- ExtraICState extra_state);
-
static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus);
protected:
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index 30faba85e9..81ce3a6a1f 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -4,8 +4,11 @@
#include "src/ic/keyed-store-generic.h"
-#include "src/compiler/code-assembler.h"
+#include "src/code-factory.h"
+#include "src/code-stub-assembler.h"
#include "src/contexts.h"
+#include "src/ic/accessor-assembler-impl.h"
+#include "src/interface-descriptors.h"
#include "src/isolate.h"
namespace v8 {
@@ -13,10 +16,12 @@ namespace internal {
using compiler::Node;
-class KeyedStoreGenericAssembler : public CodeStubAssembler {
+class KeyedStoreGenericAssembler : public AccessorAssemblerImpl {
public:
- void KeyedStoreGeneric(const StoreICParameters* p,
- LanguageMode language_mode);
+ explicit KeyedStoreGenericAssembler(compiler::CodeAssemblerState* state)
+ : AccessorAssemblerImpl(state) {}
+
+ void KeyedStoreGeneric(LanguageMode language_mode);
private:
enum UpdateLength {
@@ -30,7 +35,8 @@ class KeyedStoreGenericAssembler : public CodeStubAssembler {
Node* value, Node* context, Label* slow);
void EmitGenericPropertyStore(Node* receiver, Node* receiver_map,
- const StoreICParameters* p, Label* slow);
+ const StoreICParameters* p, Label* slow,
+ LanguageMode language_mode);
void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
Label* non_fast_elements,
@@ -60,16 +66,18 @@ class KeyedStoreGenericAssembler : public CodeStubAssembler {
ElementsKind packed_kind,
ElementsKind packed_kind_2, Label* bailout);
- // Do not add fields, so that this is safe to reinterpret_cast to CSA.
+ void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
+ void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name,
+ Label* accessor,
+ Variable* var_accessor_pair,
+ Variable* var_accessor_holder,
+ Label* readonly, Label* bailout);
};
-void KeyedStoreGenericGenerator::Generate(
- CodeStubAssembler* assembler, const CodeStubAssembler::StoreICParameters* p,
- LanguageMode language_mode) {
- STATIC_ASSERT(sizeof(CodeStubAssembler) ==
- sizeof(KeyedStoreGenericAssembler));
- auto assm = reinterpret_cast<KeyedStoreGenericAssembler*>(assembler);
- assm->KeyedStoreGeneric(p, language_mode);
+void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state,
+ LanguageMode language_mode) {
+ KeyedStoreGenericAssembler assembler(state);
+ assembler.KeyedStoreGeneric(language_mode);
}
void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
@@ -94,9 +102,7 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
non_fast_elements);
Node* elements_kind = LoadMapElementsKind(prototype_map);
STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
- GotoIf(Int32LessThanOrEqual(elements_kind,
- Int32Constant(LAST_FAST_ELEMENTS_KIND)),
- &loop_body);
+ GotoIf(IsFastElementsKind(elements_kind), &loop_body);
GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
Goto(non_fast_elements);
}
@@ -112,7 +118,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
TrapAllocationMemento(receiver, bailout);
}
Label perform_transition(this), check_holey_map(this);
- Variable var_target_map(this, MachineType::PointerRepresentation());
+ Variable var_target_map(this, MachineRepresentation::kTagged);
// Check if the receiver has the default |from_kind| map.
{
Node* packed_map =
@@ -143,7 +149,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
capacity, INTPTR_PARAMETERS, bailout);
}
- StoreObjectField(receiver, JSObject::kMapOffset, var_target_map.value());
+ StoreMap(receiver, var_target_map.value());
}
}
@@ -160,7 +166,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
}
Node* holey_map =
LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind));
- StoreObjectField(receiver, JSObject::kMapOffset, holey_map);
+ StoreMap(receiver, holey_map);
Goto(done);
}
@@ -219,6 +225,15 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
if (update_length != kDontChangeLength) {
CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(receiver_map),
Int32Constant(JS_ARRAY_TYPE)));
+ // Check if the length property is writable. The fast check is only
+ // supported for fast properties.
+ GotoIf(IsDictionaryMap(receiver_map), slow);
+ // The length property is non-configurable, so it's guaranteed to always
+ // be the first property.
+ Node* descriptors = LoadMapDescriptors(receiver_map);
+ Node* details =
+ LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
+ GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), slow);
}
STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
const int kHeaderSize = FixedArray::kHeaderSize - kHeapObjectTag;
@@ -276,7 +291,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
FAST_ELEMENTS, slow);
}
- Store(MachineRepresentation::kTagged, elements, offset, value);
+ Store(elements, offset, value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
Bind(&must_transition);
@@ -320,7 +335,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
FAST_SMI_ELEMENTS, target_kind, slow);
// The elements backing store didn't change, no reload necessary.
CSA_ASSERT(this, WordEqual(elements, LoadElements(receiver)));
- Store(MachineRepresentation::kTagged, elements, offset, value);
+ Store(elements, offset, value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
update_length);
}
@@ -356,8 +371,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// Try to store the value as a double.
{
Label non_number_value(this);
- Node* double_value = PrepareValueForWrite(value, Representation::Double(),
- &non_number_value);
+ Node* double_value = TryTaggedToFloat64(value, &non_number_value);
+
// Make sure we do not store signalling NaNs into double arrays.
double_value = Float64SilenceNaN(double_value);
// If we're about to introduce holes, ensure holey elements.
@@ -384,7 +399,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
Node* fast_elements = LoadElements(receiver);
Node* fast_offset = ElementOffsetFromIndex(
intptr_index, FAST_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
- Store(MachineRepresentation::kTagged, fast_elements, fast_offset, value);
+ Store(fast_elements, fast_offset, value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
}
}
@@ -399,14 +414,13 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
void KeyedStoreGenericAssembler::EmitGenericElementStore(
Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
Node* value, Node* context, Label* slow) {
- Label if_in_bounds(this), if_increment_length_by_one(this),
+ Label if_fast(this), if_in_bounds(this), if_increment_length_by_one(this),
if_bump_length_with_gap(this), if_grow(this), if_nonfast(this),
if_typed_array(this), if_dictionary(this);
Node* elements = LoadElements(receiver);
Node* elements_kind = LoadMapElementsKind(receiver_map);
- GotoIf(
- Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
- &if_nonfast);
+ Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
+ Bind(&if_fast);
Label if_array(this);
GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), &if_array);
@@ -482,37 +496,268 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
}
+void KeyedStoreGenericAssembler::JumpIfDataProperty(Node* details,
+ Label* writable,
+ Label* readonly) {
+ // Accessor properties never have the READ_ONLY attribute set.
+ GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
+ readonly);
+ Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
+ GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
+ // Fall through if it's an accessor property.
+}
+
+void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
+ Node* receiver_map, Node* name, Label* accessor,
+ Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
+ Label* bailout) {
+ Label ok_to_write(this);
+ Variable var_holder(this, MachineRepresentation::kTagged);
+ var_holder.Bind(LoadMapPrototype(receiver_map));
+ Variable var_holder_map(this, MachineRepresentation::kTagged);
+ var_holder_map.Bind(LoadMap(var_holder.value()));
+
+ Variable* merged_variables[] = {&var_holder, &var_holder_map};
+ Label loop(this, arraysize(merged_variables), merged_variables);
+ Goto(&loop);
+ Bind(&loop);
+ {
+ Node* holder = var_holder.value();
+ Node* holder_map = var_holder_map.value();
+ Node* instance_type = LoadMapInstanceType(holder_map);
+ Label next_proto(this);
+ {
+ Label found(this), found_fast(this), found_dict(this), found_global(this);
+ Variable var_meta_storage(this, MachineRepresentation::kTagged);
+ Variable var_entry(this, MachineType::PointerRepresentation());
+ TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
+ &found_dict, &found_global, &var_meta_storage,
+ &var_entry, &next_proto, bailout);
+ Bind(&found_fast);
+ {
+ 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);
+ JumpIfDataProperty(details, &ok_to_write, readonly);
+
+ // Accessor case.
+ Variable var_details(this, MachineRepresentation::kWord32);
+ LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
+ &var_details, var_accessor_pair);
+ var_accessor_holder->Bind(holder);
+ Goto(accessor);
+ }
+
+ Bind(&found_dict);
+ {
+ 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);
+ JumpIfDataProperty(details, &ok_to_write, readonly);
+
+ // Accessor case.
+ const int kNameToValueOffset = (NameDictionary::kEntryValueIndex -
+ NameDictionary::kEntryKeyIndex) *
+ kPointerSize;
+ var_accessor_pair->Bind(
+ LoadFixedArrayElement(dictionary, entry, kNameToValueOffset));
+ var_accessor_holder->Bind(holder);
+ Goto(accessor);
+ }
+
+ Bind(&found_global);
+ {
+ 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);
+
+ Node* value =
+ LoadObjectField(property_cell, PropertyCell::kValueOffset);
+ GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
+ Node* details = LoadAndUntagToWord32ObjectField(
+ property_cell, PropertyCell::kDetailsOffset);
+ JumpIfDataProperty(details, &ok_to_write, readonly);
+
+ // Accessor case.
+ var_accessor_pair->Bind(value);
+ var_accessor_holder->Bind(holder);
+ Goto(accessor);
+ }
+ }
+
+ Bind(&next_proto);
+ // Bailout if it can be an integer indexed exotic case.
+ GotoIf(Word32Equal(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
+ bailout);
+ Node* proto = LoadMapPrototype(holder_map);
+ GotoIf(WordEqual(proto, NullConstant()), &ok_to_write);
+ var_holder.Bind(proto);
+ var_holder_map.Bind(LoadMap(proto));
+ Goto(&loop);
+ }
+ Bind(&ok_to_write);
+}
+
void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
- Node* receiver, Node* receiver_map, const StoreICParameters* p,
- Label* slow) {
- Comment("stub cache probe");
- // TODO(jkummerow): Don't rely on the stub cache as much.
- // - existing properties can be overwritten inline (unless readonly).
- // - for dictionary mode receivers, we can even add properties inline
- // (unless the prototype chain prevents it).
- Variable var_handler(this, MachineRepresentation::kTagged);
- Label found_handler(this, &var_handler), stub_cache_miss(this);
- TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name,
- &found_handler, &var_handler, &stub_cache_miss);
- Bind(&found_handler);
+ Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow,
+ LanguageMode language_mode) {
+ Variable var_accessor_pair(this, MachineRepresentation::kTagged);
+ Variable var_accessor_holder(this, MachineRepresentation::kTagged);
+ Label stub_cache(this), fast_properties(this), dictionary_properties(this),
+ accessor(this), readonly(this);
+ Node* properties = LoadProperties(receiver);
+ Node* properties_map = LoadMap(properties);
+ Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
+ &dictionary_properties, &fast_properties);
+
+ Bind(&fast_properties);
{
- Comment("KeyedStoreGeneric found handler");
- HandleStoreICHandlerCase(p, var_handler.value(), slow);
+ // TODO(jkummerow): Does it make sense to support some cases here inline?
+ // Maybe overwrite existing writable properties?
+ // Maybe support map transitions?
+ Goto(&stub_cache);
}
- Bind(&stub_cache_miss);
+
+ Bind(&dictionary_properties);
{
- Comment("KeyedStoreGeneric_miss");
- TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
- p->vector, p->receiver, p->name);
+ Comment("dictionary property store");
+ // 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), not_found(this);
+ NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
+ &var_name_index, &not_found);
+ Bind(&dictionary_found);
+ {
+ Label overwrite(this);
+ const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
+ NameDictionary::kEntryKeyIndex) *
+ kPointerSize;
+ Node* details = LoadAndUntagToWord32FixedArrayElement(
+ properties, var_name_index.value(), kNameToDetailsOffset);
+ 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_holder.Bind(receiver);
+ Goto(&accessor);
+
+ Bind(&overwrite);
+ {
+ StoreFixedArrayElement(properties, var_name_index.value(), p->value,
+ UPDATE_WRITE_BARRIER, kNameToValueOffset);
+ Return(p->value);
+ }
+ }
+
+ Bind(&not_found);
+ {
+ LookupPropertyOnPrototypeChain(receiver_map, p->name, &accessor,
+ &var_accessor_pair, &var_accessor_holder,
+ &readonly, slow);
+ Add<NameDictionary>(properties, p->name, p->value, slow);
+ Return(p->value);
+ }
+ }
+
+ Bind(&accessor);
+ {
+ Label not_callable(this);
+ Node* accessor_pair = var_accessor_pair.value();
+ GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow);
+ CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
+ Node* setter = LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
+ Node* setter_map = LoadMap(setter);
+ // FunctionTemplateInfo setters are not supported yet.
+ GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
+ GotoUnless(IsCallableMap(setter_map), &not_callable);
+
+ Callable callable = CodeFactory::Call(isolate());
+ CallJS(callable, p->context, setter, receiver, p->value);
+ Return(p->value);
+
+ Bind(&not_callable);
+ {
+ if (language_mode == STRICT) {
+ Node* message =
+ SmiConstant(Smi::FromInt(MessageTemplate::kNoSetterInCallback));
+ TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name,
+ var_accessor_holder.value());
+ } else {
+ DCHECK_EQ(SLOPPY, language_mode);
+ Return(p->value);
+ }
+ }
+ }
+
+ Bind(&readonly);
+ {
+ if (language_mode == STRICT) {
+ Node* message =
+ SmiConstant(Smi::FromInt(MessageTemplate::kStrictReadOnlyProperty));
+ Node* type = Typeof(p->receiver, p->context);
+ TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name,
+ type, p->receiver);
+ } else {
+ DCHECK_EQ(SLOPPY, language_mode);
+ Return(p->value);
+ }
+ }
+
+ Bind(&stub_cache);
+ {
+ Comment("stub cache probe");
+ Variable var_handler(this, MachineRepresentation::kTagged);
+ Label found_handler(this, &var_handler), stub_cache_miss(this);
+ TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name,
+ &found_handler, &var_handler, &stub_cache_miss);
+ Bind(&found_handler);
+ {
+ Comment("KeyedStoreGeneric found handler");
+ HandleStoreICHandlerCase(p, var_handler.value(), slow);
+ }
+ Bind(&stub_cache_miss);
+ {
+ Comment("KeyedStoreGeneric_miss");
+ TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value,
+ p->slot, p->vector, p->receiver, p->name);
+ }
}
}
-void KeyedStoreGenericAssembler::KeyedStoreGeneric(const StoreICParameters* p,
- LanguageMode language_mode) {
+void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
+ typedef StoreWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
Variable var_index(this, MachineType::PointerRepresentation());
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);
@@ -522,26 +767,28 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(const StoreICParameters* p,
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
&slow);
- TryToName(p->name, &if_index, &var_index, &if_unique_name, &slow);
+ TryToName(name, &if_index, &var_index, &if_unique_name, &slow);
Bind(&if_index);
{
Comment("integer index");
EmitGenericElementStore(receiver, receiver_map, instance_type,
- var_index.value(), p->value, p->context, &slow);
+ var_index.value(), value, context, &slow);
}
Bind(&if_unique_name);
{
Comment("key is unique name");
- EmitGenericPropertyStore(receiver, receiver_map, p, &slow);
+ KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name,
+ value, slot, vector);
+ EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode);
}
Bind(&slow);
{
Comment("KeyedStoreGeneric_slow");
- TailCallRuntime(Runtime::kSetProperty, p->context, p->receiver, p->name,
- p->value, SmiConstant(language_mode));
+ TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value,
+ SmiConstant(language_mode));
}
}
diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h
index daeb61fe68..8028736aa1 100644
--- a/deps/v8/src/ic/keyed-store-generic.h
+++ b/deps/v8/src/ic/keyed-store-generic.h
@@ -5,15 +5,18 @@
#ifndef V8_SRC_IC_KEYED_STORE_GENERIC_H_
#define V8_SRC_IC_KEYED_STORE_GENERIC_H_
-#include "src/code-stub-assembler.h"
+#include "src/globals.h"
namespace v8 {
namespace internal {
+namespace compiler {
+class CodeAssemblerState;
+}
+
class KeyedStoreGenericGenerator {
public:
- static void Generate(CodeStubAssembler* assembler,
- const CodeStubAssembler::StoreICParameters* p,
+ static void Generate(compiler::CodeAssemblerState* state,
LanguageMode 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 b2ddea5dac..43588b707a 100644
--- a/deps/v8/src/ic/mips/handler-compiler-mips.cc
+++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc
@@ -129,14 +129,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ Addu(sp, sp, Operand(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in ra register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in ra register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -181,18 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ lw(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -342,57 +322,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ li(this->name(), Operand(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ lw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ And(at, scratch, Operand(Map::Deprecated::kMask));
- __ Branch(miss, ne, at, Operand(zero_reg));
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ lw(scratch,
- FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ Branch(miss_label, ne, value_reg, Operand(scratch));
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ lw(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- // Compare map directly within the Branch() functions.
- __ GetWeakValue(scratch, Map::WeakCellForMap(field_type->AsClass()));
- __ Branch(miss_label, ne, map_reg, Operand(scratch));
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -520,14 +449,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ li(v0, value);
- __ Ret();
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/mips/ic-compiler-mips.cc b/deps/v8/src/ic/mips/ic-compiler-mips.cc
deleted file mode 100644
index 86a602b3ec..0000000000
--- a/deps/v8/src/ic/mips/ic-compiler-mips.cc
+++ /dev/null
@@ -1,33 +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.
-
-#if V8_TARGET_ARCH_MIPS
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister());
-
- __ li(a0, Operand(Smi::FromInt(language_mode)));
- __ Push(a0);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_MIPS
diff --git a/deps/v8/src/ic/mips/ic-mips.cc b/deps/v8/src/ic/mips/ic-mips.cc
index 561c9d331b..e31aab1d76 100644
--- a/deps/v8/src/ic/mips/ic-mips.cc
+++ b/deps/v8/src/ic/mips/ic-mips.cc
@@ -19,455 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as elements or name clobbering
-// one of these in the case of not jumping to the miss label.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-// The address returned from GenerateStringDictionaryProbes() in scratch2
-// is used.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal
- // property.
- __ bind(&done); // scratch2 == elements + 4 * index.
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ And(at, scratch1,
- Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
- __ Branch(miss, ne, at, Operand(zero_reg));
-
- // Get the value at the masked, scaled index and return.
- __ lw(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-// The address returned from GenerateStringDictionaryProbes() in scratch2
-// is used.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ bind(&done); // scratch2 == elements + 4 * index.
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- (PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY))
- << kSmiTagSize;
- __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
- __ Branch(miss, ne, at, Operand(zero_reg));
-
- // Store the value at the masked, scaled index and return.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
- __ sw(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ mov(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = a0;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ lw(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), v0, a3, t0);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return a3; }
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in ra.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, t0, t1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in ra.
-
- __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
- __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in ra.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, t0, t1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in ra.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = t0;
- Register scratch2 = t4;
- Register scratch3 = t5;
- Register address = t1;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, scratch2, scratch3, address));
-
- if (check_map == kCheckMap) {
- __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(fast_double, ne, elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element.
- Label holecheck_passed1;
- __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ lw(scratch, MemOperand(address));
- __ Branch(&holecheck_passed1, ne, scratch,
- Operand(masm->isolate()->factory()->the_hole_value()));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ sw(value, MemOperand(address));
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ sw(value, MemOperand(address));
- // Update write barrier for the elements array address.
- __ mov(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kRAHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
- __ Branch(slow, ne, elements_map, Operand(at));
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- __ Addu(address, elements, Operand(FixedDoubleArray::kHeaderSize +
- kHoleNanUpper32Offset - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2);
- __ lw(scratch, MemOperand(address));
- __ Branch(&fast_double_without_map_check, ne, scratch,
- Operand(kHoleNanUpper32));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, scratch2,
- scratch3, &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ lw(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- __ Branch(&non_double_value, ne, scratch, Operand(at));
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(value.is(a0));
- Register receiver_map = a3;
- Register elements_map = t2;
- Register elements = t3; // Elements array of the receiver.
- // t0 and t1 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
- __ Branch(&slow, ne, t0, Operand(zero_reg));
- // Check if the object is a JS array or not.
- __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ Branch(&slow, lo, t0, Operand(JS_OBJECT_TYPE));
-
- // Object case: Check key against length in the elements array.
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&fast_object, lo, key, Operand(t0));
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // a0: value.
- // a1: key.
- // a2: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ lw(t0, FieldMemOperand(key, HeapObject::kMapOffset));
- __ lb(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(t0, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, t1, t2, t4, t5));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ li(slot, Operand(Smi::FromInt(slot_index)));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, t1,
- t2, t4, t5);
- // Cache miss.
- __ Branch(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- // Only support writing to array[array.length].
- __ Branch(&slow, ne, key, Operand(t0));
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&slow, hs, key, Operand(t0));
- __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(&check_if_double_array, ne, elements_map,
- Heap::kFixedArrayMapRootIndex);
-
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ Branch(&extra, hs, key, Operand(t0));
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -491,40 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = t1;
- DCHECK(receiver.is(a1));
- DCHECK(name.is(a2));
- DCHECK(value.is(a0));
- DCHECK(StoreWithVectorDescriptor::VectorRegister().is(a3));
- DCHECK(StoreWithVectorDescriptor::SlotRegister().is(t0));
-
- __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, t2, t5);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, t2, t5);
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, t2, t5);
- GenerateMiss(masm);
-}
-
-
#undef __
diff --git a/deps/v8/src/ic/mips/stub-cache-mips.cc b/deps/v8/src/ic/mips/stub-cache-mips.cc
deleted file mode 100644
index d476c1e63e..0000000000
--- a/deps/v8/src/ic/mips/stub-cache-mips.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_MIPS
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register offset_scratch) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
- uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
- uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
-
- // Check the relative positions of the address fields.
- DCHECK(value_off_addr > key_off_addr);
- DCHECK((value_off_addr - key_off_addr) % 4 == 0);
- DCHECK((value_off_addr - key_off_addr) < (256 * 4));
- DCHECK(map_off_addr > key_off_addr);
- DCHECK((map_off_addr - key_off_addr) % 4 == 0);
- DCHECK((map_off_addr - key_off_addr) < (256 * 4));
-
- Label miss;
- Register base_addr = scratch;
- scratch = no_reg;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ Lsa(offset_scratch, offset, offset, 1);
-
- // Calculate the base address of the entry.
- __ li(base_addr, Operand(key_offset));
- __ Addu(base_addr, base_addr, offset_scratch);
-
- // Check that the key in the entry matches the name.
- __ lw(at, MemOperand(base_addr, 0));
- __ Branch(&miss, ne, name, Operand(at));
-
- // Check the map matches.
- __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
- __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Branch(&miss, ne, at, Operand(scratch2));
-
- // Get the code entry from the cache.
- Register code = scratch2;
- scratch2 = no_reg;
- __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
- __ Jump(at);
-
- // Miss: fall through.
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 12.
- DCHECK(sizeof(Entry) == 12);
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Check register validity.
- DCHECK(!scratch.is(no_reg));
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
- __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Addu(scratch, scratch, at);
- __ Xor(scratch, scratch, Operand(kPrimaryMagic));
- __ And(scratch, scratch,
- Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary probe.
- __ Subu(scratch, scratch, name);
- __ Addu(scratch, scratch, Operand(kSecondaryMagic));
- __ And(scratch, scratch,
- Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_MIPS
diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
index 249f8fedb3..06af88d19e 100644
--- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
+++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
@@ -129,14 +129,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ Daddu(sp, sp, Operand(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in ra register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in ra register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -181,18 +173,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ ld(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ ld(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -342,57 +322,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ li(this->name(), Operand(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ lwu(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ And(at, scratch, Operand(Map::Deprecated::kMask));
- __ Branch(miss, ne, at, Operand(zero_reg));
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ ld(scratch,
- FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ Branch(miss_label, ne, value_reg, Operand(scratch));
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ ld(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- // Compare map directly within the Branch() functions.
- __ GetWeakValue(scratch, Map::WeakCellForMap(field_type->AsClass()));
- __ Branch(miss_label, ne, map_reg, Operand(scratch));
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -520,14 +449,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ li(v0, value);
- __ Ret();
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/mips64/ic-compiler-mips64.cc b/deps/v8/src/ic/mips64/ic-compiler-mips64.cc
deleted file mode 100644
index 276f3afd38..0000000000
--- a/deps/v8/src/ic/mips64/ic-compiler-mips64.cc
+++ /dev/null
@@ -1,33 +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.
-
-#if V8_TARGET_ARCH_MIPS64
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister());
-
- __ li(a0, Operand(Smi::FromInt(language_mode)));
- __ Push(a0);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_MIPS64
diff --git a/deps/v8/src/ic/mips64/ic-mips64.cc b/deps/v8/src/ic/mips64/ic-mips64.cc
index 57efa350c8..fa351ba5a3 100644
--- a/deps/v8/src/ic/mips64/ic-mips64.cc
+++ b/deps/v8/src/ic/mips64/ic-mips64.cc
@@ -19,458 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as elements or name clobbering
-// one of these in the case of not jumping to the miss label.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-// The address returned from GenerateStringDictionaryProbes() in scratch2
-// is used.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal
- // property.
- __ bind(&done); // scratch2 == elements + 4 * index.
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ And(at, scratch1,
- Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
- __ Branch(miss, ne, at, Operand(zero_reg));
-
- // Get the value at the masked, scaled index and return.
- __ ld(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-// The address returned from GenerateStringDictionaryProbes() in scratch2
-// is used.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ bind(&done); // scratch2 == elements + 4 * index.
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- (PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY));
- __ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ And(at, scratch1, Operand(Smi::FromInt(kTypeAndReadOnlyMask)));
- __ Branch(miss, ne, at, Operand(zero_reg));
-
- // Store the value at the masked, scaled index and return.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ Daddu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
- __ sd(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ mov(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = a0;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
- Label slow;
-
- __ ld(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), v0, a3, a4);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return a3; }
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is on the stack.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(a4, a5, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, a4, a5);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in ra.
-
- __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
- __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in ra.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(a4, a5, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, a4, a5);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in ra.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = a4;
- Register scratch2 = t0;
- Register address = a5;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, scratch2, address));
-
- if (check_map == kCheckMap) {
- __ ld(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(fast_double, ne, elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element.
- Label holecheck_passed1;
- __ Daddu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
- __ SmiScale(at, key, kPointerSizeLog2);
- __ daddu(address, address, at);
- __ ld(scratch, MemOperand(address));
-
- __ Branch(&holecheck_passed1, ne, scratch,
- Operand(masm->isolate()->factory()->the_hole_value()));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Daddu(scratch, key, Operand(Smi::FromInt(1)));
- __ sd(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ Daddu(address, elements,
- Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiScale(scratch, key, kPointerSizeLog2);
- __ Daddu(address, address, scratch);
- __ sd(value, MemOperand(address));
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Daddu(scratch, key, Operand(Smi::FromInt(1)));
- __ sd(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Daddu(address, elements,
- Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiScale(scratch, key, kPointerSizeLog2);
- __ Daddu(address, address, scratch);
- __ sd(value, MemOperand(address));
- // Update write barrier for the elements array address.
- __ mov(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kRAHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
- __ Branch(slow, ne, elements_map, Operand(at));
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- __ Daddu(address, elements,
- Operand(FixedDoubleArray::kHeaderSize + Register::kExponentOffset -
- kHeapObjectTag));
- __ SmiScale(at, key, kPointerSizeLog2);
- __ daddu(address, address, at);
- __ lw(scratch, MemOperand(address));
- __ Branch(&fast_double_without_map_check, ne, scratch,
- Operand(static_cast<int32_t>(kHoleNanUpper32)));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, scratch2,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Daddu(scratch, key, Operand(Smi::FromInt(1)));
- __ sd(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ ld(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- __ Branch(&non_double_value, ne, scratch, Operand(at));
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(value.is(a0));
- Register receiver_map = a3;
- Register elements_map = a6;
- Register elements = a7; // Elements array of the receiver.
- // a4 and a5 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ lbu(a4, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ And(a4, a4, Operand(1 << Map::kIsAccessCheckNeeded));
- __ Branch(&slow, ne, a4, Operand(zero_reg));
- // Check if the object is a JS array or not.
- __ lbu(a4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ Branch(&array, eq, a4, Operand(JS_ARRAY_TYPE));
- // Check that the object is some kind of JSObject.
- __ Branch(&slow, lt, a4, Operand(FIRST_JS_OBJECT_TYPE));
-
- // Object case: Check key against length in the elements array.
- __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ ld(a4, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&fast_object, lo, key, Operand(a4));
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // a0: value.
- // a1: key.
- // a2: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ ld(a4, FieldMemOperand(key, HeapObject::kMapOffset));
- __ lb(a4, FieldMemOperand(a4, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(a4, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
-
- DCHECK(!AreAliased(vector, slot, a5, a6, a7, t0));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ li(slot, Operand(Smi::FromInt(slot_index)));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, a5,
- a6, a7, t0);
- // Cache miss.
- __ Branch(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- // Only support writing to array[array.length].
- __ Branch(&slow, ne, key, Operand(a4));
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ ld(a4, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&slow, hs, key, Operand(a4));
- __ ld(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(&check_if_double_array, ne, elements_map,
- Heap::kFixedArrayMapRootIndex);
-
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ ld(a4, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ Branch(&extra, hs, key, Operand(a4));
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -494,38 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = a5;
- DCHECK(!AreAliased(
- value, receiver, name, StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::SlotRegister(), dictionary, a6, a7));
-
- __ ld(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, a6, a7);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, a6, a7);
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, a6, a7);
- GenerateMiss(masm);
-}
-
-
#undef __
diff --git a/deps/v8/src/ic/mips64/stub-cache-mips64.cc b/deps/v8/src/ic/mips64/stub-cache-mips64.cc
deleted file mode 100644
index 6a87b7ba88..0000000000
--- a/deps/v8/src/ic/mips64/stub-cache-mips64.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_MIPS64
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register offset_scratch) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uint64_t key_off_addr = reinterpret_cast<uint64_t>(key_offset.address());
- uint64_t value_off_addr = reinterpret_cast<uint64_t>(value_offset.address());
- uint64_t map_off_addr = reinterpret_cast<uint64_t>(map_offset.address());
-
- // Check the relative positions of the address fields.
- DCHECK(value_off_addr > key_off_addr);
- DCHECK((value_off_addr - key_off_addr) % 4 == 0);
- DCHECK((value_off_addr - key_off_addr) < (256 * 4));
- DCHECK(map_off_addr > key_off_addr);
- DCHECK((map_off_addr - key_off_addr) % 4 == 0);
- DCHECK((map_off_addr - key_off_addr) < (256 * 4));
-
- Label miss;
- Register base_addr = scratch;
- scratch = no_reg;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ Dlsa(offset_scratch, offset, offset, 1);
-
- // Calculate the base address of the entry.
- __ li(base_addr, Operand(key_offset));
- __ Dlsa(base_addr, base_addr, offset_scratch,
- kPointerSizeLog2 - StubCache::kCacheIndexShift);
-
- // Check that the key in the entry matches the name.
- __ ld(at, MemOperand(base_addr, 0));
- __ Branch(&miss, ne, name, Operand(at));
-
- // Check the map matches.
- __ ld(at, MemOperand(base_addr,
- static_cast<int32_t>(map_off_addr - key_off_addr)));
- __ ld(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Branch(&miss, ne, at, Operand(scratch2));
-
- // Get the code entry from the cache.
- Register code = scratch2;
- scratch2 = no_reg;
- __ ld(code, MemOperand(base_addr,
- static_cast<int32_t>(value_off_addr - key_off_addr)));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ Daddu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
- __ Jump(at);
-
- // Miss: fall through.
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 12.
- // DCHECK(sizeof(Entry) == 12);
- // DCHECK(sizeof(Entry) == 3 * kPointerSize);
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Check register validity.
- DCHECK(!scratch.is(no_reg));
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ lwu(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
- __ ld(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Addu(scratch, scratch, at);
- __ Xor(scratch, scratch, Operand(kPrimaryMagic));
- __ And(scratch, scratch,
- Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary probe.
- __ Subu(scratch, scratch, name);
- __ Addu(scratch, scratch, kSecondaryMagic);
- __ And(scratch, scratch,
- Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_MIPS64
diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
index e0caaa6a1f..d4edcc1ec9 100644
--- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
+++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
@@ -130,14 +130,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ addi(sp, sp, Operand(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -184,18 +176,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ LoadP(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -350,58 +330,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ mov(this->name(), Operand(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ lwz(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ DecodeField<Map::Deprecated>(r0, scratch, SetRC);
- __ bne(miss, cr0);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ LoadP(scratch, FieldMemOperand(
- scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ cmp(value_reg, scratch);
- __ bne(miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ bne(miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -538,14 +466,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ Move(r3, value);
- __ Ret();
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/ppc/ic-compiler-ppc.cc b/deps/v8/src/ic/ppc/ic-compiler-ppc.cc
deleted file mode 100644
index c6b36f29f4..0000000000
--- a/deps/v8/src/ic/ppc/ic-compiler-ppc.cc
+++ /dev/null
@@ -1,31 +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.
-
-#if V8_TARGET_ARCH_PPC
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- __ mov(r0, Operand(Smi::FromInt(language_mode)));
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister(), r0);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_PPC
diff --git a/deps/v8/src/ic/ppc/ic-ppc.cc b/deps/v8/src/ic/ppc/ic-ppc.cc
index 359a6a42dd..3c325d8f92 100644
--- a/deps/v8/src/ic/ppc/ic-ppc.cc
+++ b/deps/v8/src/ic/ppc/ic-ppc.cc
@@ -19,187 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as elements or name clobbering
-// one of these in the case of not jumping to the miss label.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal
- // property.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ mr(r0, scratch2);
- __ LoadSmiLiteral(scratch2, Smi::FromInt(PropertyDetails::TypeField::kMask));
- __ and_(scratch2, scratch1, scratch2, SetRC);
- __ bne(miss, cr0);
- __ mr(scratch2, r0);
-
- // Get the value at the masked, scaled index and return.
- __ LoadP(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- int kTypeAndReadOnlyMask =
- PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY);
- __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ mr(r0, scratch2);
- __ LoadSmiLiteral(scratch2, Smi::FromInt(kTypeAndReadOnlyMask));
- __ and_(scratch2, scratch1, scratch2, SetRC);
- __ bne(miss, cr0);
- __ mr(scratch2, r0);
-
- // Store the value at the masked, scaled index and return.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ addi(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
- __ StoreP(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ mr(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = r3;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ LoadP(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), r3, r6, r7);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return r6; }
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r7, r8, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, r7, r8);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
- __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r7, r8, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, r7, r8);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -223,307 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = r7;
- Register address = r8;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, address));
-
- if (check_map == kCheckMap) {
- __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ mov(scratch, Operand(masm->isolate()->factory()->fixed_array_map()));
- __ cmp(elements_map, scratch);
- __ bne(fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ LoadPX(scratch, MemOperand(address, scratch));
- __ Cmpi(scratch, Operand(masm->isolate()->factory()->the_hole_value()), r0);
- __ bne(&holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset), r0);
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ StorePX(value, MemOperand(address, scratch));
- __ Ret();
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset), r0);
- }
- __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ StorePUX(value, MemOperand(address, scratch));
- // Update write barrier for the elements array address.
- __ mr(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kLRHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret();
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ bne(slow);
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- __ addi(address, elements,
- Operand((FixedDoubleArray::kHeaderSize + Register::kExponentOffset -
- kHeapObjectTag)));
- __ SmiToDoubleArrayOffset(scratch, key);
- __ lwzx(scratch, MemOperand(address, scratch));
- __ Cmpi(scratch, Operand(kHoleNanUpper32), r0);
- __ bne(&fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, d0,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset), r0);
- }
- __ Ret();
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- __ bne(&non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- r3 : value
- // -- r4 : key
- // -- r5 : receiver
- // -- lr : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(receiver.is(r4));
- DCHECK(key.is(r5));
- DCHECK(value.is(r3));
- Register receiver_map = r6;
- Register elements_map = r9;
- Register elements = r10; // Elements array of the receiver.
- // r7 and r8 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ lbz(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ andi(r0, ip, Operand(1 << Map::kIsAccessCheckNeeded));
- __ bne(&slow, cr0);
- // Check if the object is a JS array or not.
- __ lbz(r7, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ cmpi(r7, Operand(JS_ARRAY_TYPE));
- __ beq(&array);
- // Check that the object is some kind of JSObject.
- __ cmpi(r7, Operand(FIRST_JS_OBJECT_TYPE));
- __ blt(&slow);
-
- // Object case: Check key against length in the elements array.
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ cmpl(key, ip);
- __ blt(&fast_object);
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // r3: value.
- // r4: key.
- // r5: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ LoadP(r7, FieldMemOperand(key, HeapObject::kMapOffset));
- __ lbz(r7, FieldMemOperand(r7, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(r7, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, r8, r9, r10, r11));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r8,
- r9, r10, r11);
- // Cache miss.
- __ b(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- __ bne(&slow); // Only support writing to writing to array[array.length].
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ cmpl(key, ip);
- __ bge(&slow);
- __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ mov(ip, Operand(masm->isolate()->factory()->fixed_array_map()));
- __ cmp(elements_map, ip); // PPC - I think I can re-use ip here
- __ bne(&check_if_double_array);
- __ b(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ mov(ip, Operand(masm->isolate()->factory()->fixed_double_array_map()));
- __ cmp(elements_map, ip); // PPC - another ip re-use
- __ bne(&slow);
- __ b(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ LoadP(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ cmpl(key, ip);
- __ bge(&extra);
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = r8;
- DCHECK(receiver.is(r4));
- DCHECK(name.is(r5));
- DCHECK(value.is(r3));
- DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r6));
- DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r7));
-
- __ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, r9, r10);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, r9, r10);
- __ Ret();
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, r9, r10);
- GenerateMiss(masm);
-}
-
-
#undef __
diff --git a/deps/v8/src/ic/ppc/stub-cache-ppc.cc b/deps/v8/src/ic/ppc/stub-cache-ppc.cc
deleted file mode 100644
index 3dad306f11..0000000000
--- a/deps/v8/src/ic/ppc/stub-cache-ppc.cc
+++ /dev/null
@@ -1,176 +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.
-
-#if V8_TARGET_ARCH_PPC
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register offset_scratch) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
- uintptr_t value_off_addr =
- reinterpret_cast<uintptr_t>(value_offset.address());
- uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address());
-
- // Check the relative positions of the address fields.
- DCHECK(value_off_addr > key_off_addr);
- DCHECK((value_off_addr - key_off_addr) % 4 == 0);
- DCHECK((value_off_addr - key_off_addr) < (256 * 4));
- DCHECK(map_off_addr > key_off_addr);
- DCHECK((map_off_addr - key_off_addr) % 4 == 0);
- DCHECK((map_off_addr - key_off_addr) < (256 * 4));
-
- Label miss;
- Register base_addr = scratch;
- scratch = no_reg;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ ShiftLeftImm(offset_scratch, offset, Operand(1));
- __ add(offset_scratch, offset, offset_scratch);
-
- // Calculate the base address of the entry.
- __ mov(base_addr, Operand(key_offset));
-#if V8_TARGET_ARCH_PPC64
- DCHECK(kPointerSizeLog2 > StubCache::kCacheIndexShift);
- __ ShiftLeftImm(offset_scratch, offset_scratch,
- Operand(kPointerSizeLog2 - StubCache::kCacheIndexShift));
-#else
- DCHECK(kPointerSizeLog2 == StubCache::kCacheIndexShift);
-#endif
- __ add(base_addr, base_addr, offset_scratch);
-
- // Check that the key in the entry matches the name.
- __ LoadP(ip, MemOperand(base_addr, 0));
- __ cmp(name, ip);
- __ bne(&miss);
-
- // Check the map matches.
- __ LoadP(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
- __ LoadP(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ cmp(ip, scratch2);
- __ bne(&miss);
-
- // Get the code entry from the cache.
- Register code = scratch2;
- scratch2 = no_reg;
- __ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ b(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ b(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ addi(r0, code, Operand(Code::kHeaderSize - kHeapObjectTag));
- __ mtctr(r0);
- __ bctr();
-
- // Miss: fall through.
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
-#if V8_TARGET_ARCH_PPC64
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 24.
- DCHECK(sizeof(Entry) == 24);
-#else
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 12.
- DCHECK(sizeof(Entry) == 12);
-#endif
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Check scratch, extra and extra2 registers are valid.
- DCHECK(!scratch.is(no_reg));
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ lwz(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
- __ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ add(scratch, scratch, ip);
- __ Xor(scratch, scratch, Operand(kPrimaryMagic));
- // The mask omits the last two bits because they are not part of the hash.
- __ andi(scratch, scratch,
- Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary probe.
- __ sub(scratch, scratch, name);
- __ Add(scratch, scratch, kSecondaryMagic, r0);
- __ andi(scratch, scratch,
- Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_PPC
diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc
index 72658ec1d1..40a8c310d8 100644
--- a/deps/v8/src/ic/s390/handler-compiler-s390.cc
+++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc
@@ -125,14 +125,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ la(sp, MemOperand(sp, 2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- // No-op. Return address is in lr register.
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -177,16 +169,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ LoadP(result,
- FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
-}
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -335,54 +317,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ mov(this->name(), Operand(name));
-}
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ LoadlW(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
- __ DecodeField<Map::Deprecated>(r0, scratch);
- __ bne(miss);
- }
-}
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ CmpP(value_reg, FieldMemOperand(
- scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ bne(miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ LoadP(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ bne(miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -512,12 +446,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ Move(r2, value);
- __ Ret();
-}
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/s390/ic-compiler-s390.cc b/deps/v8/src/ic/s390/ic-compiler-s390.cc
deleted file mode 100644
index a7691d83c5..0000000000
--- a/deps/v8/src/ic/s390/ic-compiler-s390.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 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.
-
-#if V8_TARGET_ARCH_S390
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- __ mov(r0, Operand(Smi::FromInt(language_mode)));
- __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
- StoreDescriptor::ValueRegister(), r0);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_S390
diff --git a/deps/v8/src/ic/s390/ic-s390.cc b/deps/v8/src/ic/s390/ic-s390.cc
index bd83af1f59..6438cfca47 100644
--- a/deps/v8/src/ic/s390/ic-s390.cc
+++ b/deps/v8/src/ic/s390/ic-s390.cc
@@ -18,182 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used from LoadIC GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as elements or name clobbering
-// one of these in the case of not jumping to the miss label.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register result, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry check that the value is a normal
- // property.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ LoadRR(r0, scratch2);
- __ LoadSmiLiteral(scratch2, Smi::FromInt(PropertyDetails::TypeField::kMask));
- __ AndP(scratch2, scratch1);
- __ bne(miss);
- __ LoadRR(scratch2, r0);
-
- // Get the value at the masked, scaled index and return.
- __ LoadP(result,
- FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
-}
-
-// Helper function used from StoreIC::GenerateNormal.
-//
-// elements: Property dictionary. It is not clobbered if a jump to the miss
-// label is done.
-// name: Property name. It is not clobbered if a jump to the miss label is
-// done
-// value: The value to store.
-// The two scratch registers need to be different from elements, name and
-// result.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
- Register elements, Register name,
- Register value, Register scratch1,
- Register scratch2) {
- // Main use of the scratch registers.
- // scratch1: Used as temporary and to hold the capacity of the property
- // dictionary.
- // scratch2: Used as temporary.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
- name, scratch1, scratch2);
-
- // If probing finds an entry in the dictionary check that the value
- // is a normal property that is not read only.
- __ bind(&done); // scratch2 == elements + 4 * index
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- int kTypeAndReadOnlyMask =
- PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY);
- __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ LoadRR(r0, scratch2);
- __ LoadSmiLiteral(scratch2, Smi::FromInt(kTypeAndReadOnlyMask));
- __ AndP(scratch2, scratch1);
- __ bne(miss /*, cr0*/);
- __ LoadRR(scratch2, r0);
-
- // Store the value at the masked, scaled index and return.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ AddP(scratch2, Operand(kValueOffset - kHeapObjectTag));
- __ StoreP(value, MemOperand(scratch2));
-
- // Update the write barrier. Make sure not to clobber the value.
- __ LoadRR(scratch1, value);
- __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
- kDontSaveFPRegs);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = r2;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ LoadP(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), r2, r5, r6);
- __ Ret();
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return r5; }
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r6, r7, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, r6, r7);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ LoadRR(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
- __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in lr.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(r6, r7, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, r6, r7);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in lr.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@@ -216,303 +40,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = r6;
- Register address = r7;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, address));
-
- if (check_map == kCheckMap) {
- __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ CmpP(elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- __ bne(fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- // @TODO(joransiu) : Fold AddP into memref of LoadP
- __ AddP(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ LoadP(scratch, MemOperand(address, scratch));
- __ CmpP(scratch, Operand(masm->isolate()->factory()->the_hole_value()));
- __ bne(&holecheck_passed1, Label::kNear);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ AddP(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ StoreP(value, MemOperand(address, scratch));
- __ Ret();
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ AddP(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ SmiToPtrArrayOffset(scratch, key);
- __ StoreP(value, MemOperand(address, scratch));
- __ la(address, MemOperand(address, scratch));
- // Update write barrier for the elements array address.
- __ LoadRR(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kLRHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret();
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ bne(slow);
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- // @TODO(joransiu) : Fold AddP Operand into LoadlW
- __ AddP(address, elements,
- Operand((FixedDoubleArray::kHeaderSize + Register::kExponentOffset -
- kHeapObjectTag)));
- __ SmiToDoubleArrayOffset(scratch, key);
- __ LoadlW(scratch, MemOperand(address, scratch));
- __ CmpP(scratch, Operand(kHoleNanUpper32));
- __ bne(&fast_double_without_map_check, Label::kNear);
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, d0,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ AddSmiLiteral(scratch, key, Smi::FromInt(1), r0);
- __ StoreP(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret();
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- __ bne(&non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ b(&finish_object_store);
-}
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- r2 : value
- // -- r3 : key
- // -- r4 : receiver
- // -- lr : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(receiver.is(r3));
- DCHECK(key.is(r4));
- DCHECK(value.is(r2));
- Register receiver_map = r5;
- Register elements_map = r8;
- Register elements = r9; // Elements array of the receiver.
- // r6 and r7 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ LoadlB(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ AndP(r0, ip, Operand(1 << Map::kIsAccessCheckNeeded));
- __ bne(&slow, Label::kNear);
- // Check if the object is a JS array or not.
- __ LoadlB(r6, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ CmpP(r6, Operand(JS_ARRAY_TYPE));
- __ beq(&array);
- // Check that the object is some kind of JSObject.
- __ CmpP(r6, Operand(FIRST_JS_OBJECT_TYPE));
- __ blt(&slow, Label::kNear);
-
- // Object case: Check key against length in the elements array.
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ CmpLogicalP(key, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ blt(&fast_object);
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // r2: value.
- // r3: key.
- // r4: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ LoadP(r6, FieldMemOperand(key, HeapObject::kMapOffset));
- __ LoadlB(r6, FieldMemOperand(r6, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(r6, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, r7, r8, r9, ip));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r7,
- r8, r9, ip);
- // Cache miss.
- __ b(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- __ bne(&slow); // Only support writing to writing to array[array.length].
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ CmpLogicalP(key, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ bge(&slow);
- __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ CmpP(elements_map, Operand(masm->isolate()->factory()->fixed_array_map()));
- __ bne(&check_if_double_array, Label::kNear);
- __ b(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ CmpP(elements_map,
- Operand(masm->isolate()->factory()->fixed_double_array_map()));
- __ bne(&slow);
- __ b(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ CmpLogicalP(key, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ bge(&extra);
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Label miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = r7;
- DCHECK(receiver.is(r3));
- DCHECK(name.is(r4));
- DCHECK(value.is(r2));
- DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r5));
- DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r6));
-
- __ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1, r8, r9);
- __ Ret();
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1, r8, r9);
- GenerateMiss(masm);
-}
-
#undef __
Condition CompareIC::ComputeCondition(Token::Value op) {
@@ -624,13 +151,13 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
cc = static_cast<Condition>((branch_instr & 0x00f00000) >> 20);
DCHECK((cc == ne) || (cc == eq));
cc = (cc == ne) ? eq : ne;
- patcher.masm()->brc(cc, Operand((branch_instr & 0xffff) << 1));
+ patcher.masm()->brc(cc, Operand(branch_instr & 0xffff));
} else if (Instruction::S390OpcodeValue(branch_address) == BRCL) {
cc = static_cast<Condition>(
(branch_instr & (static_cast<uint64_t>(0x00f0) << 32)) >> 36);
DCHECK((cc == ne) || (cc == eq));
cc = (cc == ne) ? eq : ne;
- patcher.masm()->brcl(cc, Operand((branch_instr & 0xffffffff) << 1));
+ patcher.masm()->brcl(cc, Operand(branch_instr & 0xffffffff));
} else {
DCHECK(false);
}
diff --git a/deps/v8/src/ic/s390/stub-cache-s390.cc b/deps/v8/src/ic/s390/stub-cache-s390.cc
deleted file mode 100644
index a0564a3be3..0000000000
--- a/deps/v8/src/ic/s390/stub-cache-s390.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2015 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.
-
-#if V8_TARGET_ARCH_S390
-
-#include "src/ic/stub-cache.h"
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register scratch, Register scratch2,
- Register offset_scratch) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
- uintptr_t value_off_addr =
- reinterpret_cast<uintptr_t>(value_offset.address());
- uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address());
-
- // Check the relative positions of the address fields.
- DCHECK(value_off_addr > key_off_addr);
- DCHECK((value_off_addr - key_off_addr) % 4 == 0);
- DCHECK((value_off_addr - key_off_addr) < (256 * 4));
- DCHECK(map_off_addr > key_off_addr);
- DCHECK((map_off_addr - key_off_addr) % 4 == 0);
- DCHECK((map_off_addr - key_off_addr) < (256 * 4));
-
- Label miss;
- Register base_addr = scratch;
- scratch = no_reg;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ ShiftLeftP(offset_scratch, offset, Operand(1));
- __ AddP(offset_scratch, offset, offset_scratch);
-
- // Calculate the base address of the entry.
- __ mov(base_addr, Operand(key_offset));
-#if V8_TARGET_ARCH_S390X
- DCHECK(kPointerSizeLog2 > StubCache::kCacheIndexShift);
- __ ShiftLeftP(offset_scratch, offset_scratch,
- Operand(kPointerSizeLog2 - StubCache::kCacheIndexShift));
-#else
- DCHECK(kPointerSizeLog2 == StubCache::kCacheIndexShift);
-#endif
- __ AddP(base_addr, base_addr, offset_scratch);
-
- // Check that the key in the entry matches the name.
- __ CmpP(name, MemOperand(base_addr, 0));
- __ bne(&miss, Label::kNear);
-
- // Check the map matches.
- __ LoadP(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
- __ CmpP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ bne(&miss, Label::kNear);
-
- // Get the code entry from the cache.
- Register code = scratch2;
- scratch2 = no_reg;
- __ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ b(&miss, Label::kNear);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ b(&miss, Label::kNear);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- // TODO(joransiu): Combine into indirect branch
- __ la(code, MemOperand(code, Code::kHeaderSize - kHeapObjectTag));
- __ b(code);
-
- // Miss: fall through.
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
-#if V8_TARGET_ARCH_S390X
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 24.
- DCHECK(sizeof(Entry) == 24);
-#else
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 12.
- DCHECK(sizeof(Entry) == 12);
-#endif
-
- // Make sure that there are no register conflicts.
- DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
-
- // Check scratch, extra and extra2 registers are valid.
- DCHECK(!scratch.is(no_reg));
- DCHECK(!extra.is(no_reg));
- DCHECK(!extra2.is(no_reg));
- DCHECK(!extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch, extra, extra2 and
- // extra3 don't conflict with the vector and slot registers, which need
- // to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- Register vector, slot;
- if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
- vector = StoreWithVectorDescriptor::VectorRegister();
- slot = StoreWithVectorDescriptor::SlotRegister();
- } else {
- DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
- vector = LoadWithVectorDescriptor::VectorRegister();
- slot = LoadWithVectorDescriptor::SlotRegister();
- }
- DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
- extra3);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ LoadlW(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
- __ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ AddP(scratch, scratch, ip);
- __ XorP(scratch, scratch, Operand(kPrimaryMagic));
- // The mask omits the last two bits because they are not part of the hash.
- __ AndP(scratch, scratch,
- Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Primary miss: Compute hash for secondary probe.
- __ SubP(scratch, scratch, name);
- __ AddP(scratch, scratch, Operand(kSecondaryMagic));
- __ AndP(scratch, scratch,
- Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
- extra3);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
- extra3);
-}
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_S390
diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h
index bdd7f4a3be..e8df26d37b 100644
--- a/deps/v8/src/ic/stub-cache.h
+++ b/deps/v8/src/ic/stub-cache.h
@@ -48,13 +48,6 @@ class StubCache {
// Collect all maps that match the name.
void CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
Handle<Context> native_context, Zone* zone);
- // Generate code for probing the stub cache table.
- // Arguments extra, extra2 and extra3 may be used to pass additional scratch
- // registers. Set to no_reg if not needed.
- // If leave_frame is true, then exit a frame before the tail call.
- void GenerateProbe(MacroAssembler* masm, Register receiver, Register name,
- Register scratch, Register extra, Register extra2 = no_reg,
- Register extra3 = no_reg);
enum Table { kPrimary, kSecondary };
diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc
index 36acccc007..a89afa8a7e 100644
--- a/deps/v8/src/ic/x64/handler-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc
@@ -44,16 +44,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ addp(rsp, Immediate(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ Push(tmp);
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ Pop(tmp);
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -93,18 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadNativeContextSlot(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ movp(result,
- FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register result, Register scratch,
Label* miss_label) {
@@ -348,59 +326,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ Move(this->name(), name);
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
- __ andl(scratch, Immediate(Map::Deprecated::kMask));
- __ j(not_zero, miss);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ movp(scratch,
- FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ cmpp(value_reg, scratch);
- __ j(not_equal, miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- Label do_store;
- __ movp(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ j(not_equal, miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -533,13 +458,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ Move(rax, value);
- __ ret(0);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/x64/ic-compiler-x64.cc b/deps/v8/src/ic/x64/ic-compiler-x64.cc
deleted file mode 100644
index 9d734338bb..0000000000
--- a/deps/v8/src/ic/x64/ic-compiler-x64.cc
+++ /dev/null
@@ -1,39 +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.
-
-#if V8_TARGET_ARCH_X64
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- // Return address is on the stack.
- DCHECK(!rbx.is(StoreDescriptor::ReceiverRegister()) &&
- !rbx.is(StoreDescriptor::NameRegister()) &&
- !rbx.is(StoreDescriptor::ValueRegister()));
-
- __ PopReturnAddressTo(rbx);
- __ Push(StoreDescriptor::ReceiverRegister());
- __ Push(StoreDescriptor::NameRegister());
- __ Push(StoreDescriptor::ValueRegister());
- __ Push(Smi::FromInt(language_mode));
- __ PushReturnAddressFrom(rbx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_X64
diff --git a/deps/v8/src/ic/x64/ic-x64.cc b/deps/v8/src/ic/x64/ic-x64.cc
index a916e22fa5..587ebd3daa 100644
--- a/deps/v8/src/ic/x64/ic-x64.cc
+++ b/deps/v8/src/ic/x64/ic-x64.cc
@@ -18,450 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used to load a property from a dictionary backing storage.
-// This function may return false negatives, so miss_label
-// must always call a backup property load that is complete.
-// This function is safe to call if name is not an internalized string,
-// and will jump to the miss_label in that case.
-// The generated code assumes that the receiver has slow properties,
-// is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register r0, Register r1, Register result) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is unchanged.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // r0 - used to hold the capacity of the property dictionary.
- //
- // r1 - used to hold the index into the property dictionary.
- //
- // result - holds the result on exit if the load succeeded.
-
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
- elements, name, r0, r1);
-
- // If probing finds an entry in the dictionary, r1 contains the
- // index into the dictionary. Check that the value is a normal
- // property.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ Test(Operand(elements, r1, times_pointer_size,
- kDetailsOffset - kHeapObjectTag),
- Smi::FromInt(PropertyDetails::TypeField::kMask));
- __ j(not_zero, miss_label);
-
- // Get the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ movp(result, Operand(elements, r1, times_pointer_size,
- kValueOffset - kHeapObjectTag));
-}
-
-
-// Helper function used to store a property to a dictionary backing
-// storage. This function may fail to store a property even though it
-// is in the dictionary, so code at miss_label must always call a
-// backup property store that is complete. This function is safe to
-// call if name is not an internalized string, and will jump to the miss_label
-// in that case. The generated code assumes that the receiver has slow
-// properties, is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register value, Register scratch0,
- Register scratch1) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is clobbered.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // value - holds the value to store and is unchanged.
- //
- // scratch0 - used during the positive dictionary lookup and is clobbered.
- //
- // scratch1 - used for index into the property dictionary and is clobbered.
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(
- masm, miss_label, &done, elements, name, scratch0, scratch1);
-
- // If probing finds an entry in the dictionary, scratch0 contains the
- // index into the dictionary. Check that the value is a normal
- // property that is not read only.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY);
- __ Test(Operand(elements, scratch1, times_pointer_size,
- kDetailsOffset - kHeapObjectTag),
- Smi::FromInt(kTypeAndReadOnlyMask));
- __ j(not_zero, miss_label);
-
- // Store the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ leap(scratch1, Operand(elements, scratch1, times_pointer_size,
- kValueOffset - kHeapObjectTag));
- __ movp(Operand(scratch1, 0), value);
-
- // Update write barrier. Make sure not to clobber the value.
- __ movp(scratch0, value);
- __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register key = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- DCHECK(receiver.is(rdx));
- DCHECK(key.is(rcx));
- DCHECK(value.is(rax));
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- // rbx: receiver's elements array (a FixedArray)
- // receiver is a JSArray.
- // r9: map of receiver
- if (check_map == kCheckMap) {
- __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
- __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- __ movp(kScratchRegister,
- FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize));
- __ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ leal(rdi, Operand(key, 1));
- __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize),
- value);
- __ ret(0);
-
- __ bind(&non_smi_value);
- // Writing a non-smi, check whether array allows non-smi elements.
- // r9: receiver's map
- __ CheckFastObjectElements(r9, &transition_smi_elements);
-
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ leal(rdi, Operand(key, 1));
- __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
- }
- __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize),
- value);
- __ movp(rdx, value); // Preserve the value which is returned.
- __ RecordWriteArray(rbx, rdx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ ret(0);
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- // rdi: elements array's map
- __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
- __ j(not_equal, slow);
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmpl(FieldOperand(rbx, key, times_8, offset), Immediate(kHoleNanUpper32));
- __ j(not_equal, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, rbx, key, kScratchDoubleReg,
- &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ leal(rdi, Operand(key, 1));
- __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
- }
- __ ret(0);
-
- __ bind(&transition_smi_elements);
- __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset));
-
- // Transition the array appropriately depending on the value type.
- __ movp(r9, FieldOperand(value, HeapObject::kMapOffset));
- __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
- __ j(not_equal, &non_double_value);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS, rbx, rdi, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- rbx, mode, slow);
- __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, rbx,
- rdi, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, rbx, mode, slow);
- __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- rbx, rdi, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, receiver, key,
- value, rbx, mode, slow);
- __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // Return address is on the stack.
- Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register key = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(rdx));
- DCHECK(key.is(rcx));
-
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow_with_tagged_index);
- // Get the map from the receiver.
- __ movp(r9, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ testb(FieldOperand(r9, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &slow_with_tagged_index);
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- __ SmiToInteger32(key, key);
-
- __ CmpInstanceType(r9, JS_ARRAY_TYPE);
- __ j(equal, &array);
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ CmpInstanceType(r9, JS_OBJECT_TYPE);
- __ j(below, &slow);
-
- // Object case: Check key against length in the elements array.
- __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds.
- __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key);
- // rbx: FixedArray
- __ j(above, &fast_object);
-
- // Slow case: call runtime.
- __ bind(&slow);
- __ Integer32ToSmi(key, key);
- __ bind(&slow_with_tagged_index);
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ movp(r9, FieldOperand(key, HeapObject::kMapOffset));
- __ movzxbp(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(r9, &slow_with_tagged_index);
-
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ Move(vector, dummy_vector);
- __ Move(slot, Smi::FromInt(slot_index));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r9,
- no_reg);
- // Cache miss.
- __ jmp(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // receiver is a JSArray.
- // rbx: receiver's elements array (a FixedArray)
- // flags: smicompare (receiver.length(), rbx)
- __ j(not_equal, &slow); // do not leave holes in the array
- __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key);
- __ j(below_equal, &slow);
- // Increment index to get new length.
- __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
- __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, &check_if_double_array);
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- // rdi: elements array's map
- __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
- __ j(not_equal, &slow);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- // receiver is a JSArray.
- __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array, compute the
- // address to store into and fall through to fast case.
- __ SmiCompareInteger32(FieldOperand(receiver, JSArray::kLengthOffset), key);
- __ j(below_equal, &extra);
-
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
- kCheckMap, kDontIncrementLength);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = rax;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ movp(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), rbx, rdi, rax);
- __ ret(0);
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- LoadIC::GenerateRuntimeGetProperty(masm);
-}
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
- DCHECK(!rdi.is(receiver) && !rdi.is(name) && !rdi.is(slot) &&
- !rdi.is(vector));
-
- __ PopReturnAddressTo(rdi);
- __ Push(receiver);
- __ Push(name);
- __ Push(slot);
- __ Push(vector);
- __ PushReturnAddressFrom(rdi);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is on the stack.
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_load_miss(), 1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
-
- DCHECK(!rbx.is(receiver) && !rbx.is(name));
-
- __ PopReturnAddressTo(rbx);
- __ Push(receiver);
- __ Push(name);
- __ PushReturnAddressFrom(rbx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is on the stack.
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_keyed_load_miss(), 1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
-
- DCHECK(!rbx.is(receiver) && !rbx.is(name));
-
- __ PopReturnAddressTo(rbx);
- __ Push(receiver);
- __ Push(name);
- __ PushReturnAddressFrom(rbx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@@ -480,38 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ PushReturnAddressFrom(temp);
}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- Register dictionary = r11;
- DCHECK(!AreAliased(dictionary, StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::SlotRegister()));
-
- Label miss;
-
- __ movp(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
- GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1);
- __ ret(0);
-
- __ bind(&miss);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1);
- GenerateMiss(masm);
-}
-
-
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
diff --git a/deps/v8/src/ic/x64/stub-cache-x64.cc b/deps/v8/src/ic/x64/stub-cache-x64.cc
deleted file mode 100644
index 946aee51fc..0000000000
--- a/deps/v8/src/ic/x64/stub-cache-x64.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_X64
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register receiver, Register name,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset) {
- // We need to scale up the pointer by 2 when the offset is scaled by less
- // than the pointer size.
- DCHECK(kPointerSize == kInt64Size
- ? kPointerSizeLog2 == StubCache::kCacheIndexShift + 1
- : kPointerSizeLog2 == StubCache::kCacheIndexShift);
- ScaleFactor scale_factor = kPointerSize == kInt64Size ? times_2 : times_1;
-
- DCHECK_EQ(3u * kPointerSize, sizeof(StubCache::Entry));
- // The offset register holds the entry offset times four (due to masking
- // and shifting optimizations).
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- Label miss;
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ leap(offset, Operand(offset, offset, times_2, 0));
-
- __ LoadAddress(kScratchRegister, key_offset);
-
- // Check that the key in the entry matches the name.
- __ cmpp(name, Operand(kScratchRegister, offset, scale_factor, 0));
- __ j(not_equal, &miss);
-
- // Get the map entry from the cache.
- // Use key_offset + kPointerSize * 2, rather than loading map_offset.
- DCHECK(stub_cache->map_reference(table).address() -
- stub_cache->key_reference(table).address() ==
- kPointerSize * 2);
- __ movp(kScratchRegister,
- Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
- __ cmpp(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
- __ j(not_equal, &miss);
-
- // Get the code entry from the cache.
- __ LoadAddress(kScratchRegister, value_offset);
- __ movp(kScratchRegister, Operand(kScratchRegister, offset, scale_factor, 0));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Jump to the first instruction in the code stub.
- __ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(kScratchRegister);
-
- __ bind(&miss);
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
- USE(extra); // The register extra is not used on the X64 platform.
- USE(extra2); // The register extra2 is not used on the X64 platform.
- USE(extra3); // The register extra2 is not used on the X64 platform.
- // Make sure that code is valid. The multiplying code relies on the
- // entry size being 3 * kPointerSize.
- DCHECK(sizeof(Entry) == 3 * kPointerSize);
-
- // Make sure that there are no register conflicts.
- DCHECK(!scratch.is(receiver));
- DCHECK(!scratch.is(name));
-
- // Check scratch register is valid, extra and extra2 are unused.
- DCHECK(!scratch.is(no_reg));
- DCHECK(extra2.is(no_reg));
- DCHECK(extra3.is(no_reg));
-
-#ifdef DEBUG
- // If vector-based ics are in use, ensure that scratch doesn't conflict with
- // the vector and slot registers, which need to be preserved for a handler
- // call or miss.
- if (IC::ICUseVector(ic_kind_)) {
- if (ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC) {
- Register vector = LoadWithVectorDescriptor::VectorRegister();
- Register slot = LoadDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, scratch));
- } else {
- DCHECK(ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC);
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, scratch));
- }
- }
-#endif
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
- // Use only the low 32 bits of the map pointer.
- __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xorp(scratch, Immediate(kPrimaryMagic));
- // We mask out the last two bits because they are not part of the hash and
- // they are always 01 for maps. Also in the two 'and' instructions below.
- __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, receiver, name, scratch);
-
- // Primary miss: Compute hash for secondary probe.
- __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
- __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xorp(scratch, Immediate(kPrimaryMagic));
- __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
- __ subl(scratch, name);
- __ addl(scratch, Immediate(kSecondaryMagic));
- __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, receiver, name, scratch);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_X64
diff --git a/deps/v8/src/ic/x87/OWNERS b/deps/v8/src/ic/x87/OWNERS
index dd9998b261..61245ae8e2 100644
--- a/deps/v8/src/ic/x87/OWNERS
+++ b/deps/v8/src/ic/x87/OWNERS
@@ -1 +1,2 @@
weiliang.lin@intel.com
+chunyang.dai@intel.com
diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc
index a5c32d37cc..4a521b76d3 100644
--- a/deps/v8/src/ic/x87/handler-compiler-x87.cc
+++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc
@@ -83,16 +83,6 @@ void PropertyHandlerCompiler::DiscardVectorAndSlot() {
__ add(esp, Immediate(2 * kPointerSize));
}
-void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ push(tmp);
-}
-
-void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
- MacroAssembler* masm = this->masm();
- __ pop(tmp);
-}
-
void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
MacroAssembler* masm, Label* miss_label, Register receiver,
Handle<Name> name, Register scratch0, Register scratch1) {
@@ -132,18 +122,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-
-void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register result, Label* miss) {
- __ LoadGlobalFunction(index, result);
- // Load its initial map. The global functions all have initial maps.
- __ mov(result,
- FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
MacroAssembler* masm, Register receiver, Register scratch1,
Register scratch2, Label* miss_label) {
@@ -359,58 +337,6 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
}
}
-
-void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
- __ mov(this->name(), Immediate(name));
-}
-
-
-void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
- Register map_reg,
- Register scratch,
- Label* miss) {
- Handle<WeakCell> cell = Map::WeakCellForMap(transition);
- DCHECK(!map_reg.is(scratch));
- __ LoadWeakValue(map_reg, cell, miss);
- if (transition->CanBeDeprecated()) {
- __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
- __ and_(scratch, Immediate(Map::Deprecated::kMask));
- __ j(not_zero, miss);
- }
-}
-
-
-void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
- int descriptor,
- Register value_reg,
- Register scratch,
- Label* miss_label) {
- DCHECK(!map_reg.is(scratch));
- DCHECK(!map_reg.is(value_reg));
- DCHECK(!value_reg.is(scratch));
- __ LoadInstanceDescriptors(map_reg, scratch);
- __ mov(scratch,
- FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
- __ cmp(value_reg, scratch);
- __ j(not_equal, miss_label);
-}
-
-void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
- Register value_reg,
- Label* miss_label) {
- Register map_reg = scratch1();
- Register scratch = scratch2();
- DCHECK(!value_reg.is(map_reg));
- DCHECK(!value_reg.is(scratch));
- __ JumpIfSmi(value_reg, miss_label);
- if (field_type->IsClass()) {
- __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
- __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
- scratch);
- __ j(not_equal, miss_label);
- }
-}
-
void PropertyHandlerCompiler::GenerateAccessCheck(
Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
Label* miss, bool compare_native_contexts_only) {
@@ -540,14 +466,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
- // Return the constant value.
- __ LoadObject(eax, value);
- __ ret(0);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
diff --git a/deps/v8/src/ic/x87/ic-compiler-x87.cc b/deps/v8/src/ic/x87/ic-compiler-x87.cc
deleted file mode 100644
index 11a8cdcd34..0000000000
--- a/deps/v8/src/ic/x87/ic-compiler-x87.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_X87
-
-#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-
-void PropertyICCompiler::GenerateRuntimeSetProperty(
- MacroAssembler* masm, LanguageMode language_mode) {
- typedef StoreWithVectorDescriptor Descriptor;
- STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
- // ----------- S t a t e -------------
- // -- esp[12] : value
- // -- esp[8] : slot
- // -- esp[4] : vector
- // -- esp[0] : return address
- // -----------------------------------
- __ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
- Descriptor::kValue);
-
- __ mov(Operand(esp, 12), Descriptor::ReceiverRegister());
- __ mov(Operand(esp, 8), Descriptor::NameRegister());
- __ mov(Operand(esp, 4), Descriptor::ValueRegister());
- __ pop(ebx);
- __ push(Immediate(Smi::FromInt(language_mode)));
- __ push(ebx); // return address
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_X87
diff --git a/deps/v8/src/ic/x87/ic-x87.cc b/deps/v8/src/ic/x87/ic-x87.cc
index f96e509f53..049a85e92e 100644
--- a/deps/v8/src/ic/x87/ic-x87.cc
+++ b/deps/v8/src/ic/x87/ic-x87.cc
@@ -18,440 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-// Helper function used to load a property from a dictionary backing
-// storage. This function may fail to load a property even though it is
-// in the dictionary, so code at miss_label must always call a backup
-// property load that is complete. This function is safe to call if
-// name is not internalized, and will jump to the miss_label in that
-// case. The generated code assumes that the receiver has slow
-// properties, is not a global object and does not have interceptors.
-static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register r0, Register r1, Register result) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is unchanged.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // Scratch registers:
- //
- // r0 - used for the index into the property dictionary
- //
- // r1 - used to hold the capacity of the property dictionary.
- //
- // result - holds the result on exit.
-
- Label done;
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
- elements, name, r0, r1);
-
- // If probing finds an entry in the dictionary, r0 contains the
- // index into the dictionary. Check that the value is a normal
- // property.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
- __ j(not_zero, miss_label);
-
- // Get the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
-}
-
-
-// Helper function used to store a property to a dictionary backing
-// storage. This function may fail to store a property eventhough it
-// is in the dictionary, so code at miss_label must always call a
-// backup property store that is complete. This function is safe to
-// call if name is not internalized, and will jump to the miss_label in
-// that case. The generated code assumes that the receiver has slow
-// properties, is not a global object and does not have interceptors.
-static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
- Register elements, Register name,
- Register value, Register r0, Register r1) {
- // Register use:
- //
- // elements - holds the property dictionary on entry and is clobbered.
- //
- // name - holds the name of the property on entry and is unchanged.
- //
- // value - holds the value to store and is unchanged.
- //
- // r0 - used for index into the property dictionary and is clobbered.
- //
- // r1 - used to hold the capacity of the property dictionary and is clobbered.
- Label done;
-
-
- // Probe the dictionary.
- NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
- elements, name, r0, r1);
-
- // If probing finds an entry in the dictionary, r0 contains the
- // index into the dictionary. Check that the value is a normal
- // property that is not read only.
- __ bind(&done);
- const int kElementsStartOffset =
- NameDictionary::kHeaderSize +
- NameDictionary::kElementsStartIndex * kPointerSize;
- const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask =
- (PropertyDetails::TypeField::kMask |
- PropertyDetails::AttributesField::encode(READ_ONLY))
- << kSmiTagSize;
- __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(kTypeAndReadOnlyMask));
- __ j(not_zero, miss_label);
-
- // Store the value at the masked, scaled index.
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
- __ mov(Operand(r0, 0), value);
-
- // Update write barrier. Make sure not to clobber the value.
- __ mov(r1, value);
- __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register key = StoreDescriptor::NameRegister();
- Register value = StoreDescriptor::ValueRegister();
- DCHECK(receiver.is(edx));
- DCHECK(key.is(ecx));
- DCHECK(value.is(eax));
- // key is a smi.
- // ebx: FixedArray receiver->elements
- // edi: receiver map
- // Fast case: Do the store, could either Object or double.
- __ bind(fast_object);
- if (check_map == kCheckMap) {
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
- __ j(not_equal, fast_double);
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element
- Label holecheck_passed1;
- __ cmp(FixedArrayElementOperand(ebx, key),
- masm->isolate()->factory()->the_hole_value());
- __ j(not_equal, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ mov(FixedArrayElementOperand(ebx, key), value);
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- __ CheckFastObjectElements(edi, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- __ mov(FixedArrayElementOperand(ebx, key), value);
- // Update write barrier for the elements array address.
- __ mov(edx, value); // Preserve the value which is returned.
- __ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
- __ j(not_equal, slow);
- // If the value is a number, store it as a double in the FastDoubleElements
- // array.
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmp(FieldOperand(ebx, key, times_4, offset), Immediate(kHoleNanUpper32));
- __ j(not_equal, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, ebx, key, edi,
- &transition_double_elements, false);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ add(FieldOperand(receiver, JSArray::kLengthOffset),
- Immediate(Smi::FromInt(1)));
- }
- __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&transition_smi_elements);
- __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
-
- // Transition the array appropriately depending on the value type.
- __ CheckMap(value, masm->isolate()->factory()->heap_number_map(),
- &non_double_value, DONT_DO_SMI_CHECK);
-
- // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
- // and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS, ebx, edi, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, ebx,
- edi, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- ebx, edi, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, receiver, key,
- value, ebx, mode, slow);
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- typedef StoreWithVectorDescriptor Descriptor;
- // Return address is on the stack.
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
- Register receiver = Descriptor::ReceiverRegister();
- Register key = Descriptor::NameRegister();
- DCHECK(receiver.is(edx));
- DCHECK(key.is(ecx));
-
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map from the receiver.
- __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &slow);
-
- __ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
- Descriptor::kValue);
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- __ CmpInstanceType(edi, JS_ARRAY_TYPE);
- __ j(equal, &array);
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ CmpInstanceType(edi, JS_OBJECT_TYPE);
- __ j(below, &slow);
-
- // Object case: Check key against length in the elements array.
- // Key is a smi.
- // edi: receiver map
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
- __ j(below, &fast_object);
-
- // Slow case: call runtime.
- __ bind(&slow);
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ mov(ebx, FieldOperand(key, HeapObject::kMapOffset));
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(ebx, &slow);
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
- no_reg);
-
- // Cache miss.
- __ jmp(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // receiver is a JSArray.
- // key is a smi.
- // ebx: receiver->elements, a FixedArray
- // edi: receiver map
- // flags: compare (key, receiver.length())
- // do not leave holes in the array:
- __ j(not_equal, &slow);
- __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
- __ j(above_equal, &slow);
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
- __ j(not_equal, &check_if_double_array);
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
- __ j(not_equal, &slow);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- // receiver is a JSArray.
- // key is a smi.
- // edi: receiver map
- __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array and fall through to the
- // common store code.
- __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset)); // Compare smis.
- __ j(above_equal, &extra);
-
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
- kCheckMap, kDontIncrementLength);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-void LoadIC::GenerateNormal(MacroAssembler* masm) {
- Register dictionary = eax;
- DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
- DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
-
- Label slow;
-
- __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
- JSObject::kPropertiesOffset));
- GenerateDictionaryLoad(masm, &slow, dictionary,
- LoadDescriptor::NameRegister(), edi, ebx, eax);
- __ ret(0);
-
- // Dictionary load failed, go slow (but don't miss).
- __ bind(&slow);
- GenerateRuntimeGetProperty(masm);
-}
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
-
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
- DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) &&
- !edi.is(vector));
-
- __ pop(edi);
- __ push(receiver);
- __ push(name);
- __ push(slot);
- __ push(vector);
- __ push(edi);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- __ IncrementCounter(masm->isolate()->counters()->ic_load_miss(), 1);
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // Return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(!ebx.is(receiver) && !ebx.is(name));
-
- __ pop(ebx);
- __ push(receiver);
- __ push(name);
- __ push(ebx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kGetProperty);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- __ IncrementCounter(masm->isolate()->counters()->ic_keyed_load_miss(), 1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // Return address is on the stack.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(!ebx.is(receiver) && !ebx.is(name));
-
- __ pop(ebx);
- __ push(receiver);
- __ push(name);
- __ push(ebx);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@@ -470,50 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ push(return_address);
}
-
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kStoreIC_Miss);
-}
-
-
-void StoreIC::GenerateNormal(MacroAssembler* masm) {
- typedef StoreWithVectorDescriptor Descriptor;
- Label restore_miss;
- Register receiver = Descriptor::ReceiverRegister();
- Register name = Descriptor::NameRegister();
- Register value = Descriptor::ValueRegister();
- // Since the slot and vector values are passed on the stack we can use
- // respective registers as scratch registers.
- Register scratch1 = Descriptor::VectorRegister();
- Register scratch2 = Descriptor::SlotRegister();
-
- __ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
-
- // A lot of registers are needed for storing to slow case objects.
- // Push and restore receiver but rely on GenerateDictionaryStore preserving
- // the value and name.
- __ push(receiver);
-
- Register dictionary = receiver;
- __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
- GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
- scratch1, scratch2);
- __ Drop(1);
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->ic_store_normal_hit(), 1);
- __ ret(Descriptor::kStackArgumentsCount * kPointerSize);
-
- __ bind(&restore_miss);
- __ pop(receiver);
- __ IncrementCounter(counters->ic_store_normal_miss(), 1);
- GenerateMiss(masm);
-}
-
-
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
diff --git a/deps/v8/src/ic/x87/stub-cache-x87.cc b/deps/v8/src/ic/x87/stub-cache-x87.cc
deleted file mode 100644
index 68fa615420..0000000000
--- a/deps/v8/src/ic/x87/stub-cache-x87.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2012 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.
-
-#if V8_TARGET_ARCH_X87
-
-#include "src/codegen.h"
-#include "src/ic/ic.h"
-#include "src/ic/stub-cache.h"
-#include "src/interface-descriptors.h"
-
-namespace v8 {
-namespace internal {
-
-#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
- StubCache::Table table, Register name, Register receiver,
- // The offset is scaled by 4, based on
- // kCacheIndexShift, which is two bits
- Register offset, Register extra) {
- ExternalReference key_offset(stub_cache->key_reference(table));
- ExternalReference value_offset(stub_cache->value_reference(table));
- ExternalReference map_offset(stub_cache->map_reference(table));
-
- Label miss;
- Code::Kind ic_kind = stub_cache->ic_kind();
- bool is_vector_store =
- IC::ICUseVector(ic_kind) &&
- (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
-
- // Multiply by 3 because there are 3 fields per entry (name, code, map).
- __ lea(offset, Operand(offset, offset, times_2, 0));
-
- if (extra.is_valid()) {
- // Get the code entry from the cache.
- __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
-
- // Check that the key in the entry matches the name.
- __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
- __ j(not_equal, &miss);
-
- // Check the map matches.
- __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
- __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ j(not_equal, &miss);
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- if (is_vector_store) {
- // The value, vector and slot were passed to the IC on the stack and
- // they are still there. So we can just jump to the handler.
- DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
- __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(extra);
- } else {
- // The vector and slot were pushed onto the stack before starting the
- // probe, and need to be dropped before calling the handler.
- __ pop(LoadWithVectorDescriptor::VectorRegister());
- __ pop(LoadDescriptor::SlotRegister());
- __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(extra);
- }
-
- __ bind(&miss);
- } else {
- DCHECK(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
-
- // Save the offset on the stack.
- __ push(offset);
-
- // Check that the key in the entry matches the name.
- __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
- __ j(not_equal, &miss);
-
- // Check the map matches.
- __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
- __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ j(not_equal, &miss);
-
- // Restore offset register.
- __ mov(offset, Operand(esp, 0));
-
- // Get the code entry from the cache.
- __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
-
-#ifdef DEBUG
- if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
- __ jmp(&miss);
- } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
- __ jmp(&miss);
- }
-#endif
-
- // Restore offset and re-load code entry from cache.
- __ pop(offset);
- __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
-
- // Jump to the first instruction in the code stub.
- if (is_vector_store) {
- DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
- }
- __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ jmp(offset);
-
- // Pop at miss.
- __ bind(&miss);
- __ pop(offset);
- }
-}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
- Register name, Register scratch, Register extra,
- Register extra2, Register extra3) {
- Label miss;
-
- // Assert that code is valid. The multiplying code relies on the entry size
- // being 12.
- DCHECK(sizeof(Entry) == 12);
-
- // Assert that there are no register conflicts.
- DCHECK(!scratch.is(receiver));
- DCHECK(!scratch.is(name));
- DCHECK(!extra.is(receiver));
- DCHECK(!extra.is(name));
- DCHECK(!extra.is(scratch));
-
- // Assert scratch and extra registers are valid, and extra2/3 are unused.
- DCHECK(!scratch.is(no_reg));
- DCHECK(extra2.is(no_reg));
- DCHECK(extra3.is(no_reg));
-
- Register offset = scratch;
- scratch = no_reg;
-
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, &miss);
-
- // Get the map of the receiver and compute the hash.
- __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
- __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, kPrimaryMagic);
- // We mask out the last two bits because they are not part of the hash and
- // they are always 01 for maps. Also in the two 'and' instructions below.
- __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
- // ProbeTable expects the offset to be pointer scaled, which it is, because
- // the heap object tag size is 2 and the pointer size log 2 is also 2.
- DCHECK(kCacheIndexShift == kPointerSizeLog2);
-
- // Probe the primary table.
- ProbeTable(this, masm, kPrimary, name, receiver, offset, extra);
-
- // Primary miss: Compute hash for secondary probe.
- __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
- __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, kPrimaryMagic);
- __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
- __ sub(offset, name);
- __ add(offset, Immediate(kSecondaryMagic));
- __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
-
- // Probe the secondary table.
- ProbeTable(this, masm, kSecondary, name, receiver, offset, extra);
-
- // Cache miss: Fall-through and let caller handle the miss by
- // entering the runtime system.
- __ bind(&miss);
- __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
-}
-
-
-#undef __
-} // namespace internal
-} // namespace v8
-
-#endif // V8_TARGET_ARCH_X87