diff options
Diffstat (limited to 'deps/v8/src/ic')
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, ¬_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(¬_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), ¬_callable); + + Callable callable = CodeFactory::Call(isolate()); + CallJS(callable, p->context, setter, receiver, p->value); + Return(p->value); + + Bind(¬_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 |