diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-06-06 10:28:14 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-06-07 10:33:31 +0200 |
commit | 3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09 (patch) | |
tree | 9dee56e142638b34f1eccbd0ad88c3bce5377c29 /deps/v8/src/ic | |
parent | 91a1bbe3055a660194ca4d403795aa0c03e9d056 (diff) | |
download | android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.gz android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.bz2 android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.zip |
deps: update V8 to 5.9.211.32
PR-URL: https://github.com/nodejs/node/pull/13263
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
29 files changed, 2706 insertions, 3478 deletions
diff --git a/deps/v8/src/ic/access-compiler.cc b/deps/v8/src/ic/access-compiler.cc index d210ea8c71..d06028030c 100644 --- a/deps/v8/src/ic/access-compiler.cc +++ b/deps/v8/src/ic/access-compiler.cc @@ -3,39 +3,12 @@ // found in the LICENSE file. #include "src/ic/access-compiler.h" +#include "src/assembler-inl.h" #include "src/objects-inl.h" namespace v8 { namespace internal { - -Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags, - const char* name) { - // Create code object in the heap. - CodeDesc desc; - masm()->GetCode(&desc); - Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject()); - if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey()); -#ifdef ENABLE_DISASSEMBLER - if (FLAG_print_code_stubs) { - CodeTracer::Scope trace_scope(isolate()->GetCodeTracer()); - OFStream os(trace_scope.file()); - code->Disassemble(name, os); - } -#endif - return code; -} - - -Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags, - Handle<Name> name) { - return (FLAG_print_code_stubs && !name.is_null() && name->IsString()) - ? GetCodeWithFlags(flags, - Handle<String>::cast(name)->ToCString().get()) - : GetCodeWithFlags(flags, NULL); -} - - void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) { Handle<Code> code(masm->isolate()->builtins()->builtin(name)); diff --git a/deps/v8/src/ic/access-compiler.h b/deps/v8/src/ic/access-compiler.h index 3d488e82ea..b91aa43aea 100644 --- a/deps/v8/src/ic/access-compiler.h +++ b/deps/v8/src/ic/access-compiler.h @@ -34,11 +34,9 @@ class PropertyAccessCompiler BASE_EMBEDDED { static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); protected: - PropertyAccessCompiler(Isolate* isolate, Code::Kind kind, - CacheHolderFlag cache_holder) + PropertyAccessCompiler(Isolate* isolate, Code::Kind kind) : registers_(GetCallingConvention(isolate, kind)), kind_(kind), - cache_holder_(cache_holder), isolate_(isolate), masm_(isolate, NULL, 256, CodeObjectRequired::kYes) { // TODO(yangguo): remove this once we can serialize IC stubs. @@ -46,10 +44,8 @@ class PropertyAccessCompiler BASE_EMBEDDED { } Code::Kind kind() const { return kind_; } - CacheHolderFlag cache_holder() const { return cache_holder_; } MacroAssembler* masm() { return &masm_; } Isolate* isolate() const { return isolate_; } - Heap* heap() const { return isolate()->heap(); } Factory* factory() const { return isolate()->factory(); } Register receiver() const { return registers_[0]; } @@ -63,16 +59,11 @@ class PropertyAccessCompiler BASE_EMBEDDED { static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code); - Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name); - Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name); - private: static Register* GetCallingConvention(Isolate* isolate, Code::Kind kind); static void InitializePlatformSpecific(AccessCompilerData* data); Code::Kind kind_; - CacheHolderFlag cache_holder_; - Isolate* isolate_; MacroAssembler masm_; // Ensure that MacroAssembler has a reasonable size. diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index d3379ab6d2..eb3971c54f 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -8,6 +8,7 @@ #include "src/code-stubs.h" #include "src/counters.h" #include "src/ic/handler-configuration.h" +#include "src/ic/ic.h" #include "src/ic/stub-cache.h" #include "src/objects-inl.h" @@ -57,32 +58,55 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map, Node* feedback, Label* if_handler, Variable* var_handler, Label* if_miss, - int unroll_count) { + int min_feedback_capacity) { Comment("HandlePolymorphicCase"); DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); + // Deferred so the unrolled case can omit frame construction in bytecode + // handler. + Label loop(this, Label::kDeferred); + // Iterate {feedback} array. const int kEntrySize = 2; - for (int i = 0; i < unroll_count; i++) { + // Loading feedback's length is delayed until we need it when looking past + // the first {min_feedback_capacity} (map, handler) pairs. + Node* length = nullptr; + CSA_ASSERT(this, SmiGreaterThanOrEqual( + LoadFixedArrayBaseLength(feedback), + SmiConstant(min_feedback_capacity * kEntrySize))); + + const int kUnrolledIterations = IC::kMaxPolymorphicMapCount; + for (int i = 0; i < kUnrolledIterations; i++) { + int map_index = i * kEntrySize; + int handler_index = i * kEntrySize + 1; + + if (i >= min_feedback_capacity) { + if (length == nullptr) length = LoadFixedArrayBaseLength(feedback); + GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), length), + if_miss); + } + Label next_entry(this); Node* cached_map = - LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize)); + LoadWeakCellValue(LoadFixedArrayElement(feedback, map_index)); GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry); // Found, now call handler. - Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1); + Node* handler = LoadFixedArrayElement(feedback, handler_index); var_handler->Bind(handler); Goto(if_handler); - Bind(&next_entry); + BIND(&next_entry); } + Goto(&loop); - // Loop from {unroll_count}*kEntrySize to {length}. - Node* init = IntPtrConstant(unroll_count * kEntrySize); - Node* length = LoadAndUntagFixedArrayBaseLength(feedback); + // Loop from {kUnrolledIterations}*kEntrySize to {length}. + BIND(&loop); + Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize); + Node* end_index = LoadAndUntagFixedArrayBaseLength(feedback); BuildFastLoop( - init, length, + start_index, end_index, [this, receiver_map, feedback, if_handler, var_handler](Node* index) { Node* cached_map = LoadWeakCellValue(LoadFixedArrayElement(feedback, index)); @@ -95,103 +119,106 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map, var_handler->Bind(handler); Goto(if_handler); - Bind(&next_entry); + BIND(&next_entry); }, kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); // The loop falls through if no handler was found. Goto(if_miss); } -void AccessorAssembler::HandleKeyedStorePolymorphicCase( - Node* receiver_map, Node* feedback, Label* if_handler, - Variable* var_handler, Label* if_transition_handler, - Variable* var_transition_map_cell, Label* if_miss) { - 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(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, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); - // The loop falls through if no handler was found. - Goto(if_miss); -} - void AccessorAssembler::HandleLoadICHandlerCase( const LoadICParameters* p, Node* handler, Label* miss, - ElementSupport support_elements) { + ExitPoint* exit_point, ElementSupport support_elements) { Comment("have_handler"); - ExitPoint direct_exit(this); - Variable var_holder(this, MachineRepresentation::kTagged); - var_holder.Bind(p->receiver); - Variable var_smi_handler(this, MachineRepresentation::kTagged); - var_smi_handler.Bind(handler); + VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver); + VARIABLE(var_smi_handler, MachineRepresentation::kTagged, handler); Variable* vars[] = {&var_holder, &var_smi_handler}; Label if_smi_handler(this, 2, vars); - Label try_proto_handler(this), call_handler(this); + Label try_proto_handler(this, Label::kDeferred), + call_handler(this, Label::kDeferred); 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); + BIND(&if_smi_handler); { HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), - miss, &direct_exit, support_elements); + miss, exit_point, false, support_elements); } - Bind(&try_proto_handler); + BIND(&try_proto_handler); { GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler, - &if_smi_handler, miss, &direct_exit, false); + &if_smi_handler, miss, exit_point, false); } - Bind(&call_handler); + BIND(&call_handler); { typedef LoadWithVectorDescriptor Descriptor; - TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver, - p->name, p->slot, p->vector); + exit_point->ReturnCallStub(Descriptor(isolate()), handler, p->context, + p->receiver, p->name, p->slot, p->vector); + } +} + +void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, + Variable* var_double_value, + Label* rebox_double, + ExitPoint* exit_point) { + 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); + exit_point->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); + exit_point->Return(value); + + BIND(&is_double); + var_double_value->Bind(LoadHeapNumberValue(value)); + Goto(rebox_double); } } void AccessorAssembler::HandleLoadICSmiHandlerCase( const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, - ExitPoint* exit_point, ElementSupport support_elements) { - Variable var_double_value(this, MachineRepresentation::kFloat64); + ExitPoint* exit_point, bool throw_reference_error_if_nonexistent, + ElementSupport support_elements) { + VARIABLE(var_double_value, 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); - GotoIfNot( - WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)), - &property); + GotoIfNot(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)), + &property); Comment("element_load"); Node* intptr_index = TryToIntptr(p->name, miss); @@ -207,7 +234,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( &var_double_value, &unimplemented_elements_kind, out_of_bounds, miss, exit_point); - Bind(&unimplemented_elements_kind); + BIND(&unimplemented_elements_kind); { // Smi handlers should only be installed for supported elements kinds. // Crash if we get here. @@ -215,7 +242,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( Goto(miss); } - Bind(&if_hole); + BIND(&if_hole); { Comment("convert hole"); GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss); @@ -228,78 +255,136 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( exit_point->Return(UndefinedConstant()); } - Bind(&property); + BIND(&property); Comment("property_load"); } - Label constant(this), field(this); - Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)), - &field, &constant); + Label constant(this), field(this), normal(this, Label::kDeferred), + interceptor(this, Label::kDeferred), nonexistent(this), + accessor(this, Label::kDeferred), global(this, Label::kDeferred); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field); - Bind(&field); - { - Comment("field_load"); - Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)), + &constant); - Label inobject(this), out_of_object(this); - Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject, - &out_of_object); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)), + &nonexistent); - Bind(&inobject); - { - Label is_double(this); - GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); - exit_point->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); - } + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)), + &normal); - 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); - exit_point->Return(value); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)), + &accessor); - Bind(&is_double); - var_double_value.Bind(LoadHeapNumberValue(value)); - Goto(&rebox_double); - } + Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global, + &interceptor); - Bind(&rebox_double); - exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value())); + BIND(&field); + HandleLoadField(holder, handler_word, &var_double_value, &rebox_double, + exit_point); + + BIND(&nonexistent); + // This is a handler for a load of a non-existent value. + if (throw_reference_error_if_nonexistent) { + exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context, + p->name); + } else { + exit_point->Return(UndefinedConstant()); } - Bind(&constant); + BIND(&constant); { Comment("constant_load"); Node* descriptors = LoadMapDescriptors(LoadMap(holder)); - Node* descriptor = - DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word); + Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word); + Node* scaled_descriptor = + IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize)); + Node* value_index = + IntPtrAdd(scaled_descriptor, + IntPtrConstant(DescriptorArray::kFirstIndex + + DescriptorArray::kEntryValueIndex)); CSA_ASSERT(this, UintPtrLessThan(descriptor, LoadAndUntagFixedArrayBaseLength(descriptors))); - Node* value = LoadFixedArrayElement(descriptors, descriptor); + Node* value = LoadFixedArrayElement(descriptors, value_index); - Label if_accessor_info(this); + Label if_accessor_info(this, Label::kDeferred); GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word), &if_accessor_info); exit_point->Return(value); - Bind(&if_accessor_info); + BIND(&if_accessor_info); Callable callable = CodeFactory::ApiGetter(isolate()); exit_point->ReturnCallStub(callable, p->context, p->receiver, holder, value); } + + BIND(&normal); + { + Comment("load_normal"); + Node* properties = LoadProperties(holder); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); + Label found(this, &var_name_index); + NameDictionaryLookup<NameDictionary>(properties, p->name, &found, + &var_name_index, miss); + BIND(&found); + { + VARIABLE(var_details, MachineRepresentation::kWord32); + VARIABLE(var_value, MachineRepresentation::kTagged); + LoadPropertyFromNameDictionary(properties, var_name_index.value(), + &var_details, &var_value); + Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), + p->context, p->receiver, miss); + exit_point->Return(value); + } + } + + BIND(&accessor); + { + Comment("accessor_load"); + Node* descriptors = LoadMapDescriptors(LoadMap(holder)); + Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word); + Node* scaled_descriptor = + IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize)); + Node* value_index = + IntPtrAdd(scaled_descriptor, + IntPtrConstant(DescriptorArray::kFirstIndex + + DescriptorArray::kEntryValueIndex)); + CSA_ASSERT(this, + UintPtrLessThan(descriptor, + LoadAndUntagFixedArrayBaseLength(descriptors))); + Node* accessor_pair = LoadFixedArrayElement(descriptors, value_index); + CSA_ASSERT(this, IsAccessorPair(accessor_pair)); + Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset); + CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter))); + + Callable callable = CodeFactory::Call(isolate()); + exit_point->Return(CallJS(callable, p->context, getter, p->receiver)); + } + + BIND(&global); + { + CSA_ASSERT(this, IsPropertyCell(holder)); + // Ensure the property cell doesn't contain the hole. + Node* value = LoadObjectField(holder, PropertyCell::kValueOffset); + Node* details = + LoadAndUntagToWord32ObjectField(holder, PropertyCell::kDetailsOffset); + GotoIf(IsTheHole(value), miss); + + exit_point->Return( + CallGetterIfAccessor(value, details, p->context, p->receiver, miss)); + } + + BIND(&interceptor); + { + Comment("load_interceptor"); + exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor, + p->context, p->name, p->receiver, holder, + p->slot, p->vector); + } + + BIND(&rebox_double); + exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value())); } void AccessorAssembler::HandleLoadICProtoHandlerCase( @@ -328,53 +413,64 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase( miss); Goto(&validity_cell_check_done); - Bind(&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); - GotoIfNot( - IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags), - &check_prototypes); + GotoIfNot(IsSetWord<LoadHandler::LookupOnReceiverBits>(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); + Node* properties = LoadProperties(p->receiver); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); + Label found(this, &var_name_index); + NameDictionaryLookup<NameDictionary>(properties, p->name, &found, + &var_name_index, &check_prototypes); + BIND(&found); + { + VARIABLE(var_details, MachineRepresentation::kWord32); + VARIABLE(var_value, MachineRepresentation::kTagged); + LoadPropertyFromNameDictionary(properties, var_name_index.value(), + &var_details, &var_value); + Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), + p->context, p->receiver, miss); + exit_point->Return(value); + } } - Bind(&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); + 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) { - exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context, - p->name); - } else { - exit_point->Return(UndefinedConstant()); - } + Label load_from_cached_holder(this), done(this); + + Branch(WordEqual(maybe_holder_cell, NullConstant()), &done, + &load_from_cached_holder); + + BIND(&load_from_cached_holder); + { + // For regular holders, having passed the receiver map check and the + // validity cell check implies that |holder| is alive. However, for + // global object receivers, the |maybe_holder_cell| may be cleared. + Node* holder = LoadWeakCellValue(maybe_holder_cell, miss); - 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); + Goto(&done); + } - var_holder->Bind(holder); + BIND(&done); var_smi_handler->Bind(smi_handler); Goto(if_smi_handler); } - Bind(&array_handler); + BIND(&array_handler); { exit_point->ReturnCallStub( CodeFactory::LoadICProtoArray(isolate(), @@ -383,11 +479,12 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase( } } -Node* AccessorAssembler::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()); +Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p, + Node* handler, + Node* handler_length, + Node* handler_flags, + Label* miss) { + VARIABLE(start_index, MachineType::PointerRepresentation()); start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex)); Label can_access(this); @@ -415,7 +512,7 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck( LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX); Branch(WordEqual(expected_token, current_token), &can_access, miss); } - Bind(&can_access); + BIND(&can_access); BuildFastLoop(start_index.value(), handler_length, [this, p, handler, miss](Node* current) { @@ -427,22 +524,21 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck( 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()); + + VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver); + Label done(this); + GotoIf(WordEqual(maybe_holder_cell, NullConstant()), &done); + + { + // For regular holders, having passed the receiver map check and the + // validity cell check implies that |holder| is alive. However, for + // global object receivers, the |maybe_holder_cell| may be cleared. + var_holder.Bind(LoadWeakCellValue(maybe_holder_cell, miss)); + Goto(&done); } - 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; + BIND(&done); + return var_holder.value(); } void AccessorAssembler::HandleLoadGlobalICHandlerCase( @@ -451,64 +547,164 @@ void AccessorAssembler::HandleLoadGlobalICHandlerCase( LoadICParameters p = *pp; DCHECK_NULL(p.receiver); Node* native_context = LoadNativeContext(p.context); - p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX); + p.receiver = LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX); - Variable var_holder(this, MachineRepresentation::kTagged); - Variable var_smi_handler(this, MachineRepresentation::kTagged); + VARIABLE(var_holder, MachineRepresentation::kTagged, + LoadContextElement(native_context, Context::EXTENSION_INDEX)); + VARIABLE(var_smi_handler, MachineRepresentation::kTagged); Label if_smi_handler(this); + HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler, &if_smi_handler, miss, exit_point, throw_reference_error_if_nonexistent); - Bind(&if_smi_handler); - HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(), - miss, exit_point, kOnlyProperties); + BIND(&if_smi_handler); + HandleLoadICSmiHandlerCase( + &p, var_holder.value(), var_smi_handler.value(), miss, exit_point, + throw_reference_error_if_nonexistent, kOnlyProperties); +} + +void AccessorAssembler::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 AccessorAssembler::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); + Label if_proto_handler(this), if_element_handler(this), call_handler(this), + store_global(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); + BIND(&if_smi_handler); { Node* holder = p->receiver; Node* handler_word = SmiUntag(handler); + Label if_fast_smi(this), slow(this); + GotoIfNot( + WordEqual(handler_word, IntPtrConstant(StoreHandler::kStoreNormal)), + &if_fast_smi); + + Node* properties = LoadProperties(holder); + + VARIABLE(var_name_index, MachineType::PointerRepresentation()); + Label dictionary_found(this, &var_name_index); + NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found, + &var_name_index, miss); + BIND(&dictionary_found); + { + Node* details = LoadDetailsByKeyIndex<NameDictionary>( + properties, var_name_index.value()); + // Check that the property is a writable data property (no accessor). + const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask | + PropertyDetails::kAttributesReadOnlyMask; + STATIC_ASSERT(kData == 0); + GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss); + + StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(), + p->value); + Return(p->value); + } + + BIND(&if_fast_smi); // Handle non-transitioning field stores. HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss); } - Bind(&if_nonsmi_handler); + BIND(&if_nonsmi_handler); { Node* handler_map = LoadMap(handler); if (support_elements == kSupportElements) { GotoIf(IsTuple2Map(handler_map), &if_element_handler); } + GotoIf(IsWeakCellMap(handler_map), &store_global); Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler); } if (support_elements == kSupportElements) { - Bind(&if_element_handler); + BIND(&if_element_handler); { HandleStoreICElementHandlerCase(p, handler, miss); } } - Bind(&if_proto_handler); - { - HandleStoreICProtoHandler(p, handler, miss); - } + BIND(&if_proto_handler); + { HandleStoreICProtoHandler(p, handler, miss, support_elements); } // |handler| is a heap object. Must be code, call it. - Bind(&call_handler); + BIND(&call_handler); { StoreWithVectorDescriptor descriptor(isolate()); TailCallStub(descriptor, handler, p->context, p->receiver, p->name, p->value, p->slot, p->vector); } + + BIND(&store_global); + { + Node* cell = LoadWeakCellValue(handler, miss); + CSA_ASSERT(this, IsPropertyCell(cell)); + + // Load the payload of the global parameter cell. A hole indicates that + // the cell has been invalidated and that the store must be handled by the + // runtime. + Node* cell_contents = LoadObjectField(cell, PropertyCell::kValueOffset); + Node* details = + LoadAndUntagToWord32ObjectField(cell, PropertyCell::kDetailsOffset); + Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details); + + Label constant(this), store(this), not_smi(this); + + GotoIf( + Word32Equal( + type, Int32Constant(static_cast<int>(PropertyCellType::kConstant))), + &constant); + + GotoIf(IsTheHole(cell_contents), miss); + + GotoIf( + Word32Equal( + type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))), + &store); + CSA_ASSERT(this, + Word32Or(Word32Equal(type, + Int32Constant(static_cast<int>( + PropertyCellType::kConstantType))), + Word32Equal(type, + Int32Constant(static_cast<int>( + PropertyCellType::kUndefined))))); + + GotoIfNot(TaggedIsSmi(cell_contents), ¬_smi); + GotoIfNot(TaggedIsSmi(p->value), miss); + Goto(&store); + + BIND(¬_smi); + { + GotoIf(TaggedIsSmi(p->value), miss); + Node* expected_map = LoadMap(cell_contents); + Node* map = LoadMap(p->value); + GotoIfNot(WordEqual(expected_map, map), miss); + Goto(&store); + } + + BIND(&store); + { + StoreObjectField(cell, PropertyCell::kValueOffset, p->value); + Return(p->value); + } + + BIND(&constant); + { + GotoIfNot(WordEqual(cell_contents, p->value), miss); + Return(p->value); + } + } } void AccessorAssembler::HandleStoreICElementHandlerCase( @@ -528,8 +724,9 @@ void AccessorAssembler::HandleStoreICElementHandlerCase( p->value, p->slot, p->vector); } -void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, - Node* handler, Label* miss) { +void AccessorAssembler::HandleStoreICProtoHandler( + const StoreICParameters* p, Node* handler, Label* miss, + ElementSupport support_elements) { // IC dispatchers rely on these assumptions to be held. STATIC_ASSERT(FixedArray::kLengthOffset == StoreHandler::kTransitionCellOffset); @@ -550,25 +747,25 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, miss); Goto(&validity_cell_check_done); - Bind(&validity_cell_check_done); - Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset); - CSA_ASSERT(this, TaggedIsSmi(smi_handler)); + BIND(&validity_cell_check_done); + Node* smi_or_code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset); 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); + VARIABLE(var_transition, MachineRepresentation::kTagged); + Label if_transition(this), if_transition_to_constant(this), + if_store_normal(this); + BIND(&tuple_handler); { Node* transition = LoadWeakCellValue(maybe_transition_cell, miss); var_transition.Bind(transition); Goto(&if_transition); } - Bind(&array_handler); + BIND(&array_handler); { Node* length = SmiUntag(maybe_transition_cell); BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length, @@ -586,15 +783,34 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, Goto(&if_transition); } - Bind(&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); + GotoIf(IsDeprecatedMap(transition), miss); + + if (support_elements == kSupportElements) { + Label if_smi_handler(this); + + GotoIf(TaggedIsSmi(smi_or_code), &if_smi_handler); + Node* code_handler = smi_or_code; + CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler))); + + StoreTransitionDescriptor descriptor(isolate()); + TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name, + transition, p->value, p->slot, p->vector); + + BIND(&if_smi_handler); + } + + Node* smi_handler = smi_or_code; + CSA_ASSERT(this, TaggedIsSmi(smi_handler)); + Node* handler_word = SmiUntag(smi_handler); Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); + GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kStoreNormal)), + &if_store_normal); GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kTransitionToConstant)), &if_transition_to_constant); @@ -603,19 +819,64 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition, miss); - Bind(&if_transition_to_constant); + BIND(&if_transition_to_constant); { // Check that constant matches value. - Node* value_index_in_descriptor = - DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); + Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word); + Node* scaled_descriptor = + IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize)); + Node* value_index = + IntPtrAdd(scaled_descriptor, + IntPtrConstant(DescriptorArray::kFirstIndex + + DescriptorArray::kEntryValueIndex)); Node* descriptors = LoadMapDescriptors(transition); - Node* constant = - LoadFixedArrayElement(descriptors, value_index_in_descriptor); + CSA_ASSERT( + this, + UintPtrLessThan(descriptor, + LoadAndUntagFixedArrayBaseLength(descriptors))); + + Node* constant = LoadFixedArrayElement(descriptors, value_index); GotoIf(WordNotEqual(p->value, constant), miss); StoreMap(p->receiver, transition); Return(p->value); } + + BIND(&if_store_normal); + { + Node* properties = LoadProperties(p->receiver); + + VARIABLE(var_name_index, MachineType::PointerRepresentation()); + Label found(this, &var_name_index), not_found(this); + NameDictionaryLookup<NameDictionary>(properties, p->name, &found, + &var_name_index, ¬_found); + BIND(&found); + { + Node* details = LoadDetailsByKeyIndex<NameDictionary>( + properties, var_name_index.value()); + // Check that the property is a writable data property (no accessor). + const int kTypeAndReadOnlyMask = + PropertyDetails::KindField::kMask | + PropertyDetails::kAttributesReadOnlyMask; + STATIC_ASSERT(kData == 0); + GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss); + + StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(), + p->value); + Return(p->value); + } + + BIND(¬_found); + { + Label slow(this); + Add<NameDictionary>(properties, p->name, p->value, &slow); + Return(p->value); + + BIND(&slow); + TailCallRuntime(Runtime::kAddDictionaryProperty, p->context, + p->receiver, p->name, p->value); + } + } } } @@ -667,21 +928,21 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, IntPtrConstant(StoreHandler::kSmi))); Goto(&if_smi_field); - Bind(&if_tagged_field); + BIND(&if_tagged_field); { Comment("store tagged field"); HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), value, transition, miss); } - Bind(&if_double_field); + BIND(&if_double_field); { Comment("store double field"); HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), value, transition, miss); } - Bind(&if_heap_object_field); + BIND(&if_heap_object_field); { Comment("store heap object field"); HandleStoreFieldAndReturn(handler_word, holder, @@ -689,7 +950,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, miss); } - Bind(&if_smi_field); + BIND(&if_smi_field); { Comment("store smi field"); HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), @@ -710,7 +971,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word, Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, &if_out_of_object); - Bind(&if_inobject); + BIND(&if_inobject); { StoreNamedField(handler_word, holder, true, representation, prepared_value, transition_to_field, miss); @@ -720,7 +981,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word, Return(value); } - Bind(&if_out_of_object); + BIND(&if_out_of_object); { if (transition_to_field) { Label storage_extended(this); @@ -731,7 +992,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word, Comment("] Extend storage"); Goto(&storage_extended); - Bind(&storage_extended); + BIND(&storage_extended); } StoreNamedField(handler_word, holder, false, representation, prepared_value, @@ -761,12 +1022,19 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, IntPtrConstant(StoreHandler::kStoreConstField)), &done); } - Node* value_index_in_descriptor = - DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); + Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word); + Node* scaled_descriptor = + IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize)); + Node* value_index = + IntPtrAdd(scaled_descriptor, + IntPtrConstant(DescriptorArray::kFirstIndex + + DescriptorArray::kEntryValueIndex)); Node* descriptors = LoadMapDescriptors(transition ? transition : LoadMap(holder)); - Node* maybe_field_type = - LoadFixedArrayElement(descriptors, value_index_in_descriptor); + CSA_ASSERT(this, + UintPtrLessThan(descriptor, + LoadAndUntagFixedArrayBaseLength(descriptors))); + Node* maybe_field_type = LoadFixedArrayElement(descriptors, value_index); GotoIf(TaggedIsSmi(maybe_field_type), &done); // Check that value type matches the field type. @@ -774,7 +1042,7 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, Node* field_type = LoadWeakCellValue(maybe_field_type, bailout); Branch(WordEqual(LoadMap(value), field_type), &done, bailout); } - Bind(&done); + BIND(&done); } else if (representation.IsSmi()) { GotoIfNot(TaggedIsSmi(value), bailout); @@ -786,11 +1054,12 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder, } void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) { - Node* properties = LoadProperties(object); - Node* length = LoadFixedArrayBaseLength(properties); - ParameterMode mode = OptimalParameterMode(); - length = TaggedToParameter(length, mode); + + Node* properties = LoadProperties(object); + Node* length = (mode == INTPTR_PARAMETERS) + ? LoadAndUntagFixedArrayBaseLength(properties) + : LoadFixedArrayBaseLength(properties); Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode); Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode); @@ -866,7 +1135,7 @@ void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object, } Goto(&done); } - Bind(&done); + BIND(&done); } // Do the store. @@ -885,7 +1154,7 @@ void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object, Node* intptr_index, Node* is_jsarray_condition, Label* miss) { - Variable var_length(this, MachineType::PointerRepresentation()); + VARIABLE(var_length, MachineType::PointerRepresentation()); Comment("Fast elements bounds check"); Label if_array(this), length_loaded(this, &var_length); GotoIf(is_jsarray_condition, &if_array); @@ -893,12 +1162,12 @@ void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object, var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); Goto(&length_loaded); } - Bind(&if_array); + BIND(&if_array); { var_length.Bind(SmiUntag(LoadJSArrayLength(object))); Goto(&length_loaded); } - Bind(&length_loaded); + BIND(&length_loaded); GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss); } @@ -935,13 +1204,13 @@ void AccessorAssembler::EmitElementLoad( Switch(elements_kind, unimplemented_elements_kind, kinds, labels, arraysize(kinds)); - Bind(&if_fast_packed); + BIND(&if_fast_packed); { Comment("fast packed elements"); exit_point->Return(LoadFixedArrayElement(elements, intptr_index)); } - Bind(&if_fast_holey); + BIND(&if_fast_holey); { Comment("fast holey elements"); Node* element = LoadFixedArrayElement(elements, intptr_index); @@ -949,7 +1218,7 @@ void AccessorAssembler::EmitElementLoad( exit_point->Return(element); } - Bind(&if_fast_double); + BIND(&if_fast_double); { Comment("packed double elements"); var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index, @@ -957,7 +1226,7 @@ void AccessorAssembler::EmitElementLoad( Goto(rebox_double); } - Bind(&if_fast_holey_double); + BIND(&if_fast_holey_double); { Comment("holey double elements"); Node* value = LoadFixedDoubleArrayElement(elements, intptr_index, @@ -967,7 +1236,7 @@ void AccessorAssembler::EmitElementLoad( Goto(rebox_double); } - Bind(&if_nonfast); + BIND(&if_nonfast); { STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); GotoIf(Int32GreaterThanOrEqual( @@ -979,15 +1248,15 @@ void AccessorAssembler::EmitElementLoad( Goto(unimplemented_elements_kind); } - Bind(&if_dictionary); + BIND(&if_dictionary); { Comment("dictionary elements"); GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds); - Variable var_entry(this, MachineType::PointerRepresentation()); + VARIABLE(var_entry, MachineType::PointerRepresentation()); Label if_found(this); NumberDictionaryLookup<SeededNumberDictionary>( elements, intptr_index, &if_found, &var_entry, if_hole); - Bind(&if_found); + BIND(&if_found); // Check that the value is a data property. Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value()); Node* details = @@ -1000,7 +1269,7 @@ void AccessorAssembler::EmitElementLoad( LoadValueByKeyIndex<SeededNumberDictionary>(elements, index)); } - Bind(&if_typed_array); + BIND(&if_typed_array); { Comment("typed elements"); // Check if buffer has been neutered. @@ -1039,47 +1308,47 @@ void AccessorAssembler::EmitElementLoad( DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels)); Switch(elements_kind, miss, elements_kinds, elements_kind_labels, kTypedElementsKindCount); - Bind(&uint8_elements); + BIND(&uint8_elements); { Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too. Node* element = Load(MachineType::Uint8(), backing_store, intptr_index); exit_point->Return(SmiFromWord32(element)); } - Bind(&int8_elements); + BIND(&int8_elements); { Comment("INT8_ELEMENTS"); Node* element = Load(MachineType::Int8(), backing_store, intptr_index); exit_point->Return(SmiFromWord32(element)); } - Bind(&uint16_elements); + BIND(&uint16_elements); { Comment("UINT16_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(1)); Node* element = Load(MachineType::Uint16(), backing_store, index); exit_point->Return(SmiFromWord32(element)); } - Bind(&int16_elements); + BIND(&int16_elements); { Comment("INT16_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(1)); Node* element = Load(MachineType::Int16(), backing_store, index); exit_point->Return(SmiFromWord32(element)); } - Bind(&uint32_elements); + BIND(&uint32_elements); { Comment("UINT32_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(2)); Node* element = Load(MachineType::Uint32(), backing_store, index); exit_point->Return(ChangeUint32ToTagged(element)); } - Bind(&int32_elements); + BIND(&int32_elements); { Comment("INT32_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(2)); Node* element = Load(MachineType::Int32(), backing_store, index); exit_point->Return(ChangeInt32ToTagged(element)); } - Bind(&float32_elements); + BIND(&float32_elements); { Comment("FLOAT32_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(2)); @@ -1087,7 +1356,7 @@ void AccessorAssembler::EmitElementLoad( var_double_value->Bind(ChangeFloat32ToFloat64(element)); Goto(rebox_double); } - Bind(&float64_elements); + BIND(&float64_elements); { Comment("FLOAT64_ELEMENTS"); Node* index = WordShl(intptr_index, IntPtrConstant(3)); @@ -1106,26 +1375,25 @@ void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name, 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); + Branch(IsPropertyCell(maybe_prototype), &if_property_cell, + &if_dictionary_object); - Bind(&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); + 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); + GotoIfNot(IsTheHole(value), miss); Goto(&done); } - Bind(&done); + BIND(&done); } void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name, @@ -1133,11 +1401,11 @@ void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name, 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()); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label done(this); NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index, &done); - Bind(&done); + BIND(&done); } void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, @@ -1157,7 +1425,7 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, Node* elements_kind = LoadMapElementsKind(receiver_map); Node* is_jsarray_condition = Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); - Variable var_double_value(this, MachineRepresentation::kFloat64); + VARIABLE(var_double_value, MachineRepresentation::kFloat64); Label rebox_double(this, &var_double_value); // Unimplemented elements kinds fall back to a runtime call. @@ -1168,10 +1436,10 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, &var_double_value, unimplemented_elements_kind, &if_oob, slow, &direct_exit); - Bind(&rebox_double); + BIND(&rebox_double); Return(AllocateHeapNumberWithValue(var_double_value.value())); - Bind(&if_oob); + BIND(&if_oob); { Comment("out of bounds"); // Negative keys can't take the fast OOB path. @@ -1180,13 +1448,13 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, Goto(&if_element_hole); } - Bind(&if_element_hole); + BIND(&if_element_hole); { Comment("found the hole"); Label return_undefined(this); BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow); - Bind(&return_undefined); + BIND(&return_undefined); Return(UndefinedConstant()); } } @@ -1194,12 +1462,15 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, Node* instance_type, Node* key, const LoadICParameters* p, - Label* slow) { + Label* slow, + UseStubCache use_stub_cache) { + ExitPoint direct_exit(this); + Comment("key is unique name"); Label if_found_on_receiver(this), if_property_dictionary(this), lookup_prototype_chain(this); - Variable var_details(this, MachineRepresentation::kWord32); - Variable var_value(this, MachineRepresentation::kTagged); + VARIABLE(var_details, MachineRepresentation::kWord32); + VARIABLE(var_value, MachineRepresentation::kTagged); // Receivers requiring non-standard accesses (interceptors, access // checks, strings and string wrappers, proxies) are handled in the runtime. @@ -1219,11 +1490,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, Node* descriptors = LoadMapDescriptors(receiver_map); Label if_descriptor_found(this), stub_cache(this); - Variable var_name_index(this, MachineType::PointerRepresentation()); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); + Label* notfound = + use_stub_cache == kUseStubCache ? &stub_cache : &lookup_prototype_chain; DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found, - &var_name_index, &stub_cache); + &var_name_index, notfound); - Bind(&if_descriptor_found); + BIND(&if_descriptor_found); { LoadPropertyFromFastObject(receiver, receiver_map, descriptors, var_name_index.value(), &var_details, @@ -1231,17 +1504,17 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, Goto(&if_found_on_receiver); } - Bind(&stub_cache); - { + if (use_stub_cache == kUseStubCache) { + BIND(&stub_cache); Comment("stub cache probe for fast property load"); - Variable var_handler(this, MachineRepresentation::kTagged); + VARIABLE(var_handler, 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(&found_handler); + { HandleLoadICHandlerCase(p, var_handler.value(), slow, &direct_exit); } - Bind(&stub_cache_miss); + BIND(&stub_cache_miss); { // TODO(jkummerow): Check if the property exists on the prototype // chain. If it doesn't, then there's no point in missing. @@ -1251,18 +1524,18 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, } } - Bind(&if_property_dictionary); + 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()); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label dictionary_found(this, &var_name_index); NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, &var_name_index, &lookup_prototype_chain); - Bind(&dictionary_found); + BIND(&dictionary_found); { LoadPropertyFromNameDictionary(properties, var_name_index.value(), &var_details, &var_value); @@ -1270,7 +1543,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, } } - Bind(&if_found_on_receiver); + BIND(&if_found_on_receiver); { Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), p->context, receiver, slow); @@ -1278,10 +1551,10 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, Return(value); } - Bind(&lookup_prototype_chain); + BIND(&lookup_prototype_chain); { - Variable var_holder_map(this, MachineRepresentation::kTagged); - Variable var_holder_instance_type(this, MachineRepresentation::kWord32); + VARIABLE(var_holder_map, MachineRepresentation::kTagged); + VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32); Label return_undefined(this); Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type}; Label loop(this, arraysize(merged_variables), merged_variables); @@ -1291,7 +1564,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, // Private symbols must not be looked up on the prototype chain. GotoIf(IsPrivateSymbol(key), &return_undefined); Goto(&loop); - Bind(&loop); + BIND(&loop); { // Bailout if it can be an integer indexed exotic case. GotoIf(Word32Equal(var_holder_instance_type.value(), @@ -1310,17 +1583,17 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, // This trampoline and the next are required to appease Turbofan's // variable merging. - Bind(&next_proto); + BIND(&next_proto); Goto(&loop); - Bind(&goto_slow); + BIND(&goto_slow); Goto(slow); - Bind(&return_value); + BIND(&return_value); Return(var_value.value()); } - Bind(&return_undefined); + BIND(&return_undefined); Return(UndefinedConstant()); } } @@ -1430,7 +1703,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver, TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name, receiver_map, if_handler, var_handler, &try_secondary); - Bind(&try_secondary); + BIND(&try_secondary); { // Probe the secondary table. Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset); @@ -1438,7 +1711,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver, receiver_map, if_handler, var_handler, &miss); } - Bind(&miss); + BIND(&miss); { IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); Goto(if_miss); @@ -1447,44 +1720,189 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver, //////////////////// Entry points into private implementation (one per stub). +void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p, + ExitPoint* exit_point) { + // Must be kept in sync with LoadIC. + + // This function is hand-tuned to omit frame construction for common cases, + // e.g.: monomorphic field and constant loads through smi handlers. + // Polymorphic ICs with a hit in the first two entries also omit frames. + // TODO(jgruber): Frame omission is fragile and can be affected by minor + // changes in control flow and logic. We currently have no way of ensuring + // that no frame is constructed, so it's easy to break this optimization by + // accident. + Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred); + + // Inlined fast path. + { + Comment("LoadIC_BytecodeHandler_fast"); + + Node* recv_map = LoadReceiverMap(p->receiver); + GotoIf(IsDeprecatedMap(recv_map), &miss); + + VARIABLE(var_handler, MachineRepresentation::kTagged); + Label try_polymorphic(this), if_handler(this, &var_handler); + + Node* feedback = + TryMonomorphicCase(p->slot, p->vector, recv_map, &if_handler, + &var_handler, &try_polymorphic); + + BIND(&if_handler); + HandleLoadICHandlerCase(p, var_handler.value(), &miss, exit_point); + + BIND(&try_polymorphic); + { + GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), + &stub_call); + HandlePolymorphicCase(recv_map, feedback, &if_handler, &var_handler, + &miss, 2); + } + } + + BIND(&stub_call); + { + Comment("LoadIC_BytecodeHandler_noninlined"); + + // Call into the stub that implements the non-inlined parts of LoadIC. + Callable ic = CodeFactory::LoadICInOptimizedCode_Noninlined(isolate()); + Node* code_target = HeapConstant(ic.code()); + exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context, + p->receiver, p->name, p->slot, p->vector); + } + + BIND(&miss); + { + Comment("LoadIC_BytecodeHandler_miss"); + + exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, + p->receiver, p->name, p->slot, p->vector); + } +} + void AccessorAssembler::LoadIC(const LoadICParameters* p) { - Variable var_handler(this, MachineRepresentation::kTagged); - // TODO(ishell): defer blocks when it works. - Label if_handler(this, &var_handler), try_polymorphic(this), - try_megamorphic(this /*, Label::kDeferred*/), - miss(this /*, Label::kDeferred*/); + // Must be kept in sync with LoadIC_BytecodeHandler. + + ExitPoint direct_exit(this); + + VARIABLE(var_handler, MachineRepresentation::kTagged); + Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred), + try_polymorphic(this), miss(this, Label::kDeferred); Node* receiver_map = LoadReceiverMap(p->receiver); - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); + GotoIf(IsDeprecatedMap(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(&if_handler); + HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit); - Bind(&try_polymorphic); + BIND(&try_polymorphic); { // Check polymorphic case. Comment("LoadIC_try_polymorphic"); GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()), - &try_megamorphic); + &non_inlined); HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, &miss, 2); } - Bind(&try_megamorphic); + BIND(&non_inlined); + LoadIC_Noninlined(p, receiver_map, feedback, &var_handler, &if_handler, &miss, + &direct_exit); + + BIND(&miss); + direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, + p->name, p->slot, p->vector); +} + +void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, + Node* receiver_map, Node* feedback, + Variable* var_handler, + Label* if_handler, Label* miss, + ExitPoint* exit_point) { + Label try_uninitialized(this, Label::kDeferred); + + // Neither deprecated map nor monomorphic. These cases are handled in the + // bytecode handler. + CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map))); + CSA_ASSERT(this, + WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback))); + CSA_ASSERT(this, WordNotEqual(LoadMap(feedback), FixedArrayMapConstant())); + DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); + { // Check megamorphic case. GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); + &try_uninitialized); TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, - &if_handler, &var_handler, &miss); + if_handler, var_handler, miss); + } + + BIND(&try_uninitialized); + { + // Check uninitialized case. + GotoIfNot( + WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)), + miss); + exit_point->ReturnCallStub(CodeFactory::LoadIC_Uninitialized(isolate()), + p->context, p->receiver, p->name, p->slot, + p->vector); + } +} + +void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) { + Label miss(this); + Node* receiver = p->receiver; + GotoIf(TaggedIsSmi(receiver), &miss); + Node* receiver_map = LoadMap(receiver); + Node* instance_type = LoadMapInstanceType(receiver_map); + + // Optimistically write the state transition to the vector. + StoreFixedArrayElement(p->vector, p->slot, + LoadRoot(Heap::kpremonomorphic_symbolRootIndex), + SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); + + Label not_function_prototype(this); + GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), + ¬_function_prototype); + GotoIfNot(WordEqual(p->name, LoadRoot(Heap::kprototype_stringRootIndex)), + ¬_function_prototype); + Node* bit_field = LoadMapBitField(receiver_map); + GotoIf(IsSetWord32(bit_field, 1 << Map::kHasNonInstancePrototype), + ¬_function_prototype); + // Function.prototype load. + { + // TODO(jkummerow): Unify with LoadIC_FunctionPrototype builtin + // (when we have a shared CSA base class for all builtins). + Node* proto_or_map = + LoadObjectField(receiver, JSFunction::kPrototypeOrInitialMapOffset); + GotoIf(IsTheHole(proto_or_map), &miss); + + VARIABLE(var_result, MachineRepresentation::kTagged, proto_or_map); + Label done(this, &var_result); + GotoIfNot(IsMap(proto_or_map), &done); + + var_result.Bind(LoadMapPrototype(proto_or_map)); + Goto(&done); + + BIND(&done); + Return(var_result.value()); } - Bind(&miss); + BIND(¬_function_prototype); + + GenericPropertyLoad(receiver, receiver_map, instance_type, p->name, p, &miss, + kDontUseStubCache); + + BIND(&miss); { + // Undo the optimistic state transition. + StoreFixedArrayElement(p->vector, p->slot, + LoadRoot(Heap::kuninitialized_symbolRootIndex), + SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); + TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, p->slot, p->vector); } @@ -1504,14 +1922,14 @@ void AccessorAssembler::LoadICProtoArray( Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler); - Node* holder = - EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags, - &miss, throw_reference_error_if_nonexistent); + Node* holder = EmitLoadICProtoArrayCheck(p, handler, handler_length, + handler_flags, &miss); HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit, + throw_reference_error_if_nonexistent, kOnlyProperties); - Bind(&miss); + BIND(&miss); { TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, p->slot, p->vector); @@ -1528,40 +1946,56 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( // 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)); + CSA_ASSERT(this, IsPropertyCell(property_cell)); Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); GotoIf(WordEqual(value, TheHoleConstant()), miss); exit_point->Return(value); } -void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p, +void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* pp, TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss) { Comment("LoadGlobalIC_TryHandlerCase"); - Label call_handler(this); + Label call_handler(this), non_smi(this); Node* handler = - LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); - CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler))); + LoadFixedArrayElement(pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS); GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), miss); - GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); + + GotoIfNot(TaggedIsSmi(handler), &non_smi); bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF; - HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point, + + { + LoadICParameters p = *pp; + DCHECK_NULL(p.receiver); + Node* native_context = LoadNativeContext(p.context); + p.receiver = + LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX); + Node* holder = LoadContextElement(native_context, Context::EXTENSION_INDEX); + HandleLoadICSmiHandlerCase(&p, holder, handler, miss, exit_point, + throw_reference_error_if_nonexistent, + kOnlyProperties); + } + + BIND(&non_smi); + GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); + + HandleLoadGlobalICHandlerCase(pp, handler, miss, exit_point, throw_reference_error_if_nonexistent); - Bind(&call_handler); + BIND(&call_handler); { LoadWithVectorDescriptor descriptor(isolate()); - Node* native_context = LoadNativeContext(p->context); + Node* native_context = LoadNativeContext(pp->context); Node* receiver = - LoadContextElement(native_context, Context::EXTENSION_INDEX); - exit_point->ReturnCallStub(descriptor, handler, p->context, receiver, - p->name, p->slot, p->vector); + LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX); + exit_point->ReturnCallStub(descriptor, handler, pp->context, receiver, + pp->name, pp->slot, pp->vector); } } @@ -1575,38 +2009,44 @@ void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p, void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode) { + // Must be kept in sync with Interpreter::BuildLoadGlobal. + ExitPoint direct_exit(this); Label try_handler(this), miss(this); LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit, &try_handler, &miss); - Bind(&try_handler); + BIND(&try_handler); LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss); - Bind(&miss); + BIND(&miss); LoadGlobalIC_MissCase(p, &direct_exit); } void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { - Variable var_handler(this, MachineRepresentation::kTagged); - // TODO(ishell): defer blocks when it works. - Label if_handler(this, &var_handler), try_polymorphic(this), - try_megamorphic(this /*, Label::kDeferred*/), - try_polymorphic_name(this /*, Label::kDeferred*/), - miss(this /*, Label::kDeferred*/); + ExitPoint direct_exit(this); + + VARIABLE(var_handler, MachineRepresentation::kTagged); + Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred), + try_megamorphic(this, Label::kDeferred), + try_polymorphic_name(this, Label::kDeferred), + miss(this, Label::kDeferred); Node* receiver_map = LoadReceiverMap(p->receiver); - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); + GotoIf(IsDeprecatedMap(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(&if_handler); + { + HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit, + kSupportElements); + } - Bind(&try_polymorphic); + BIND(&try_polymorphic); { // Check polymorphic case. Comment("KeyedLoadIC_try_polymorphic"); @@ -1616,7 +2056,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { &miss, 2); } - Bind(&try_megamorphic); + BIND(&try_megamorphic); { // Check megamorphic case. Comment("KeyedLoadIC_try_megamorphic"); @@ -1626,21 +2066,19 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context, p->receiver, p->name, p->slot, p->vector); } - Bind(&try_polymorphic_name); + BIND(&try_polymorphic_name); { // We might have a name in feedback, and a fixed array in the next slot. Comment("KeyedLoadIC_try_polymorphic_name"); GotoIfNot(WordEqual(feedback, p->name), &miss); // If the name comparison succeeded, we know we have a fixed array with // at least one map/handler pair. - Node* offset = ElementOffsetFromIndex( - p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS, - FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag); - Node* array = Load(MachineType::AnyTagged(), p->vector, offset); + Node* array = + LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss, 1); } - Bind(&miss); + BIND(&miss); { Comment("KeyedLoadIC_miss"); TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, @@ -1649,8 +2087,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) { } void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { - Variable var_index(this, MachineType::PointerRepresentation()); - Variable var_unique(this, MachineRepresentation::kTagged); + VARIABLE(var_index, MachineType::PointerRepresentation()); + VARIABLE(var_unique, MachineRepresentation::kTagged); var_unique.Bind(p->name); // Dummy initialization. Label if_index(this), if_unique_name(this), slow(this); @@ -1662,19 +2100,19 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, &slow); - Bind(&if_index); + BIND(&if_index); { GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(), &slow); } - Bind(&if_unique_name); + BIND(&if_unique_name); { GenericPropertyLoad(receiver, receiver_map, instance_type, var_unique.value(), p, &slow); } - Bind(&slow); + BIND(&slow); { Comment("KeyedLoadGeneric_slow"); IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); @@ -1684,27 +2122,27 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { } } -void AccessorAssembler::StoreIC(const StoreICParameters* p) { - Variable var_handler(this, MachineRepresentation::kTagged); - // TODO(ishell): defer blocks when it works. - Label if_handler(this, &var_handler), try_polymorphic(this), - try_megamorphic(this /*, Label::kDeferred*/), - miss(this /*, Label::kDeferred*/); +void AccessorAssembler::StoreIC(const StoreICParameters* p, + LanguageMode language_mode) { + VARIABLE(var_handler, MachineRepresentation::kTagged); + Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred), + try_megamorphic(this, Label::kDeferred), + try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred); Node* receiver_map = LoadReceiverMap(p->receiver); - GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss); + GotoIf(IsDeprecatedMap(receiver_map), &miss); // Check monomorphic case. Node* feedback = TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler, &var_handler, &try_polymorphic); - Bind(&if_handler); + BIND(&if_handler); { Comment("StoreIC_if_handler"); HandleStoreICHandlerCase(p, var_handler.value(), &miss); } - Bind(&try_polymorphic); + BIND(&try_polymorphic); { // Check polymorphic case. Comment("StoreIC_try_polymorphic"); @@ -1715,16 +2153,26 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { &miss, 2); } - Bind(&try_megamorphic); + BIND(&try_megamorphic); { // Check megamorphic case. GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), - &miss); + &try_uninitialized); TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name, &if_handler, &var_handler, &miss); } - Bind(&miss); + BIND(&try_uninitialized); + { + // Check uninitialized case. + GotoIfNot( + WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)), + &miss); + TailCallStub(CodeFactory::StoreIC_Uninitialized(isolate(), language_mode), + p->context, p->receiver, p->name, p->value, p->slot, + p->vector); + } + BIND(&miss); { TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot, p->vector, p->receiver, p->name); @@ -1733,80 +2181,40 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode) { - // TODO(ishell): defer blocks when it works. - Label miss(this /*, Label::kDeferred*/); + Label miss(this, Label::kDeferred); { - Variable var_handler(this, MachineRepresentation::kTagged); + VARIABLE(var_handler, 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*/); + Label if_handler(this, &var_handler), + try_polymorphic(this, Label::kDeferred), + 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); + GotoIf(IsDeprecatedMap(receiver_map), &miss); // Check monomorphic case. Node* feedback = TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler, &var_handler, &try_polymorphic); - Bind(&if_handler); + BIND(&if_handler); { Comment("KeyedStoreIC_if_handler"); HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements); } - Bind(&try_polymorphic); + BIND(&try_polymorphic); { // CheckPolymorphic case. Comment("KeyedStoreIC_try_polymorphic"); GotoIfNot( 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); - GotoIfNot(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); - } - } + HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler, + &miss, 2); } - Bind(&try_megamorphic); + BIND(&try_megamorphic); { // Check megamorphic case. Comment("KeyedStoreIC_try_megamorphic"); @@ -1818,22 +2226,20 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p, p->context, p->receiver, p->name, p->value, p->slot, p->vector); } - Bind(&try_polymorphic_name); + BIND(&try_polymorphic_name); { // We might have a name in feedback, and a fixed array in the next slot. Comment("KeyedStoreIC_try_polymorphic_name"); GotoIfNot(WordEqual(feedback, p->name), &miss); // If the name comparison succeeded, we know we have a FixedArray with // at least one map/handler pair. - Node* offset = ElementOffsetFromIndex( - p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS, - FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag); - Node* array = Load(MachineType::AnyTagged(), p->vector, offset); + Node* array = LoadFixedArrayElement(p->vector, p->slot, kPointerSize, + SMI_PARAMETERS); HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss, 1); } } - Bind(&miss); + BIND(&miss); { Comment("KeyedStoreIC_miss"); TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot, @@ -1856,6 +2262,47 @@ void AccessorAssembler::GenerateLoadIC() { LoadIC(&p); } +void AccessorAssembler::GenerateLoadIC_Noninlined() { + 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); + + ExitPoint direct_exit(this); + VARIABLE(var_handler, MachineRepresentation::kTagged); + Label if_handler(this, &var_handler), miss(this, Label::kDeferred); + + Node* receiver_map = LoadReceiverMap(receiver); + Node* feedback = LoadFixedArrayElement(vector, slot, 0, SMI_PARAMETERS); + + LoadICParameters p(context, receiver, name, slot, vector); + LoadIC_Noninlined(&p, receiver_map, feedback, &var_handler, &if_handler, + &miss, &direct_exit); + + BIND(&if_handler); + HandleLoadICHandlerCase(&p, var_handler.value(), &miss, &direct_exit); + + BIND(&miss); + direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, + slot, vector); +} + +void AccessorAssembler::GenerateLoadIC_Uninitialized() { + 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_Uninitialized(&p); +} + void AccessorAssembler::GenerateLoadICTrampoline() { typedef LoadDescriptor Descriptor; @@ -1865,8 +2312,8 @@ void AccessorAssembler::GenerateLoadICTrampoline() { Node* context = Parameter(Descriptor::kContext); Node* vector = LoadFeedbackVectorForStub(); - LoadICParameters p(context, receiver, name, slot, vector); - LoadIC(&p); + Callable callable = CodeFactory::LoadICInOptimizedCode(isolate()); + TailCallStub(callable, context, receiver, name, slot, vector); } void AccessorAssembler::GenerateLoadICProtoArray( @@ -1896,8 +2343,16 @@ void AccessorAssembler::GenerateLoadField() { ExitPoint direct_exit(this); - HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler), - nullptr, &direct_exit, kOnlyProperties); + VARIABLE(var_double_value, MachineRepresentation::kFloat64); + Label rebox_double(this, &var_double_value); + + Node* smi_handler = Parameter(Descriptor::kSmiHandler); + Node* handler_word = SmiUntag(smi_handler); + HandleLoadField(receiver, handler_word, &var_double_value, &rebox_double, + &direct_exit); + + BIND(&rebox_double); + Return(AllocateHeapNumberWithValue(var_double_value.value())); } void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) { @@ -1920,8 +2375,9 @@ void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) { Node* context = Parameter(Descriptor::kContext); Node* vector = LoadFeedbackVectorForStub(); - LoadICParameters p(context, nullptr, name, slot, vector); - LoadGlobalIC(&p, typeof_mode); + Callable callable = + CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode); + TailCallStub(callable, context, name, slot, vector); } void AccessorAssembler::GenerateKeyedLoadIC() { @@ -1946,8 +2402,8 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() { Node* context = Parameter(Descriptor::kContext); Node* vector = LoadFeedbackVectorForStub(); - LoadICParameters p(context, receiver, name, slot, vector); - KeyedLoadIC(&p); + Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate()); + TailCallStub(callable, context, receiver, name, slot, vector); } void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { @@ -1963,7 +2419,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() { KeyedLoadICGeneric(&p); } -void AccessorAssembler::GenerateStoreIC() { +void AccessorAssembler::GenerateStoreIC(LanguageMode language_mode) { typedef StoreWithVectorDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1974,10 +2430,10 @@ void AccessorAssembler::GenerateStoreIC() { Node* context = Parameter(Descriptor::kContext); StoreICParameters p(context, receiver, name, value, slot, vector); - StoreIC(&p); + StoreIC(&p, language_mode); } -void AccessorAssembler::GenerateStoreICTrampoline() { +void AccessorAssembler::GenerateStoreICTrampoline(LanguageMode language_mode) { typedef StoreDescriptor Descriptor; Node* receiver = Parameter(Descriptor::kReceiver); @@ -1987,8 +2443,9 @@ void AccessorAssembler::GenerateStoreICTrampoline() { Node* context = Parameter(Descriptor::kContext); Node* vector = LoadFeedbackVectorForStub(); - StoreICParameters p(context, receiver, name, value, slot, vector); - StoreIC(&p); + Callable callable = + CodeFactory::StoreICInOptimizedCode(isolate(), language_mode); + TailCallStub(callable, context, receiver, name, value, slot, vector); } void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) { @@ -2016,8 +2473,9 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline( Node* context = Parameter(Descriptor::kContext); Node* vector = LoadFeedbackVectorForStub(); - StoreICParameters p(context, receiver, name, value, slot, vector); - KeyedStoreIC(&p, language_mode); + Callable callable = + CodeFactory::KeyedStoreICInOptimizedCode(isolate(), language_mode); + TailCallStub(callable, context, receiver, name, value, slot, vector); } } // namespace internal diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index 9bc2873f85..f2cafdb128 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -24,13 +24,15 @@ class AccessorAssembler : public CodeStubAssembler { : CodeStubAssembler(state) {} void GenerateLoadIC(); + void GenerateLoadIC_Noninlined(); + void GenerateLoadIC_Uninitialized(); void GenerateLoadField(); void GenerateLoadICTrampoline(); void GenerateKeyedLoadIC(); void GenerateKeyedLoadICTrampoline(); void GenerateKeyedLoadIC_Megamorphic(); - void GenerateStoreIC(); - void GenerateStoreICTrampoline(); + void GenerateStoreIC(LanguageMode language_mode); + void GenerateStoreICTrampoline(LanguageMode language_mode); void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent); @@ -75,6 +77,10 @@ class AccessorAssembler : public CodeStubAssembler { ExitPoint* exit_point, Label* miss); void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point); + // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame + // construction on common paths. + void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point); + protected: struct StoreICParameters : public LoadICParameters { StoreICParameters(Node* context, Node* receiver, Node* name, Node* value, @@ -88,17 +94,25 @@ class AccessorAssembler : public CodeStubAssembler { void HandleStoreICHandlerCase( const StoreICParameters* p, Node* handler, Label* miss, ElementSupport support_elements = kOnlyProperties); + void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); private: // Stub generation entry points. + // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains + // logic not inlined into Ignition bytecode handlers. void LoadIC(const LoadICParameters* p); + void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map, + Node* feedback, Variable* var_handler, + Label* if_handler, Label* miss, ExitPoint* exit_point); + + void LoadIC_Uninitialized(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 StoreIC(const StoreICParameters* p, LanguageMode language_mode); void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode); // IC dispatcher behavior. @@ -109,22 +123,18 @@ class AccessorAssembler : public CodeStubAssembler { 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); + Label* if_miss, int min_feedback_capacity); // LoadIC implementation. void HandleLoadICHandlerCase( const LoadICParameters* p, Node* handler, Label* miss, - ElementSupport support_elements = kOnlyProperties); + ExitPoint* exit_point, ElementSupport support_elements = kOnlyProperties); void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, ExitPoint* exit_point, + bool throw_reference_error_if_nonexistent, ElementSupport support_elements); void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, @@ -134,10 +144,13 @@ class AccessorAssembler : public CodeStubAssembler { ExitPoint* exit_point, bool throw_reference_error_if_nonexistent); + void HandleLoadField(Node* holder, Node* handler_word, + Variable* var_double_value, Label* rebox_double, + ExitPoint* exit_point); + Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, Node* handler_length, Node* handler_flags, - Label* miss, - bool throw_reference_error_if_nonexistent); + Label* miss); // LoadGlobalIC implementation. @@ -151,7 +164,7 @@ class AccessorAssembler : public CodeStubAssembler { Node* handler, Label* miss); void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler, - Label* miss); + Label* miss, ElementSupport support_elements); // If |transition| is nullptr then the normal field store is generated or // transitioning store otherwise. void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, @@ -167,9 +180,11 @@ class AccessorAssembler : public CodeStubAssembler { void GenericElementLoad(Node* receiver, Node* receiver_map, Node* instance_type, Node* index, Label* slow); + enum UseStubCache { kUseStubCache, kDontUseStubCache }; void GenericPropertyLoad(Node* receiver, Node* receiver_map, Node* instance_type, Node* key, - const LoadICParameters* p, Label* slow); + const LoadICParameters* p, Label* slow, + UseStubCache use_stub_cache = kUseStubCache); // Low-level helpers. diff --git a/deps/v8/src/ic/arm/access-compiler-arm.cc b/deps/v8/src/ic/arm/access-compiler-arm.cc index e501cdcc8b..627c06c858 100644 --- a/deps/v8/src/ic/arm/access-compiler-arm.cc +++ b/deps/v8/src/ic/arm/access-compiler-arm.cc @@ -6,6 +6,8 @@ #include "src/ic/access-compiler.h" +#include "src/objects-inl.h" + namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc index ebef63ca66..dd99a21219 100644 --- a/deps/v8/src/ic/arm/handler-compiler-arm.cc +++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc @@ -7,6 +7,7 @@ #include "src/ic/handler-compiler.h" #include "src/api-arguments.h" +#include "src/assembler-inl.h" #include "src/field-type.h" #include "src/ic/call-optimization.h" #include "src/ic/ic.h" @@ -17,43 +18,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- r0 : receiver - // -- r2 : name - // -- lr : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(cp); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ldr(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(r1, holder, accessor_index, ACCESSOR_GETTER); - __ mov(r0, Operand(0)); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(cp); } @@ -199,24 +170,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ b(ne, miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -288,13 +241,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } - // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -347,8 +293,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -413,15 +358,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -430,10 +374,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -445,92 +387,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ cmp(r0, scratch1()); - __ b(eq, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -569,41 +431,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(result, ip); - __ b(eq, &miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r1, r3); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc index b749027ebe..5cf9dc46ae 100644 --- a/deps/v8/src/ic/arm/ic-arm.cc +++ b/deps/v8/src/ic/arm/ic-arm.cc @@ -4,9 +4,11 @@ #if V8_TARGET_ARCH_ARM +#include "src/assembler-inl.h" #include "src/codegen.h" #include "src/ic/ic.h" #include "src/ic/stub-cache.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/arm64/access-compiler-arm64.cc b/deps/v8/src/ic/arm64/access-compiler-arm64.cc index 8cbb5278ea..1b58e5c697 100644 --- a/deps/v8/src/ic/arm64/access-compiler-arm64.cc +++ b/deps/v8/src/ic/arm64/access-compiler-arm64.cc @@ -5,6 +5,7 @@ #if V8_TARGET_ARCH_ARM64 #include "src/ic/access-compiler.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc index b7dc58974f..68bd393cab 100644 --- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc +++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc @@ -7,6 +7,8 @@ #include "src/ic/handler-compiler.h" #include "src/api-arguments.h" +#include "src/arm64/assembler-arm64-inl.h" +#include "src/arm64/macro-assembler-arm64-inl.h" #include "src/field-type.h" #include "src/ic/call-optimization.h" #include "src/ic/ic.h" @@ -99,22 +101,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -190,13 +176,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } - // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -258,38 +237,13 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( __ Ret(); } - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ Push(cp); - - if (accessor_index >= 0) { - DCHECK(!AreAliased(holder, scratch)); - DCHECK(!AreAliased(receiver, scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ Ldr(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ Push(receiver); - __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER); - __ Mov(x0, 0); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ Pop(cp); } @@ -300,39 +254,6 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter( #define __ ACCESS_MASM(masm()) -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - Register NamedStoreHandlerCompiler::value() { return StoreDescriptor::ValueRegister(); } @@ -373,8 +294,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // object_reg and holder_reg registers can alias. @@ -439,15 +359,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -457,10 +376,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { __ B(&success); __ Bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ Bind(&success); @@ -474,94 +391,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { __ B(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ Bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), - scratch3())); - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex, - &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ Bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(this->name(), holder_reg, receiver()); - } else { - __ Pop(this->name(), holder_reg); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc index 8c7d4f2241..f77bb8af5b 100644 --- a/deps/v8/src/ic/arm64/ic-arm64.cc +++ b/deps/v8/src/ic/arm64/ic-arm64.cc @@ -4,9 +4,11 @@ #if V8_TARGET_ARCH_ARM64 +#include "src/arm64/assembler-arm64-inl.h" #include "src/codegen.h" #include "src/ic/ic.h" #include "src/ic/stub-cache.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -69,7 +71,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address, // to // tb(!n)z test_reg, #0, <target> Instruction* to_patch = info.SmiCheck(); - PatchingAssembler patcher(isolate, to_patch, 1); + PatchingAssembler patcher(isolate, reinterpret_cast<byte*>(to_patch), 1); DCHECK(to_patch->IsTestBranch()); DCHECK(to_patch->ImmTestBranchBit5() == 0); DCHECK(to_patch->ImmTestBranchBit40() == 0); diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc new file mode 100644 index 0000000000..29df4bf082 --- /dev/null +++ b/deps/v8/src/ic/binary-op-assembler.cc @@ -0,0 +1,827 @@ +// 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/binary-op-assembler.h" + +#include "src/globals.h" + +namespace v8 { +namespace internal { + +using compiler::Node; + +Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry for floating point addition. + Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred), + check_rhsisoddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_add_stub(this), end(this); + VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64); + VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64); + VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); + VARIABLE(var_result, MachineRepresentation::kTagged); + + // Check if the {lhs} is a Smi or a HeapObject. + Label if_lhsissmi(this), if_lhsisnotsmi(this); + Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + + BIND(&if_lhsissmi); + { + // Check if the {rhs} is also a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + BIND(&if_rhsissmi); + { + // Try fast Smi addition first. + Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs), + BitcastTaggedToWord(rhs)); + Node* overflow = Projection(1, pair); + + // Check if the Smi additon overflowed. + Label if_overflow(this), if_notoverflow(this); + Branch(overflow, &if_overflow, &if_notoverflow); + + BIND(&if_overflow); + { + var_fadd_lhs.Bind(SmiToFloat64(lhs)); + var_fadd_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fadd); + } + + BIND(&if_notoverflow); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); + Goto(&end); + } + } + + BIND(&if_rhsisnotsmi); + { + // Load the map of {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_fadd_lhs.Bind(SmiToFloat64(lhs)); + var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fadd); + } + } + + BIND(&if_lhsisnotsmi); + { + // Load the map of {lhs}. + Node* lhs_map = LoadMap(lhs); + + // Check if {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if the {rhs} is Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + BIND(&if_rhsissmi); + { + var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fadd_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fadd); + } + + BIND(&if_rhsisnotsmi); + { + // Load the map of {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fadd); + } + } + + BIND(&do_fadd); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); + Node* result = AllocateHeapNumberWithValue(value); + var_result.Bind(result); + Goto(&end); + } + + BIND(&if_lhsisnotnumber); + { + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + Label if_lhsisoddball(this), if_lhsisnotoddball(this); + Node* lhs_instance_type = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball); + + BIND(&if_lhsisoddball); + { + GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); + + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, + &check_rhsisoddball); + } + + BIND(&if_lhsisnotoddball); + { + // Exit unless {lhs} is a string + GotoIfNot(IsStringInstanceType(lhs_instance_type), + &call_with_any_feedback); + + // Check if the {rhs} is a smi, and exit the string check early if it is. + GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); + + Node* rhs_instance_type = LoadInstanceType(rhs); + + // Exit unless {rhs} is a string. Since {lhs} is a string we no longer + // need an Oddball check. + GotoIfNot(IsStringInstanceType(rhs_instance_type), + &call_with_any_feedback); + + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString)); + Callable callable = + CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + + Goto(&end); + } + } + + BIND(&check_rhsisoddball); + { + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + BIND(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_add_stub); + } + + BIND(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_add_stub); + } + + BIND(&call_add_stub); + { + Callable callable = CodeFactory::Add(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + BIND(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry for floating point subtraction. + Label do_fsub(this), end(this), call_subtract_stub(this), + if_lhsisnotnumber(this), check_rhsisoddball(this), + call_with_any_feedback(this); + VARIABLE(var_fsub_lhs, MachineRepresentation::kFloat64); + VARIABLE(var_fsub_rhs, MachineRepresentation::kFloat64); + VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); + VARIABLE(var_result, MachineRepresentation::kTagged); + + // Check if the {lhs} is a Smi or a HeapObject. + Label if_lhsissmi(this), if_lhsisnotsmi(this); + Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + + BIND(&if_lhsissmi); + { + // Check if the {rhs} is also a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + BIND(&if_rhsissmi); + { + // Try a fast Smi subtraction first. + Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs), + BitcastTaggedToWord(rhs)); + Node* overflow = Projection(1, pair); + + // Check if the Smi subtraction overflowed. + Label if_overflow(this), if_notoverflow(this); + Branch(overflow, &if_overflow, &if_notoverflow); + + BIND(&if_overflow); + { + // lhs, rhs - smi and result - number. combined - number. + // The result doesn't fit into Smi range. + var_fsub_lhs.Bind(SmiToFloat64(lhs)); + var_fsub_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fsub); + } + + BIND(&if_notoverflow); + // lhs, rhs, result smi. combined - smi. + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); + Goto(&end); + } + + BIND(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Perform a floating point subtraction. + var_fsub_lhs.Bind(SmiToFloat64(lhs)); + var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fsub); + } + } + + BIND(&if_lhsisnotsmi); + { + // Load the map of the {lhs}. + Node* lhs_map = LoadMap(lhs); + + // Check if the {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if the {rhs} is a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + BIND(&if_rhsissmi); + { + // Perform a floating point subtraction. + var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fsub_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fsub); + } + + BIND(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Perform a floating point subtraction. + var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fsub); + } + } + + BIND(&do_fsub); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* lhs_value = var_fsub_lhs.value(); + Node* rhs_value = var_fsub_rhs.value(); + Node* value = Float64Sub(lhs_value, rhs_value); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + BIND(&if_lhsisnotnumber); + { + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + // Check if lhs is an oddball. + Node* lhs_instance_type = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(lhs_is_oddball, &call_with_any_feedback); + + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + BIND(&if_rhsissmi); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + + BIND(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + } + + BIND(&check_rhsisoddball); + { + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(rhs_is_oddball, &call_with_any_feedback); + + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + + BIND(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_subtract_stub); + } + + BIND(&call_subtract_stub); + { + Callable callable = CodeFactory::Subtract(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + BIND(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point multiplication. + Label do_fmul(this), if_lhsisnotnumber(this, Label::kDeferred), + check_rhsisoddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_multiply_stub(this), end(this); + VARIABLE(var_lhs_float64, MachineRepresentation::kFloat64); + VARIABLE(var_rhs_float64, MachineRepresentation::kFloat64); + VARIABLE(var_result, MachineRepresentation::kTagged); + VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); + + Label lhs_is_smi(this), lhs_is_not_smi(this); + Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); + + BIND(&lhs_is_smi); + { + Label rhs_is_smi(this), rhs_is_not_smi(this); + Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + + BIND(&rhs_is_smi); + { + // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, + // in case of overflow. + var_result.Bind(SmiMul(lhs, rhs)); + var_type_feedback.Bind( + SelectSmiConstant(TaggedIsSmi(var_result.value()), + BinaryOperationFeedback::kSignedSmall, + BinaryOperationFeedback::kNumber)); + Goto(&end); + } + + BIND(&rhs_is_not_smi); + { + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Convert {lhs} to a double and multiply it with the value of {rhs}. + var_lhs_float64.Bind(SmiToFloat64(lhs)); + var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fmul); + } + } + + BIND(&lhs_is_not_smi); + { + Node* lhs_map = LoadMap(lhs); + + // Check if {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if {rhs} is a Smi. + Label rhs_is_smi(this), rhs_is_not_smi(this); + Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + + BIND(&rhs_is_smi); + { + // Convert {rhs} to a double and multiply it with the value of {lhs}. + var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); + var_rhs_float64.Bind(SmiToFloat64(rhs)); + Goto(&do_fmul); + } + + BIND(&rhs_is_not_smi); + { + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Both {lhs} and {rhs} are HeapNumbers. Load their values and + // multiply them. + var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); + var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fmul); + } + } + + BIND(&do_fmul); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); + Node* result = AllocateHeapNumberWithValue(value); + var_result.Bind(result); + Goto(&end); + } + + BIND(&if_lhsisnotnumber); + { + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + // Check if lhs is an oddball. + Node* lhs_instance_type = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(lhs_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); + + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, + &check_rhsisoddball); + } + + BIND(&check_rhsisoddball); + { + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + BIND(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_multiply_stub); + } + + BIND(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_multiply_stub); + } + + BIND(&call_multiply_stub); + { + Callable callable = CodeFactory::Multiply(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + BIND(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_DivideWithFeedback(Node* context, + Node* dividend, + Node* divisor, + Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point division. + Label do_fdiv(this), dividend_is_not_number(this, Label::kDeferred), + check_divisor_for_oddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_divide_stub(this), end(this); + VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64); + VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64); + VARIABLE(var_result, MachineRepresentation::kTagged); + VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); + + Label dividend_is_smi(this), dividend_is_not_smi(this); + Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); + + BIND(÷nd_is_smi); + { + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + BIND(&divisor_is_smi); + { + Label bailout(this); + + // Try to perform Smi division if possible. + var_result.Bind(TrySmiDiv(dividend, divisor, &bailout)); + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + Goto(&end); + + // Bailout: convert {dividend} and {divisor} to double and do double + // division. + BIND(&bailout); + { + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fdiv); + } + } + + BIND(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Convert {dividend} to a double and divide it with the value of + // {divisor}. + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fdiv); + } + + BIND(÷nd_is_not_smi); + { + Node* dividend_map = LoadMap(dividend); + + // Check if {dividend} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); + + // Check if {divisor} is a Smi. + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + BIND(&divisor_is_smi); + { + // Convert {divisor} to a double and use it for a floating point + // division. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fdiv); + } + + BIND(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Both {dividend} and {divisor} are HeapNumbers. Load their values + // and divide them. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fdiv); + } + } + } + + BIND(&do_fdiv); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = + Float64Div(var_dividend_float64.value(), var_divisor_float64.value()); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + BIND(÷nd_is_not_number); + { + // We just know dividend is not a number or Smi. No checks on divisor yet. + // Check if dividend is an oddball. + Node* dividend_instance_type = LoadInstanceType(dividend); + Node* dividend_is_oddball = + Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(dividend_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); + + // Load the map of the {divisor}. + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, + &check_divisor_for_oddball); + } + + BIND(&check_divisor_for_oddball); + { + // Check if divisor is an oddball. At this point we know dividend is either + // a Smi or number or oddball and divisor is not a number or Smi. + Node* divisor_instance_type = LoadInstanceType(divisor); + Node* divisor_is_oddball = + Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + BIND(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_divide_stub); + } + + BIND(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_divide_stub); + } + + BIND(&call_divide_stub); + { + Callable callable = CodeFactory::Divide(isolate()); + var_result.Bind(CallStub(callable, context, dividend, divisor)); + Goto(&end); + } + + BIND(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_ModulusWithFeedback(Node* context, + Node* dividend, + Node* divisor, + Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point division. + Label do_fmod(this), dividend_is_not_number(this, Label::kDeferred), + check_divisor_for_oddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_modulus_stub(this), end(this); + VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64); + VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64); + VARIABLE(var_result, MachineRepresentation::kTagged); + VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); + + Label dividend_is_smi(this), dividend_is_not_smi(this); + Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); + + BIND(÷nd_is_smi); + { + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + BIND(&divisor_is_smi); + { + var_result.Bind(SmiMod(dividend, divisor)); + var_type_feedback.Bind( + SelectSmiConstant(TaggedIsSmi(var_result.value()), + BinaryOperationFeedback::kSignedSmall, + BinaryOperationFeedback::kNumber)); + Goto(&end); + } + + BIND(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Convert {dividend} to a double and divide it with the value of + // {divisor}. + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fmod); + } + } + + BIND(÷nd_is_not_smi); + { + Node* dividend_map = LoadMap(dividend); + + // Check if {dividend} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); + + // Check if {divisor} is a Smi. + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + BIND(&divisor_is_smi); + { + // Convert {divisor} to a double and use it for a floating point + // division. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fmod); + } + + BIND(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Both {dividend} and {divisor} are HeapNumbers. Load their values + // and divide them. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fmod); + } + } + + BIND(&do_fmod); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = + Float64Mod(var_dividend_float64.value(), var_divisor_float64.value()); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + BIND(÷nd_is_not_number); + { + // No checks on divisor yet. We just know dividend is not a number or Smi. + // Check if dividend is an oddball. + Node* dividend_instance_type = LoadInstanceType(dividend); + Node* dividend_is_oddball = + Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(dividend_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); + + // Load the map of the {divisor}. + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, + &check_divisor_for_oddball); + } + + BIND(&check_divisor_for_oddball); + { + // Check if divisor is an oddball. At this point we know dividend is either + // a Smi or number or oddball and divisor is not a number or Smi. + Node* divisor_instance_type = LoadInstanceType(divisor); + Node* divisor_is_oddball = + Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + BIND(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_modulus_stub); + } + + BIND(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_modulus_stub); + } + + BIND(&call_modulus_stub); + { + Callable callable = CodeFactory::Modulus(isolate()); + var_result.Bind(CallStub(callable, context, dividend, divisor)); + Goto(&end); + } + + BIND(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/ic/binary-op-assembler.h b/deps/v8/src/ic/binary-op-assembler.h new file mode 100644 index 0000000000..849dfc29dc --- /dev/null +++ b/deps/v8/src/ic/binary-op-assembler.h @@ -0,0 +1,45 @@ +// Copyright 2017 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_BINARY_OP_ASSEMBLER_H_ +#define V8_SRC_IC_BINARY_OP_ASSEMBLER_H_ + +#include "src/code-stub-assembler.h" + +namespace v8 { +namespace internal { + +namespace compiler { +class CodeAssemblerState; +} + +class BinaryOpAssembler : public CodeStubAssembler { + public: + typedef compiler::Node Node; + + explicit BinaryOpAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_DivideWithFeedback(Node* context, Node* dividend, + Node* divisor, Node* slot_id, + Node* feedback_vector); + + Node* Generate_ModulusWithFeedback(Node* context, Node* dividend, + Node* divisor, Node* slot_id, + Node* feedback_vector); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_SRC_IC_BINARY_OP_ASSEMBLER_H_ diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc index 6a9734d5eb..69ba39768a 100644 --- a/deps/v8/src/ic/handler-compiler.cc +++ b/deps/v8/src/ic/handler-compiler.cc @@ -4,6 +4,7 @@ #include "src/ic/handler-compiler.h" +#include "src/assembler-inl.h" #include "src/field-type.h" #include "src/ic/call-optimization.h" #include "src/ic/handler-configuration-inl.h" @@ -16,9 +17,8 @@ namespace internal { Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, Handle<Map> stub_holder, - Code::Kind kind, - CacheHolderFlag cache_holder) { - Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder); + Code::Kind kind) { + Code::Flags flags = Code::ComputeHandlerFlags(kind); Code* code = stub_holder->LookupInCodeCache(*name, flags); if (code == nullptr) return Handle<Code>(); return handle(code); @@ -26,10 +26,27 @@ Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, Handle<Name> name) { - Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder()); - Handle<Code> code = GetCodeWithFlags(flags, name); + Code::Flags flags = Code::ComputeHandlerFlags(kind); + + // Create code object in the heap. + CodeDesc desc; + masm()->GetCode(&desc); + Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject()); + if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey()); +#ifdef ENABLE_DISASSEMBLER + if (FLAG_print_code_stubs) { + char* raw_name = !name.is_null() && name->IsString() + ? String::cast(*name)->ToCString().get() + : nullptr; + CodeTracer::Scope trace_scope(isolate()->GetCodeTracer()); + OFStream os(trace_scope.file()); + code->Disassemble(raw_name, os); + } +#endif + PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG, AbstractCode::cast(*code), *name)); + #ifdef DEBUG code->VerifyEmbeddedObjects(); #endif @@ -39,11 +56,9 @@ Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, #define __ ACCESS_MASM(masm()) - Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss, - ReturnHolder return_what) { + Label* miss) { if (map()->IsPrimitiveMap() || map()->IsJSGlobalProxyMap()) { // If the receiver is a global proxy and if we get to this point then // the compile-time (current) native context has access to global proxy's @@ -60,7 +75,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, // Check that the maps starting from the prototype haven't changed. return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, - miss, return_what); + miss); } @@ -68,8 +83,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, // miss. Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss, - ReturnHolder return_what) { + Label* miss) { if (map()->IsJSGlobalProxyMap()) { Handle<Context> native_context = isolate()->native_context(); Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate()); @@ -77,7 +91,7 @@ Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, } return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, - miss, return_what); + miss); } @@ -86,7 +100,7 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { if (IC::ShouldPushPopSlotAndVector(kind())) { PushVectorAndSlot(); } - Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER); + Register reg = FrontendHeader(receiver(), name, &miss); FrontendFooter(name, &miss); // The footer consumes the vector and slot from the stack if miss occurs. if (IC::ShouldPushPopSlotAndVector(kind())) { @@ -96,16 +110,6 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { } Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( - Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) { - if (V8_UNLIKELY(FLAG_runtime_stats)) { - GenerateTailCall(masm(), slow_stub); - } - Register reg = Frontend(name); - GenerateLoadCallback(reg, callback); - return GetCode(kind(), name); -} - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( Handle<Name> name, const CallOptimization& call_optimization, int accessor_index, Handle<Code> slow_stub) { DCHECK(call_optimization.is_simple_api_call()); @@ -118,199 +122,6 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( return GetCode(kind(), name); } - -void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) { - if (IC::ShouldPushPopSlotAndVector(kind())) { - if (holder_reg.is(receiver())) { - PushVectorAndSlot(); - } else { - DCHECK(holder_reg.is(scratch1())); - PushVectorAndSlot(scratch2(), scratch3()); - } - } -} - - -void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg, - PopMode mode) { - if (IC::ShouldPushPopSlotAndVector(kind())) { - if (mode == DISCARD) { - DiscardVectorAndSlot(); - } else { - if (holder_reg.is(receiver())) { - PopVectorAndSlot(); - } else { - DCHECK(holder_reg.is(scratch1())); - PopVectorAndSlot(scratch2(), scratch3()); - } - } - } -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( - LookupIterator* it) { - // So far the most popular follow ups for interceptor loads are DATA and - // AccessorInfo, so inline only them. Other cases may be added - // later. - bool inline_followup = false; - switch (it->state()) { - case LookupIterator::TRANSITION: - UNREACHABLE(); - case LookupIterator::ACCESS_CHECK: - case LookupIterator::INTERCEPTOR: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - case LookupIterator::INTEGER_INDEXED_EXOTIC: - break; - 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()) { - Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); - inline_followup = - info->getter() != NULL && - AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map()); - } else if (accessors->IsAccessorPair()) { - Handle<JSObject> property_holder(it->GetHolder<JSObject>()); - Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), - isolate()); - if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) { - break; - } - if (!property_holder->HasFastProperties()) break; - CallOptimization call_optimization(getter); - Handle<Map> receiver_map = map(); - inline_followup = call_optimization.is_simple_api_call() && - call_optimization.IsCompatibleReceiverMap( - receiver_map, property_holder); - } - } - } - - Label miss; - InterceptorVectorSlotPush(receiver()); - bool lost_holder_register = false; - auto holder_orig = holder(); - // non masking interceptors must check the entire chain, so temporarily reset - // the holder to be that last element for the FrontendHeader call. - if (holder()->GetNamedInterceptor()->non_masking()) { - DCHECK(!inline_followup); - JSObject* last = *holder(); - PrototypeIterator iter(isolate(), last); - while (!iter.IsAtEnd()) { - lost_holder_register = true; - // Casting to JSObject is fine here. The LookupIterator makes sure to - // look behind non-masking interceptors during the original lookup, and - // we wouldn't try to compile a handler if there was a Proxy anywhere. - last = iter.GetCurrent<JSObject>(); - iter.Advance(); - } - auto last_handle = handle(last); - set_holder(last_handle); - } - Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER); - // Reset the holder so further calculations are correct. - set_holder(holder_orig); - if (lost_holder_register) { - if (*it->GetReceiver() == *holder()) { - reg = receiver(); - } else { - // Reload lost holder register. - auto cell = isolate()->factory()->NewWeakCell(holder()); - __ LoadWeakValue(reg, cell, &miss); - } - } - FrontendFooter(it->name(), &miss); - InterceptorVectorSlotPop(reg); - if (inline_followup) { - // TODO(368): Compile in the whole chain: all the interceptors in - // prototypes and ultimate answer. - GenerateLoadInterceptorWithFollowup(it, reg); - } else { - GenerateLoadInterceptor(reg); - } - return GetCode(kind(), it->name()); -} - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle<AccessorInfo> callback) { - DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister())); - __ Move(ApiGetterDescriptor::HolderRegister(), reg); - // The callback is alive if this instruction is executed, - // so the weak cell is not cleared and points to data. - Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback); - __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - -void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( - LookupIterator* it, Register interceptor_reg) { - Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); - - Handle<Map> holder_map(holder()->map()); - set_map(holder_map); - set_holder(real_named_property_holder); - - Label miss; - InterceptorVectorSlotPush(interceptor_reg); - Register reg = - FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER); - FrontendFooter(it->name(), &miss); - // We discard the vector and slot now because we don't miss below this point. - InterceptorVectorSlotPop(reg, DISCARD); - - switch (it->state()) { - case LookupIterator::ACCESS_CHECK: - case LookupIterator::INTERCEPTOR: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - case LookupIterator::INTEGER_INDEXED_EXOTIC: - case LookupIterator::TRANSITION: - UNREACHABLE(); - case LookupIterator::DATA: { - 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); - GenerateTailCall(masm(), isolate()->builtins()->LoadField()); - break; - } - case LookupIterator::ACCESSOR: - if (it->GetAccessors()->IsAccessorInfo()) { - Handle<AccessorInfo> info = - Handle<AccessorInfo>::cast(it->GetAccessors()); - DCHECK_NOT_NULL(info->getter()); - GenerateLoadCallback(reg, info); - } else { - Handle<Object> function = handle( - AccessorPair::cast(*it->GetAccessors())->getter(), isolate()); - CallOptimization call_optimization(function); - GenerateApiAccessorCall(masm(), call_optimization, holder_map, - receiver(), scratch2(), false, no_reg, reg, - it->GetAccessorIndex()); - } - } -} - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( - Handle<Name> name, int accessor_index, int expected_arguments) { - Register holder = Frontend(name); - GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index, - expected_arguments, scratch2()); - return GetCode(kind(), name); -} - Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( Handle<JSObject> object, Handle<Name> name, int accessor_index, int expected_arguments) { @@ -341,51 +152,5 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( #undef __ -// static -Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler( - Handle<Map> receiver_map, Isolate* isolate) { - if (receiver_map->has_indexed_interceptor() && - !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) && - !receiver_map->GetIndexedInterceptor()->non_masking()) { - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub); - return LoadIndexedInterceptorStub(isolate).GetCode(); - } - if (receiver_map->IsStringMap()) { - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub); - return isolate->builtins()->KeyedLoadIC_IndexedString(); - } - InstanceType instance_type = receiver_map->instance_type(); - if (instance_type < FIRST_JS_RECEIVER_TYPE) { - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub); - return isolate->builtins()->KeyedLoadIC_Slow(); - } - - ElementsKind elements_kind = receiver_map->elements_kind(); - if (IsSloppyArgumentsElements(elements_kind)) { - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub); - return KeyedLoadSloppyArgumentsStub(isolate).GetCode(); - } - bool is_js_array = instance_type == JS_ARRAY_TYPE; - if (elements_kind == DICTIONARY_ELEMENTS) { - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH); - return LoadHandler::LoadElement(isolate, elements_kind, false, is_js_array); - } - DCHECK(IsFastElementsKind(elements_kind) || - IsFixedTypedArrayElementsKind(elements_kind)); - // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind). - bool convert_hole_to_undefined = - is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && - *receiver_map == isolate->get_initial_js_array_map(elements_kind); - TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH); - return LoadHandler::LoadElement(isolate, elements_kind, - convert_hole_to_undefined, is_js_array); -} - -void ElementHandlerCompiler::CompileElementHandlers( - MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { - for (int i = 0; i < receiver_maps->length(); ++i) { - handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); - } -} } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h index a37375abfb..4eb1b464c3 100644 --- a/deps/v8/src/ic/handler-compiler.h +++ b/deps/v8/src/ic/handler-compiler.h @@ -13,24 +13,19 @@ namespace internal { class CallOptimization; -enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING }; - class PropertyHandlerCompiler : public PropertyAccessCompiler { public: - static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind, - CacheHolderFlag cache_holder); + static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind); protected: PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map, - Handle<JSObject> holder, CacheHolderFlag cache_holder) - : PropertyAccessCompiler(isolate, kind, cache_holder), - map_(map), - holder_(holder) {} + Handle<JSObject> holder) + : PropertyAccessCompiler(isolate, kind), map_(map), holder_(holder) {} virtual ~PropertyHandlerCompiler() {} virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss, ReturnHolder return_what) { + Label* miss) { UNREACHABLE(); return receiver(); } @@ -104,13 +99,10 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler { // holder_reg. Register CheckPrototypes(Register object_reg, Register holder_reg, Register scratch1, Register scratch2, - Handle<Name> name, Label* miss, - ReturnHolder return_what); + Handle<Name> name, Label* miss); Handle<Code> GetCode(Code::Kind kind, Handle<Name> name); - void set_holder(Handle<JSObject> holder) { holder_ = holder; } Handle<Map> map() const { return map_; } - void set_map(Handle<Map> map) { map_ = map; } Handle<JSObject> holder() const { return holder_; } private: @@ -122,70 +114,24 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler { class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { public: NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map, - Handle<JSObject> holder, - CacheHolderFlag cache_holder) - : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder, - cache_holder) {} + Handle<JSObject> holder) + : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder) {} virtual ~NamedLoadHandlerCompiler() {} Handle<Code> CompileLoadCallback(Handle<Name> name, - Handle<AccessorInfo> callback, - Handle<Code> slow_stub); - - Handle<Code> CompileLoadCallback(Handle<Name> name, const CallOptimization& call_optimization, int accessor_index, Handle<Code> slow_stub); - // The LookupIterator is used to perform a lookup behind the interceptor. If - // the iterator points to a LookupIterator::PROPERTY, its access will be - // inlined. - Handle<Code> CompileLoadInterceptor(LookupIterator* it); - - Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index, - int expected_arguments); - - Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name, - bool is_configurable); - - static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map, - Register receiver, Register holder, - int accessor_index, int expected_arguments, - Register scratch); - - static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { - GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, - no_reg); - } - - // These constants describe the structure of the interceptor arguments on the - // stack. The arguments are pushed by the (platform-specific) - // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and - // LoadWithInterceptor. - static const int kInterceptorArgsNameIndex = 0; - static const int kInterceptorArgsThisIndex = 1; - static const int kInterceptorArgsHolderIndex = 2; - static const int kInterceptorArgsLength = 3; + static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm); protected: virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss, ReturnHolder return_what); + Label* miss); virtual void FrontendFooter(Handle<Name> name, Label* miss); private: - void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback); - - // Helper emits no code if vector-ics are disabled. - void InterceptorVectorSlotPush(Register holder_reg); - enum PopMode { POP, DISCARD }; - void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP); - - void GenerateLoadInterceptor(Register holder_reg); - void GenerateLoadInterceptorWithFollowup(LookupIterator* it, - Register holder_reg); - void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); - Register scratch3() { return registers_[4]; } }; @@ -197,8 +143,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map, Handle<JSObject> holder) - : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder, - kCacheOnReceiver) { + : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder) { #ifdef DEBUG if (Descriptor::kPassLastArgsOnStack) { ZapStackArgumentsRegisterAliases(); @@ -232,7 +177,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { protected: virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss, ReturnHolder return_what); + Label* miss); virtual void FrontendFooter(Handle<Name> name, Label* miss); void GenerateRestoreName(Label* label, Handle<Name> name); @@ -241,21 +186,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { static Register value(); }; - -class ElementHandlerCompiler : public PropertyHandlerCompiler { - public: - explicit ElementHandlerCompiler(Isolate* isolate) - : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, - Handle<Map>::null(), Handle<JSObject>::null(), - kCacheOnReceiver) {} - - virtual ~ElementHandlerCompiler() {} - - static Handle<Object> GetKeyedLoadHandler(Handle<Map> receiver_map, - Isolate* isolate); - void CompileElementHandlers(MapHandleList* receiver_maps, - List<Handle<Object>>* handlers); -}; } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h index 437c5288fb..2b9dc04b5a 100644 --- a/deps/v8/src/ic/handler-configuration-inl.h +++ b/deps/v8/src/ic/handler-configuration-inl.h @@ -13,76 +13,94 @@ namespace v8 { namespace internal { -Handle<Object> LoadHandler::LoadField(Isolate* isolate, - FieldIndex field_index) { - int config = KindBits::encode(kForFields) | +Handle<Smi> LoadHandler::LoadNormal(Isolate* isolate) { + int config = KindBits::encode(kNormal); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> LoadHandler::LoadGlobal(Isolate* isolate) { + int config = KindBits::encode(kGlobal); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) { + int config = KindBits::encode(kInterceptor); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) { + int config = KindBits::encode(kField) | IsInobjectBits::encode(field_index.is_inobject()) | IsDoubleBits::encode(field_index.is_double()) | FieldOffsetBits::encode(field_index.offset()); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) { - int config = KindBits::encode(kForConstants) | - IsAccessorInfoBits::encode(false) | - DescriptorValueIndexBits::encode( - DescriptorArray::ToValueIndex(descriptor)); +Handle<Smi> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) { + int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(false) | + DescriptorBits::encode(descriptor); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> LoadHandler::LoadAccessor(Isolate* isolate, int descriptor) { + int config = KindBits::encode(kAccessor) | IsAccessorInfoBits::encode(false) | + DescriptorBits::encode(descriptor); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) { - int config = KindBits::encode(kForConstants) | - IsAccessorInfoBits::encode(true) | - DescriptorValueIndexBits::encode( - DescriptorArray::ToValueIndex(descriptor)); +Handle<Smi> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) { + int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) | + DescriptorBits::encode(descriptor); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::EnableAccessCheckOnReceiver( - Isolate* isolate, Handle<Object> smi_handler) { - int config = Smi::cast(*smi_handler)->value(); +Handle<Smi> LoadHandler::EnableAccessCheckOnReceiver(Isolate* isolate, + Handle<Smi> smi_handler) { + int config = smi_handler->value(); #ifdef DEBUG Kind kind = KindBits::decode(config); - DCHECK_NE(kForElements, kind); + DCHECK_NE(kElement, kind); #endif config = DoAccessCheckOnReceiverBits::update(config, true); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::EnableNegativeLookupOnReceiver( - Isolate* isolate, Handle<Object> smi_handler) { - int config = Smi::cast(*smi_handler)->value(); +Handle<Smi> LoadHandler::EnableLookupOnReceiver(Isolate* isolate, + Handle<Smi> smi_handler) { + int config = smi_handler->value(); #ifdef DEBUG Kind kind = KindBits::decode(config); - DCHECK_NE(kForElements, kind); + DCHECK_NE(kElement, kind); #endif - config = DoNegativeLookupOnReceiverBits::update(config, true); + config = LookupOnReceiverBits::update(config, true); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::LoadNonExistent( - Isolate* isolate, bool do_negative_lookup_on_receiver) { - int config = - KindBits::encode(kForNonExistent) | - DoNegativeLookupOnReceiverBits::encode(do_negative_lookup_on_receiver); +Handle<Smi> LoadHandler::LoadNonExistent(Isolate* isolate) { + int config = KindBits::encode(kNonExistent); return handle(Smi::FromInt(config), isolate); } -Handle<Object> LoadHandler::LoadElement(Isolate* isolate, - ElementsKind elements_kind, - bool convert_hole_to_undefined, - bool is_js_array) { - int config = KindBits::encode(kForElements) | +Handle<Smi> LoadHandler::LoadElement(Isolate* isolate, + ElementsKind elements_kind, + bool convert_hole_to_undefined, + bool is_js_array) { + int config = KindBits::encode(kElement) | ElementsKindBits::encode(elements_kind) | ConvertHoleBits::encode(convert_hole_to_undefined) | IsJsArrayBits::encode(is_js_array); return handle(Smi::FromInt(config), isolate); } -Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind, - int descriptor, FieldIndex field_index, - Representation representation, - bool extend_storage) { +Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) { + int config = KindBits::encode(kStoreNormal); + return handle(Smi::FromInt(config), isolate); +} + +Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind, + int descriptor, FieldIndex field_index, + Representation representation, + bool extend_storage) { StoreHandler::FieldRepresentation field_rep; switch (representation.kind()) { case Representation::kSmi: @@ -99,9 +117,8 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind, break; default: UNREACHABLE(); - return Handle<Object>::null(); + return Handle<Smi>::null(); } - int value_index = DescriptorArray::ToValueIndex(descriptor); DCHECK(kind == kStoreField || kind == kTransitionToField || (kind == kStoreConstField && FLAG_track_constant_fields)); @@ -112,36 +129,35 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind, StoreHandler::ExtendStorageBits::encode(extend_storage) | StoreHandler::IsInobjectBits::encode(field_index.is_inobject()) | StoreHandler::FieldRepresentationBits::encode(field_rep) | - StoreHandler::DescriptorValueIndexBits::encode(value_index) | + StoreHandler::DescriptorBits::encode(descriptor) | StoreHandler::FieldOffsetBits::encode(field_index.offset()); return handle(Smi::FromInt(config), isolate); } -Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor, - FieldIndex field_index, - PropertyConstness constness, - Representation representation) { +Handle<Smi> StoreHandler::StoreField(Isolate* isolate, int descriptor, + FieldIndex field_index, + PropertyConstness constness, + Representation representation) { DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable); Kind kind = constness == kMutable ? kStoreField : kStoreConstField; return StoreField(isolate, kind, descriptor, field_index, representation, false); } -Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor, - FieldIndex field_index, - Representation representation, - bool extend_storage) { +Handle<Smi> StoreHandler::TransitionToField(Isolate* isolate, int descriptor, + FieldIndex field_index, + Representation representation, + bool extend_storage) { return StoreField(isolate, kTransitionToField, descriptor, field_index, representation, extend_storage); } -Handle<Object> StoreHandler::TransitionToConstant(Isolate* isolate, - int descriptor) { +Handle<Smi> StoreHandler::TransitionToConstant(Isolate* isolate, + int descriptor) { DCHECK(!FLAG_track_constant_fields); - int value_index = DescriptorArray::ToValueIndex(descriptor); int config = StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) | - StoreHandler::DescriptorValueIndexBits::encode(value_index); + StoreHandler::DescriptorBits::encode(descriptor); return handle(Smi::FromInt(config), isolate); } diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index 539d448008..ab117d5c9b 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -16,19 +16,28 @@ namespace internal { // A set of bit fields representing Smi handlers for loads. class LoadHandler { public: - enum Kind { kForElements, kForFields, kForConstants, kForNonExistent }; - class KindBits : public BitField<Kind, 0, 2> {}; + enum Kind { + kElement, + kNormal, + kGlobal, + kField, + kConstant, + kAccessor, + kInterceptor, + kNonExistent + }; + class KindBits : public BitField<Kind, 0, 3> {}; // Defines whether access rights check should be done on receiver object. - // Applicable to kForFields, kForConstants and kForNonExistent kinds only when - // loading value from prototype chain. Ignored when loading from holder. + // Applicable to named property kinds only when loading value from prototype + // chain. Ignored when loading from holder. class DoAccessCheckOnReceiverBits : public BitField<bool, KindBits::kNext, 1> {}; - // Defines whether negative lookup check should be done on receiver object. - // Applicable to kForFields, kForConstants and kForNonExistent kinds only when - // loading value from prototype chain. Ignored when loading from holder. - class DoNegativeLookupOnReceiverBits + // Defines whether a lookup should be done on receiver object before + // proceeding to the prototype chain. Applicable to named property kinds only + // when loading value from prototype chain. Ignored when loading from holder. + class LookupOnReceiverBits : public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {}; // @@ -36,20 +45,18 @@ class LoadHandler { // class IsAccessorInfoBits - : public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {}; + : public BitField<bool, LookupOnReceiverBits::kNext, 1> {}; // Index of a value entry in the descriptor array. - // +2 here is because each descriptor entry occupies 3 slots in array. - class DescriptorValueIndexBits - : public BitField<unsigned, IsAccessorInfoBits::kNext, - kDescriptorIndexBitCount + 2> {}; + class DescriptorBits : public BitField<unsigned, IsAccessorInfoBits::kNext, + kDescriptorIndexBitCount> {}; // Make sure we don't overflow the smi. - STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize); + STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize); // - // Encoding when KindBits contains kForFields. + // Encoding when KindBits contains kField. // - class IsInobjectBits - : public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {}; + class IsInobjectBits : public BitField<bool, LookupOnReceiverBits::kNext, 1> { + }; class IsDoubleBits : public BitField<bool, IsInobjectBits::kNext, 1> {}; // +1 here is to cover all possible JSObject header sizes. class FieldOffsetBits @@ -59,7 +66,7 @@ class LoadHandler { STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize); // - // Encoding when KindBits contains kForElements. + // Encoding when KindBits contains kElement. // class IsJsArrayBits : public BitField<bool, KindBits::kNext, 1> {}; class ConvertHoleBits : public BitField<bool, IsJsArrayBits::kNext, 1> {}; @@ -83,36 +90,47 @@ class LoadHandler { static const int kHolderCellIndex = 2; static const int kFirstPrototypeIndex = 3; + // Creates a Smi-handler for loading a property from a slow object. + static inline Handle<Smi> LoadNormal(Isolate* isolate); + + // Creates a Smi-handler for loading a property from a global object. + static inline Handle<Smi> LoadGlobal(Isolate* isolate); + + // Creates a Smi-handler for loading a property from an object with an + // interceptor. + static inline Handle<Smi> LoadInterceptor(Isolate* isolate); + // Creates a Smi-handler for loading a field from fast object. - static inline Handle<Object> LoadField(Isolate* isolate, - FieldIndex field_index); + static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index); // Creates a Smi-handler for loading a constant from fast object. - static inline Handle<Object> LoadConstant(Isolate* isolate, int descriptor); + static inline Handle<Smi> LoadConstant(Isolate* isolate, int descriptor); + + // Creates a Smi-handler for calling a getter on a fast object. + static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor); // Creates a Smi-handler for loading an Api getter property from fast object. - static inline Handle<Object> LoadApiGetter(Isolate* isolate, int descriptor); + static inline Handle<Smi> LoadApiGetter(Isolate* isolate, int descriptor); // Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver // check is a part of a prototype chain check. - static inline Handle<Object> EnableAccessCheckOnReceiver( - Isolate* isolate, Handle<Object> smi_handler); + static inline Handle<Smi> EnableAccessCheckOnReceiver( + Isolate* isolate, Handle<Smi> smi_handler); - // Sets DoNegativeLookupOnReceiverBits in given Smi-handler. The receiver + // Sets LookupOnReceiverBits in given Smi-handler. The receiver // check is a part of a prototype chain check. - static inline Handle<Object> EnableNegativeLookupOnReceiver( - Isolate* isolate, Handle<Object> smi_handler); + static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate, + Handle<Smi> smi_handler); // Creates a Smi-handler for loading a non-existent property. Works only as // a part of prototype chain check. - static inline Handle<Object> LoadNonExistent( - Isolate* isolate, bool do_negative_lookup_on_receiver); + static inline Handle<Smi> LoadNonExistent(Isolate* isolate); // Creates a Smi-handler for loading an element. - static inline Handle<Object> LoadElement(Isolate* isolate, - ElementsKind elements_kind, - bool convert_hole_to_undefined, - bool is_js_array); + static inline Handle<Smi> LoadElement(Isolate* isolate, + ElementsKind elements_kind, + bool convert_hole_to_undefined, + bool is_js_array); }; // A set of bit fields representing Smi handlers for stores. @@ -122,11 +140,12 @@ class StoreHandler { kStoreElement, kStoreField, kStoreConstField, + kStoreNormal, kTransitionToField, // TODO(ishell): remove once constant field tracking is done. kTransitionToConstant = kStoreConstField }; - class KindBits : public BitField<Kind, 0, 2> {}; + class KindBits : public BitField<Kind, 0, 3> {}; enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged }; @@ -134,22 +153,19 @@ class StoreHandler { // kinds. // Index of a value entry in the descriptor array. - // +2 here is because each descriptor entry occupies 3 slots in array. - class DescriptorValueIndexBits - : public BitField<unsigned, KindBits::kNext, - kDescriptorIndexBitCount + 2> {}; + class DescriptorBits + : public BitField<unsigned, KindBits::kNext, kDescriptorIndexBitCount> {}; // // Encoding when KindBits contains kTransitionToConstant. // // Make sure we don't overflow the smi. - STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize); + STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize); // // Encoding when KindBits contains kStoreField or kTransitionToField. // - class ExtendStorageBits - : public BitField<bool, DescriptorValueIndexBits::kNext, 1> {}; + class ExtendStorageBits : public BitField<bool, DescriptorBits::kNext, 1> {}; class IsInobjectBits : public BitField<bool, ExtendStorageBits::kNext, 1> {}; class FieldRepresentationBits : public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {}; @@ -175,29 +191,30 @@ class StoreHandler { static const int kFirstPrototypeIndex = 3; // Creates a Smi-handler for storing a field to fast object. - static inline Handle<Object> StoreField(Isolate* isolate, int descriptor, - FieldIndex field_index, - PropertyConstness constness, - Representation representation); + static inline Handle<Smi> StoreField(Isolate* isolate, int descriptor, + FieldIndex field_index, + PropertyConstness constness, + Representation representation); + + // Creates a Smi-handler for storing a property to a slow object. + static inline Handle<Smi> StoreNormal(Isolate* isolate); // Creates a Smi-handler for transitioning store to a field. - static inline Handle<Object> TransitionToField(Isolate* isolate, - int descriptor, - FieldIndex field_index, - Representation representation, - bool extend_storage); + static inline Handle<Smi> TransitionToField(Isolate* isolate, int descriptor, + FieldIndex field_index, + Representation representation, + bool extend_storage); // Creates a Smi-handler for transitioning store to a constant field (in this // case the only thing that needs to be done is an update of a map). - static inline Handle<Object> TransitionToConstant(Isolate* isolate, - int descriptor); + static inline Handle<Smi> TransitionToConstant(Isolate* isolate, + int descriptor); private: - static inline Handle<Object> StoreField(Isolate* isolate, Kind kind, - int descriptor, - FieldIndex field_index, - Representation representation, - bool extend_storage); + static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind, + int descriptor, FieldIndex field_index, + Representation representation, + bool extend_storage); }; } // namespace internal diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc index f0f8faddde..324dc10d03 100644 --- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc +++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc @@ -17,37 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(esi); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(scratch, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER); - __ Set(eax, 0); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(esi); @@ -201,12 +177,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the code. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); __ mov(api_function_address, Immediate(function_address)); @@ -293,23 +263,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - #undef __ #define __ ACCESS_MASM(masm()) @@ -347,8 +300,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -413,15 +365,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -451,102 +402,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ push(receiver()); - } - __ push(holder_reg); - __ push(this->name()); - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ cmp(eax, factory()->no_interceptor_result_sentinel()); - __ j(equal, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - // Clobber registers when generating debug-code to provoke errors. - __ bind(&interceptor_failed); - if (FLAG_debug_code) { - __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue))); - __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue))); - __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue))); - } - - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - // Call the runtime system to load the interceptor. - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(receiver()); - __ push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ push(slot()); - __ push(vector()); - } else { - __ push(scratch3()); // slot - __ push(scratch2()); // vector - } - __ push(Operand(esp, 4 * kPointerSize)); // return address - __ mov(Operand(esp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { // Zap register aliases of the arguments passed on the stack to ensure they // are properly loaded by the handler (debug-only). @@ -595,43 +450,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ShouldPushPopSlotAndVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ mov(result, FieldOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ cmp(result, factory()->the_hole_value()); - __ j(equal, &miss); - } else if (FLAG_debug_code) { - __ cmp(result, factory()->the_hole_value()); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1); - // The code above already loads the result into the return register. - if (IC::ShouldPushPopSlotAndVector(kind())) { - DiscardVectorAndSlot(); - } - __ ret(0); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h index aacb69091e..8ac3bd99da 100644 --- a/deps/v8/src/ic/ic-inl.h +++ b/deps/v8/src/ic/ic-inl.h @@ -86,44 +86,10 @@ Code* IC::target() const { bool IC::IsHandler(Object* object) { return (object->IsSmi() && (object != nullptr)) || object->IsTuple2() || - object->IsTuple3() || object->IsFixedArray() || + object->IsTuple3() || object->IsFixedArray() || object->IsWeakCell() || (object->IsCode() && Code::cast(object)->is_handler()); } -Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map, - bool receiver_is_holder, Isolate* isolate, - CacheHolderFlag* flag) { - if (receiver_is_holder) { - *flag = kCacheOnReceiver; - return receiver_map; - } - Handle<JSFunction> builtin_ctor; - if (Map::GetConstructorFunction(receiver_map, isolate->native_context()) - .ToHandle(&builtin_ctor)) { - *flag = kCacheOnPrototypeReceiverIsPrimitive; - return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map()); - } - *flag = receiver_map->is_dictionary_map() - ? kCacheOnPrototypeReceiverIsDictionary - : kCacheOnPrototype; - // Callers must ensure that the prototype is non-null. - return handle(JSObject::cast(receiver_map->prototype())->map()); -} - - -Handle<Map> IC::GetICCacheHolder(Handle<Map> map, Isolate* isolate, - CacheHolderFlag* flag) { - Handle<JSFunction> builtin_ctor; - if (Map::GetConstructorFunction(map, isolate->native_context()) - .ToHandle(&builtin_ctor)) { - *flag = kCacheOnPrototype; - return handle(builtin_ctor->initial_map()); - } - *flag = kCacheOnReceiver; - return map; -} - - bool IC::AddressIsDeoptimizedCode() const { return AddressIsDeoptimizedCode(isolate(), address()); } diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index f11f94a770..b3b0eb4c84 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -4,8 +4,6 @@ #include "src/ic/ic.h" -#include <iostream> - #include "src/accessors.h" #include "src/api-arguments-inl.h" #include "src/api.h" @@ -70,7 +68,6 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { void IC::TraceIC(const char* type, Handle<Object> name) { if (FLAG_ic_stats) { if (AddressIsDeoptimizedCode()) return; - DCHECK(UseVector()); State new_state = nexus()->StateFromFeedback(); TraceIC(type, name, state(), new_state); } @@ -228,7 +225,6 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); if (nexus) { kind_ = nexus->kind(); - DCHECK(UseVector()); state_ = nexus->StateFromFeedback(); extra_ic_state_ = kNoExtraICState; } else { @@ -244,7 +240,6 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) UNREACHABLE(); kind_ = FeedbackSlotKind::kInvalid; } - DCHECK(!UseVector()); state_ = StateFromCode(target); extra_ic_state_ = target->extra_ic_state(); } @@ -316,8 +311,7 @@ static void LookupForRead(LookupIterator* it) { break; } case LookupIterator::ACCESS_CHECK: - // PropertyHandlerCompiler::CheckPrototypes() knows how to emit - // access checks for global proxies. + // ICs know how to perform access checks on global proxies. if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) { break; } @@ -333,7 +327,6 @@ static void LookupForRead(LookupIterator* it) { bool IC::ShouldRecomputeHandler(Handle<String> name) { if (!RecomputeHandlerForName(name)) return false; - DCHECK(UseVector()); maybe_handler_ = nexus()->FindHandlerForMap(receiver_map()); // This is a contextual access, always just update the handler and stay @@ -362,7 +355,6 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) { if (is_keyed()) { // Determine whether the failure is due to a name failure. if (!name->IsName()) return false; - DCHECK(UseVector()); Name* stub_name = nexus()->FindFirstName(); if (*name != stub_name) return false; } @@ -442,6 +434,16 @@ void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) { TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); info->change_own_type_change_checksum(); host->set_profiler_ticks(0); + } else if (host_function->IsInterpreted()) { + if (FLAG_trace_opt_verbose) { + if (host_function->shared()->profiler_ticks() != 0) { + PrintF("[resetting ticks for "); + host_function->PrintName(); + PrintF(" due from %d due to IC change]\n", + host_function->shared()->profiler_ticks()); + } + } + host_function->shared()->set_profiler_ticks(0); } isolate->runtime_profiler()->NotifyICChanged(); // TODO(2029): When an optimized function is patched, it would @@ -452,8 +454,9 @@ void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) { void IC::PostPatching(Address address, Code* target, Code* old_target) { // Type vector based ICs update these statistics at a different time because // they don't always patch on state change. - // TODO(ishell): DCHECK - if (ICUseVector(target->kind())) return; + DCHECK(target->kind() == Code::BINARY_OP_IC || + target->kind() == Code::COMPARE_IC || + target->kind() == Code::TO_BOOLEAN_IC); DCHECK(old_target->is_inline_cache_stub()); DCHECK(target->is_inline_cache_stub()); @@ -518,20 +521,11 @@ static bool MigrateDeprecated(Handle<Object> object) { } void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { - DCHECK(UseVector()); if (new_state == PREMONOMORPHIC) { nexus()->ConfigurePremonomorphic(); } else if (new_state == MEGAMORPHIC) { - if (IsLoadIC() || IsStoreIC() || IsStoreOwnIC()) { - nexus()->ConfigureMegamorphic(); - } else if (IsKeyedLoadIC()) { - KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); - nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT); - } else { - DCHECK(IsKeyedStoreIC()); - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT); - } + DCHECK_IMPLIES(!is_keyed(), key->IsName()); + nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT); } else { UNREACHABLE(); } @@ -542,49 +536,13 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, Handle<Object> handler) { - DCHECK(UseVector()); - switch (kind_) { - case FeedbackSlotKind::kLoadProperty: { - LoadICNexus* nexus = casted_nexus<LoadICNexus>(); - nexus->ConfigureMonomorphic(map, handler); - break; - } - case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: - case FeedbackSlotKind::kLoadGlobalInsideTypeof: { - LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); - nexus->ConfigureHandlerMode(handler); - break; - } - case FeedbackSlotKind::kLoadKeyed: { - KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); - nexus->ConfigureMonomorphic(name, map, handler); - break; - } - case FeedbackSlotKind::kStoreNamedSloppy: - case FeedbackSlotKind::kStoreNamedStrict: - case FeedbackSlotKind::kStoreOwnNamed: { - StoreICNexus* nexus = casted_nexus<StoreICNexus>(); - nexus->ConfigureMonomorphic(map, handler); - break; - } - case FeedbackSlotKind::kStoreKeyedSloppy: - case FeedbackSlotKind::kStoreKeyedStrict: { - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigureMonomorphic(name, map, handler); - break; - } - case FeedbackSlotKind::kCall: - case FeedbackSlotKind::kBinaryOp: - case FeedbackSlotKind::kCompareOp: - case FeedbackSlotKind::kToBoolean: - case FeedbackSlotKind::kCreateClosure: - case FeedbackSlotKind::kLiteral: - case FeedbackSlotKind::kGeneral: - case FeedbackSlotKind::kStoreDataPropertyInLiteral: - case FeedbackSlotKind::kInvalid: - case FeedbackSlotKind::kKindsNumber: - UNREACHABLE(); - break; + if (IsLoadGlobalIC()) { + LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); + nexus->ConfigureHandlerMode(handler); + } else { + // Non-keyed ICs don't track the name explicitly. + if (!is_keyed()) name = Handle<Name>::null(); + nexus()->ConfigureMonomorphic(name, map, handler); } vector_set_ = true; @@ -593,64 +551,15 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps, List<Handle<Object>>* handlers) { - DCHECK(UseVector()); - switch (kind_) { - case FeedbackSlotKind::kLoadProperty: { - LoadICNexus* nexus = casted_nexus<LoadICNexus>(); - nexus->ConfigurePolymorphic(maps, handlers); - break; - } - case FeedbackSlotKind::kLoadKeyed: { - KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); - nexus->ConfigurePolymorphic(name, maps, handlers); - break; - } - case FeedbackSlotKind::kStoreNamedSloppy: - case FeedbackSlotKind::kStoreNamedStrict: - case FeedbackSlotKind::kStoreOwnNamed: { - StoreICNexus* nexus = casted_nexus<StoreICNexus>(); - nexus->ConfigurePolymorphic(maps, handlers); - break; - } - case FeedbackSlotKind::kStoreKeyedSloppy: - case FeedbackSlotKind::kStoreKeyedStrict: { - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigurePolymorphic(name, maps, handlers); - break; - } - case FeedbackSlotKind::kCall: - case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: - case FeedbackSlotKind::kLoadGlobalInsideTypeof: - case FeedbackSlotKind::kBinaryOp: - case FeedbackSlotKind::kCompareOp: - case FeedbackSlotKind::kToBoolean: - case FeedbackSlotKind::kCreateClosure: - case FeedbackSlotKind::kLiteral: - case FeedbackSlotKind::kGeneral: - case FeedbackSlotKind::kStoreDataPropertyInLiteral: - case FeedbackSlotKind::kInvalid: - case FeedbackSlotKind::kKindsNumber: - UNREACHABLE(); - break; - } - - vector_set_ = true; - OnFeedbackChanged(isolate(), GetHostFunction()); -} - -void IC::ConfigureVectorState(MapHandleList* maps, - MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers) { - DCHECK(UseVector()); - DCHECK(IsKeyedStoreIC()); - KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); - nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers); + DCHECK(!IsLoadGlobalIC()); + // Non-keyed ICs don't track the name explicitly. + if (!is_keyed()) name = Handle<Name>::null(); + nexus()->ConfigurePolymorphic(name, maps, handlers); vector_set_ = true; OnFeedbackChanged(isolate(), GetHostFunction()); } - 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. @@ -771,11 +680,10 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) { int number_of_valid_maps = number_of_maps - deprecated_maps - (handler_to_overwrite != -1); - if (number_of_valid_maps >= 4) return false; + if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false; if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { return false; } - DCHECK(UseVector()); if (!nexus()->FindHandlers(&handlers, maps.length())) return false; number_of_valid_maps++; @@ -834,7 +742,7 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { DCHECK(IsHandler(*handler)); // Currently only load and store ICs support non-code handlers. - DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore()); + DCHECK(IsAnyLoad() || IsAnyStore()); switch (state()) { case UNINITIALIZED: case PREMONOMORPHIC: @@ -854,13 +762,11 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { // same key. CopyICToMegamorphicCache(name); } - DCHECK(UseVector()); ConfigureVectorState(MEGAMORPHIC, name); // Fall through. case MEGAMORPHIC: UpdateMegamorphicCache(*receiver_map(), *name, *handler); // Indicate that we've handled this case. - DCHECK(UseVector()); vector_set_ = true; break; case GENERIC: @@ -869,7 +775,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { } } -Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { +Handle<Smi> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH); return LoadHandler::LoadField(isolate, index); } @@ -880,11 +786,7 @@ template <bool fill_array = true> int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, Handle<JSObject> holder, Handle<Name> name, Handle<FixedArray> array, int first_index) { - DCHECK(holder.is_null() || holder->HasFastProperties()); - - // We don't encode the requirement to check access rights because we already - // passed the access check for current native context and the access - // can't be revoked. + if (!holder.is_null() && holder->map() == *receiver_map) return 0; HandleScope scope(isolate); int checks_count = 0; @@ -904,6 +806,8 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, checks_count++; } else if (receiver_map->IsJSGlobalObjectMap()) { + // If we are creating a handler for [Load/Store]GlobalIC then we need to + // check that the property did not appear in the global object. if (fill_array) { Handle<JSGlobalObject> global = isolate->global_object(); Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( @@ -964,25 +868,40 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map, Handle<FixedArray>(), 0); } +Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder, + Handle<Name> name, Handle<Smi> smi_handler) { + if (holder->IsJSGlobalObject() && + *smi_handler != *LoadHandler::LoadInterceptor(isolate)) { + Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder); + GlobalDictionary* dict = global->global_dictionary(); + int number = dict->FindEntry(name); + DCHECK_NE(NameDictionary::kNotFound, number); + Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(number)), + isolate); + return isolate->factory()->NewWeakCell(cell); + } + return Map::GetOrCreatePrototypeWeakCell(holder, isolate); +} + } // namespace Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, Handle<JSObject> holder, Handle<Name> name, - Handle<Object> smi_handler) { + Handle<Smi> smi_handler) { int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder, name); DCHECK_LE(0, checks_count); - if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { + if (receiver_map->IsPrimitiveMap() || + receiver_map->is_access_check_needed()) { DCHECK(!receiver_map->is_dictionary_map()); DCHECK_LE(1, checks_count); // For native context. smi_handler = LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); } else if (receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap()) { - smi_handler = - LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); + smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler); } Handle<Cell> validity_cell = @@ -990,7 +909,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, DCHECK(!validity_cell.is_null()); Handle<WeakCell> holder_cell = - Map::GetOrCreatePrototypeWeakCell(holder, isolate()); + HolderCell(isolate(), holder, name, smi_handler); if (checks_count == 0) { return isolate()->factory()->NewTuple3(holder_cell, smi_handler, @@ -1006,86 +925,49 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, return handler_array; } -Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, - Handle<Name> name) { - Handle<JSObject> holder; // null handle - int checks_count = - GetPrototypeCheckCount(isolate(), receiver_map, holder, name); +Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map, + Handle<Object> holder, Handle<Name> name, + Handle<Smi> smi_handler) { + Handle<JSObject> end; // null handle + int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name); DCHECK_LE(0, checks_count); - bool do_negative_lookup_on_receiver = - receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap(); - Handle<Object> smi_handler = - LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver); - - if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { + if (receiver_map->IsPrimitiveMap() || + receiver_map->is_access_check_needed()) { DCHECK(!receiver_map->is_dictionary_map()); DCHECK_LE(1, checks_count); // For native context. smi_handler = LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); + } else if (receiver_map->is_dictionary_map() && + !receiver_map->IsJSGlobalObjectMap()) { + smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler); } Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); if (validity_cell.is_null()) { DCHECK_EQ(0, checks_count); - validity_cell = handle(Smi::FromInt(0), isolate()); + // Lookup on receiver isn't supported in case of a simple smi handler. + if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) { + return smi_handler; + } + validity_cell = handle(Smi::kZero, isolate()); } Factory* factory = isolate()->factory(); if (checks_count == 0) { - return factory->NewTuple3(factory->null_value(), smi_handler, - validity_cell); + return factory->NewTuple3(holder, smi_handler, validity_cell); } Handle<FixedArray> handler_array(factory->NewFixedArray( LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); - handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); - InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, + handler_array->set(LoadHandler::kHolderCellIndex, *holder); + InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array, LoadHandler::kFirstPrototypeIndex); return handler_array; } -bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { - DCHECK(lookup->state() == LookupIterator::ACCESSOR); - Isolate* isolate = lookup->isolate(); - Handle<Object> accessors = lookup->GetAccessors(); - if (accessors->IsAccessorInfo()) { - Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); - if (info->getter() != NULL && - !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) { - return false; - } - } else if (accessors->IsAccessorPair()) { - Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), - isolate); - if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) { - return false; - } - Handle<JSObject> holder = lookup->GetHolder<JSObject>(); - Handle<Object> receiver = lookup->GetReceiver(); - if (holder->HasFastProperties()) { - if (getter->IsJSFunction()) { - Handle<JSFunction> function = Handle<JSFunction>::cast(getter); - if (!receiver->IsJSObject() && function->shared()->IsUserJavaScript() && - is_sloppy(function->shared()->language_mode())) { - // Calling sloppy non-builtins with a value as the receiver - // requires boxing. - return false; - } - } - CallOptimization call_optimization(getter); - if (call_optimization.is_simple_api_call() && - !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) { - return false; - } - } - } - return true; -} - - void LoadIC::UpdateCaches(LookupIterator* lookup) { if (state() == UNINITIALIZED && !IsLoadGlobalIC()) { // This is the first time we execute this inline cache. Set the target to @@ -1102,34 +984,25 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { code = slow_stub(); } else if (!lookup->IsFound()) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); - code = LoadNonExistent(receiver_map(), lookup->name()); + Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate()); + code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(), + lookup->name(), smi_handler); } else { - if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA && - lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { - DCHECK(lookup->GetReceiver()->IsJSGlobalObject()); - // Now update the cell in the feedback vector. - LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); - nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell()); - TRACE_IC("LoadGlobalIC", lookup->name()); - return; - } else if (lookup->state() == LookupIterator::ACCESSOR) { - if (!IsCompatibleReceiver(lookup, receiver_map())) { - TRACE_GENERIC_IC("incompatible receiver type"); - code = slow_stub(); + if (IsLoadGlobalIC()) { + if (lookup->TryLookupCachedProperty()) { + DCHECK_EQ(LookupIterator::DATA, lookup->state()); } - } else if (lookup->state() == LookupIterator::INTERCEPTOR) { - // 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("incompatible receiver type"); - code = slow_stub(); + if (lookup->state() == LookupIterator::DATA && + 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()); + TRACE_IC("LoadGlobalIC", lookup->name()); + return; } } - if (code.is_null()) code = ComputeHandler(lookup); + code = ComputeHandler(lookup); } PatchCache(lookup->name(), code); @@ -1150,69 +1023,17 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) { } void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { - if (!FLAG_runtime_call_stats) return; - + DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state()); + if (V8_LIKELY(!FLAG_runtime_stats)) return; if (IsAnyLoad()) { - switch (lookup->state()) { - case LookupIterator::ACCESS_CHECK: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck); - break; - case LookupIterator::INTEGER_INDEXED_EXOTIC: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Exotic); - break; - case LookupIterator::INTERCEPTOR: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Interceptor); - break; - case LookupIterator::JSPROXY: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_JSProxy); - break; - case LookupIterator::NOT_FOUND: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_NonExistent); - break; - case LookupIterator::ACCESSOR: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor); - break; - case LookupIterator::DATA: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Data); - break; - case LookupIterator::TRANSITION: - TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition); - break; - } - } else if (IsAnyStore()) { - switch (lookup->state()) { - case LookupIterator::ACCESS_CHECK: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck); - break; - case LookupIterator::INTEGER_INDEXED_EXOTIC: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Exotic); - break; - case LookupIterator::INTERCEPTOR: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Interceptor); - break; - case LookupIterator::JSPROXY: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_JSProxy); - break; - case LookupIterator::NOT_FOUND: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_NonExistent); - break; - case LookupIterator::ACCESSOR: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor); - break; - case LookupIterator::DATA: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Data); - break; - case LookupIterator::TRANSITION: - TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Transition); - break; - } + TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor); } else { - TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); + DCHECK(IsAnyStore()); + TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor); } } -Handle<Object> IC::ComputeHandler(LookupIterator* lookup, - Handle<Object> value) { +Handle<Object> IC::ComputeHandler(LookupIterator* lookup) { // Try to find a globally shared handler stub. Handle<Object> shared_handler = GetMapIndependentHandler(lookup); if (!shared_handler.is_null()) { @@ -1220,24 +1041,8 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup, return shared_handler; } - // Otherwise check the map's handler cache for a map-specific handler, and - // compile one if the cache comes up empty. - bool receiver_is_holder = - lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); - CacheHolderFlag flag; - Handle<Map> stub_holder_map; - if (IsAnyLoad()) { - stub_holder_map = IC::GetHandlerCacheHolder( - receiver_map(), receiver_is_holder, isolate(), &flag); - } else { - DCHECK(IsAnyStore()); - // Store handlers cannot be cached on prototypes. - flag = kCacheOnReceiver; - stub_holder_map = receiver_map(); - } - - Handle<Object> handler = PropertyHandlerCompiler::Find( - lookup->name(), stub_holder_map, handler_kind(), flag); + Handle<Code> handler = PropertyHandlerCompiler::Find( + lookup->name(), receiver_map(), handler_kind()); // Use the cached value if it exists, and if it is different from the // handler that just missed. if (!handler.is_null()) { @@ -1266,26 +1071,21 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup, } } - handler = CompileHandler(lookup, value, flag); - DCHECK(IC::IsHandler(*handler)); - if (handler->IsCode()) { - Handle<Code> code = Handle<Code>::cast(handler); - DCHECK_EQ(Code::ExtractCacheHolderFromFlags(code->flags()), flag); - Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); - } + handler = CompileHandler(lookup); + Map::UpdateCodeCache(receiver_map(), lookup->name(), handler); return handler; } Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { Handle<Object> receiver = lookup->GetReceiver(); if (receiver->IsString() && - Name::Equals(isolate()->factory()->length_string(), lookup->name())) { + *lookup->name() == isolate()->heap()->length_string()) { FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); return SimpleFieldLoad(isolate(), index); } if (receiver->IsStringWrapper() && - Name::Equals(isolate()->factory()->length_string(), lookup->name())) { + *lookup->name() == isolate()->heap()->length_string()) { TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub); StringLengthStub string_length_stub(isolate()); return string_length_stub.GetCode(); @@ -1293,7 +1093,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { // Use specialized code for getting prototype of functions. if (receiver->IsJSFunction() && - Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) && + *lookup->name() == isolate()->heap()->prototype_string() && receiver->IsConstructor() && !Handle<JSFunction>::cast(receiver) ->map() @@ -1307,8 +1107,27 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { Handle<JSObject> holder = lookup->GetHolder<JSObject>(); bool receiver_is_holder = receiver.is_identical_to(holder); switch (lookup->state()) { - case LookupIterator::INTERCEPTOR: - break; // Custom-compiled handler. + case LookupIterator::INTERCEPTOR: { + Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate()); + + if (holder->GetNamedInterceptor()->non_masking()) { + Handle<Object> holder_ref = isolate()->factory()->null_value(); + if (!receiver_is_holder || IsLoadGlobalIC()) { + holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate()); + } + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH); + return LoadFullChain(map, holder_ref, lookup->name(), smi_handler); + } + + if (receiver_is_holder) { + DCHECK(map->has_named_interceptor()); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH); + return smi_handler; + } + + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); + } case LookupIterator::ACCESSOR: { // Use simple field loads for some well-known callback properties. @@ -1321,98 +1140,132 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { return SimpleFieldLoad(isolate(), index); } - if (IsCompatibleReceiver(lookup, map)) { - Handle<Object> accessors = lookup->GetAccessors(); - if (accessors->IsAccessorPair()) { - if (!holder->HasFastProperties()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); - } - // When debugging we need to go the slow path to flood the accessor. - if (GetHostFunction()->shared()->HasDebugInfo()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); - } - break; // Custom-compiled handler. - } else if (accessors->IsAccessorInfo()) { - Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); - if (v8::ToCData<Address>(info->getter()) == nullptr) { + Handle<Object> accessors = lookup->GetAccessors(); + if (accessors->IsAccessorPair()) { + if (lookup->TryLookupCachedProperty()) { + DCHECK_EQ(LookupIterator::DATA, lookup->state()); + return ComputeHandler(lookup); + } + + // When debugging we need to go the slow path to flood the accessor. + if (GetHostFunction()->shared()->HasDebugInfo()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); + return slow_stub(); + } + + Handle<Object> getter(AccessorPair::cast(*accessors)->getter(), + isolate()); + if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); + return slow_stub(); + } + + CallOptimization call_optimization(getter); + if (call_optimization.is_simple_api_call()) { + if (!call_optimization.IsCompatibleReceiverMap(map, holder) || + !holder->HasFastProperties()) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } - // Ruled out by IsCompatibleReceiver() above. - DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)); - if (!holder->HasFastProperties() || - (info->is_sloppy() && !receiver->IsJSReceiver())) { - DCHECK(!holder->HasFastProperties() || !receiver_is_holder); + break; + } + + // FunctionTemplate isn't yet supported as smi-handler. + if (getter->IsFunctionTemplateInfo()) { + if (!holder->HasFastProperties()) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } - Handle<Object> smi_handler = - LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex()); + break; + } + + Handle<Smi> smi_handler; + if (holder->HasFastProperties()) { + smi_handler = + LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex()); + if (receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH); return smi_handler; } - if (!IsLoadGlobalIC()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), smi_handler); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH); + } else if (holder->IsJSGlobalObject()) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH); + smi_handler = LoadHandler::LoadGlobal(isolate()); + } else { + smi_handler = LoadHandler::LoadNormal(isolate()); + + if (receiver_is_holder) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); + return smi_handler; } - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); } + + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + + Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); + + if (v8::ToCData<Address>(info->getter()) == nullptr || + !AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map) || + !holder->HasFastProperties() || + (info->is_sloppy() && !receiver->IsJSReceiver())) { + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); + return slow_stub(); + } + + Handle<Smi> smi_handler = + LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex()); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); + if (receiver_is_holder) return smi_handler; + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } case LookupIterator::DATA: { DCHECK_EQ(kData, lookup->property_details().kind()); + Handle<Smi> smi_handler; if (lookup->is_dictionary_holder()) { - if (!IsLoadIC() && !IsLoadGlobalIC()) { // IsKeyedLoadIC()? - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + smi_handler = LoadHandler::LoadNormal(isolate()); + if (receiver_is_holder) { + if (holder->IsJSGlobalObject()) { + // TODO(verwaest): This is a workaround for code that leaks the + // global object. + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH); + smi_handler = LoadHandler::LoadGlobal(isolate()); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); + } + DCHECK(!holder->IsJSGlobalObject()); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); + return smi_handler; } + if (holder->IsJSGlobalObject()) { - break; // Custom-compiled handler. - } - // There is only one shared stub for loading normalized - // properties. It does not traverse the prototype chain, so the - // property must be found in the object for the stub to be - // applicable. - if (!receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH); + smi_handler = LoadHandler::LoadGlobal(isolate()); + } else { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); } - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal); - return isolate()->builtins()->LoadIC_Normal(); - } - // -------------- Fields -------------- - if (lookup->property_details().location() == kField) { + } else if (lookup->property_details().location() == kField) { FieldIndex field = lookup->GetFieldIndex(); - Handle<Object> smi_handler = SimpleFieldLoad(isolate(), field); - if (receiver_is_holder) { - return smi_handler; - } + smi_handler = SimpleFieldLoad(isolate(), field); + if (receiver_is_holder) return smi_handler; TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), smi_handler); - } - - // -------------- Constant properties -------------- - DCHECK_EQ(kDescriptor, lookup->property_details().location()); - Handle<Object> smi_handler = - LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); - if (receiver_is_holder) { + } else { + DCHECK_EQ(kDescriptor, lookup->property_details().location()); + smi_handler = + LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); - return smi_handler; + if (receiver_is_holder) return smi_handler; + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); } - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } - case LookupIterator::INTEGER_INDEXED_EXOTIC: - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); - return slow_stub(); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH); + return LoadHandler::LoadNonExistent(isolate()); case LookupIterator::ACCESS_CHECK: case LookupIterator::JSPROXY: case LookupIterator::NOT_FOUND: @@ -1423,114 +1276,25 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { return Handle<Code>::null(); } -Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup, - Handle<Object> unused, - CacheHolderFlag cache_holder) { +Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup) { + DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state()); Handle<JSObject> holder = lookup->GetHolder<JSObject>(); -#ifdef DEBUG - // Only used by DCHECKs below. - Handle<Object> receiver = lookup->GetReceiver(); - bool receiver_is_holder = receiver.is_identical_to(holder); -#endif - // Non-map-specific handler stubs have already been selected. - DCHECK(!receiver->IsString() || - !Name::Equals(isolate()->factory()->length_string(), lookup->name())); - DCHECK(!receiver->IsStringWrapper() || - !Name::Equals(isolate()->factory()->length_string(), lookup->name())); - - DCHECK(!( - receiver->IsJSFunction() && - Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) && - receiver->IsConstructor() && - !Handle<JSFunction>::cast(receiver) - ->map() - ->has_non_instance_prototype())); - Handle<Map> map = receiver_map(); - switch (lookup->state()) { - case LookupIterator::INTERCEPTOR: { - DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - // 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); - return compiler.CompileLoadInterceptor(&it); - } - - case LookupIterator::ACCESSOR: { -#ifdef DEBUG - int object_offset; - DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(), - &object_offset)); -#endif - - DCHECK(IsCompatibleReceiver(lookup, map)); - Handle<Object> accessors = lookup->GetAccessors(); - if (accessors->IsAccessorPair()) { - if (lookup->TryLookupCachedProperty()) { - DCHECK_EQ(LookupIterator::DATA, lookup->state()); - return ComputeHandler(lookup); - } - DCHECK(holder->HasFastProperties()); - DCHECK(!GetHostFunction()->shared()->HasDebugInfo()); - Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), - isolate()); - CallOptimization call_optimization(getter); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - if (call_optimization.is_simple_api_call()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback); - int index = lookup->GetAccessorIndex(); - Handle<Code> code = compiler.CompileLoadCallback( - lookup->name(), call_optimization, index, slow_stub()); - return code; - } - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter); - int expected_arguments = Handle<JSFunction>::cast(getter) - ->shared() - ->internal_formal_parameter_count(); - return compiler.CompileLoadViaGetter( - lookup->name(), lookup->GetAccessorIndex(), expected_arguments); - } else { - DCHECK(accessors->IsAccessorInfo()); - Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); - DCHECK(v8::ToCData<Address>(info->getter()) != nullptr); - DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)); - DCHECK(holder->HasFastProperties()); - DCHECK(!receiver_is_holder); - DCHECK(!info->is_sloppy() || receiver->IsJSReceiver()); - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - Handle<Code> code = - compiler.CompileLoadCallback(lookup->name(), info, slow_stub()); - return code; - } - UNREACHABLE(); - } - case LookupIterator::DATA: { - DCHECK(lookup->is_dictionary_holder()); - DCHECK(IsLoadIC() || IsLoadGlobalIC()); - 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; - } - - case LookupIterator::INTEGER_INDEXED_EXOTIC: - case LookupIterator::ACCESS_CHECK: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - case LookupIterator::TRANSITION: - UNREACHABLE(); - } - UNREACHABLE(); - return slow_stub(); + Handle<Object> accessors = lookup->GetAccessors(); + DCHECK(accessors->IsAccessorPair()); + DCHECK(holder->HasFastProperties()); + DCHECK(!GetHostFunction()->shared()->HasDebugInfo()); + Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), + isolate()); + CallOptimization call_optimization(getter); + NamedLoadHandlerCompiler compiler(isolate(), map, holder); + DCHECK(call_optimization.is_simple_api_call()); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback); + int index = lookup->GetAccessorIndex(); + Handle<Code> code = compiler.CompileLoadCallback( + lookup->name(), call_optimization, index, slow_stub()); + return code; } @@ -1563,8 +1327,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { TargetMaps(&target_receiver_maps); if (target_receiver_maps.length() == 0) { - Handle<Object> handler = - ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate()); + Handle<Object> handler = LoadElementHandler(receiver_map); return ConfigureVectorState(Handle<Name>(), receiver_map, handler); } @@ -1592,8 +1355,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { IsMoreGeneralElementsKindTransition( target_receiver_maps.at(0)->elements_kind(), Handle<JSObject>::cast(receiver)->GetElementsKind())) { - Handle<Object> handler = - ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate()); + Handle<Object> handler = LoadElementHandler(receiver_map); return ConfigureVectorState(Handle<Name>(), receiver_map, handler); } @@ -1616,11 +1378,67 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { } List<Handle<Object>> handlers(target_receiver_maps.length()); - ElementHandlerCompiler compiler(isolate()); - compiler.CompileElementHandlers(&target_receiver_maps, &handlers); + LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers); ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers); } +Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map) { + if (receiver_map->has_indexed_interceptor() && + !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined( + isolate()) && + !receiver_map->GetIndexedInterceptor()->non_masking()) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); + return LoadIndexedInterceptorStub(isolate()).GetCode(); + } + if (receiver_map->IsStringMap()) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringStub); + return isolate()->builtins()->KeyedLoadIC_IndexedString(); + } + InstanceType instance_type = receiver_map->instance_type(); + if (instance_type < FIRST_JS_RECEIVER_TYPE) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub); + return isolate()->builtins()->KeyedLoadIC_Slow(); + } + + ElementsKind elements_kind = receiver_map->elements_kind(); + if (IsSloppyArgumentsElementsKind(elements_kind)) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub); + return KeyedLoadSloppyArgumentsStub(isolate()).GetCode(); + } + bool is_js_array = instance_type == JS_ARRAY_TYPE; + if (elements_kind == DICTIONARY_ELEMENTS) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH); + return LoadHandler::LoadElement(isolate(), elements_kind, false, + is_js_array); + } + DCHECK(IsFastElementsKind(elements_kind) || + IsFixedTypedArrayElementsKind(elements_kind)); + // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind). + bool convert_hole_to_undefined = + is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && + *receiver_map == isolate()->get_initial_js_array_map(elements_kind); + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH); + return LoadHandler::LoadElement(isolate(), elements_kind, + convert_hole_to_undefined, is_js_array); +} + +void KeyedLoadIC::LoadElementPolymorphicHandlers( + MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { + for (int i = 0; i < receiver_maps->length(); ++i) { + Handle<Map> receiver_map(receiver_maps->at(i)); + + // Mark all stable receiver maps that have elements kind transition map + // among receiver_maps as unstable because the optimizing compilers may + // generate an elements kind transition for this kind of receivers. + if (receiver_map->is_stable()) { + Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps); + if (tmap != nullptr) { + receiver_map->NotifyLeafMapLayoutChange(); + } + } + handlers->Add(LoadElementHandler(receiver_map)); + } +} MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, Handle<Object> key) { @@ -1738,46 +1556,51 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, return it->IsCacheableTransition(); } +MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object, + Handle<Name> name, + Handle<Object> value) { + DCHECK(object->IsJSGlobalObject()); + DCHECK(name->IsString()); -MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, - Handle<Object> value, - JSReceiver::StoreFromKeyed store_mode) { - if (object->IsJSGlobalObject() && name->IsString()) { - // Look up in script context table. - Handle<String> str_name = Handle<String>::cast(name); - Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object); - Handle<ScriptContextTable> script_contexts( - global->native_context()->script_context_table()); - - ScriptContextTable::LookupResult lookup_result; - if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { - Handle<Context> script_context = ScriptContextTable::GetContext( - script_contexts, lookup_result.context_index); - if (lookup_result.mode == CONST) { - return TypeError(MessageTemplate::kConstAssign, object, name); - } + // Look up in script context table. + Handle<String> str_name = Handle<String>::cast(name); + Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object); + Handle<ScriptContextTable> script_contexts( + global->native_context()->script_context_table()); - Handle<Object> previous_value = - FixedArray::get(*script_context, lookup_result.slot_index, isolate()); + ScriptContextTable::LookupResult lookup_result; + if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { + Handle<Context> script_context = ScriptContextTable::GetContext( + script_contexts, lookup_result.context_index); + if (lookup_result.mode == CONST) { + return TypeError(MessageTemplate::kConstAssign, object, name); + } - if (previous_value->IsTheHole(isolate())) { - // Do not install stubs and stay pre-monomorphic for - // uninitialized accesses. - return ReferenceError(name); - } + Handle<Object> previous_value = + FixedArray::get(*script_context, lookup_result.slot_index, isolate()); - if (FLAG_use_ic && - StoreScriptContextFieldStub::Accepted(&lookup_result)) { - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub); - StoreScriptContextFieldStub stub(isolate(), &lookup_result); - PatchCache(name, stub.GetCode()); - } + if (previous_value->IsTheHole(isolate())) { + // Do not install stubs and stay pre-monomorphic for + // uninitialized accesses. + return ReferenceError(name); + } - script_context->set(lookup_result.slot_index, *value); - return value; + if (FLAG_use_ic && StoreScriptContextFieldStub::Accepted(&lookup_result)) { + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub); + StoreScriptContextFieldStub stub(isolate(), &lookup_result); + PatchCache(name, stub.GetCode()); } + + script_context->set(lookup_result.slot_index, *value); + return value; } + return StoreIC::Store(object, name, value); +} + +MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, + Handle<Object> value, + JSReceiver::StoreFromKeyed store_mode) { // TODO(verwaest): Let SetProperty do the migration, since storing a property // might deprecate the current map again, if value does not fit. if (MigrateDeprecated(object) || object->IsJSProxy()) { @@ -1825,7 +1648,7 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, Handle<Object> handler; if (LookupForWrite(lookup, value, store_mode)) { - handler = ComputeHandler(lookup, value); + handler = ComputeHandler(lookup); } else { TRACE_GENERIC_IC("LookupForWrite said 'false'"); handler = slow_stub(); @@ -1839,28 +1662,33 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, Handle<JSObject> holder, Handle<Map> transition, Handle<Name> name) { - int descriptor = transition->LastAdded(); - Handle<DescriptorArray> descriptors(transition->instance_descriptors()); - PropertyDetails details = descriptors->GetDetails(descriptor); - Representation representation = details.representation(); - DCHECK(!representation.IsNone()); + Handle<Object> smi_handler; + if (transition->is_dictionary_map()) { + smi_handler = StoreHandler::StoreNormal(isolate()); + } else { + int descriptor = transition->LastAdded(); + Handle<DescriptorArray> descriptors(transition->instance_descriptors()); + PropertyDetails details = descriptors->GetDetails(descriptor); + Representation representation = details.representation(); + DCHECK(!representation.IsNone()); - // Declarative handlers don't support access checks. - DCHECK(!transition->is_access_check_needed()); + // Declarative handlers don't support access checks. + DCHECK(!transition->is_access_check_needed()); - Handle<Object> smi_handler; - DCHECK_EQ(kData, details.kind()); - if (details.location() == kDescriptor) { - smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor); + DCHECK_EQ(kData, details.kind()); + if (details.location() == kDescriptor) { + smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor); - } else { - DCHECK_EQ(kField, details.location()); - bool extend_storage = - Map::cast(transition->GetBackPointer())->unused_property_fields() == 0; + } else { + DCHECK_EQ(kField, details.location()); + bool extend_storage = + Map::cast(transition->GetBackPointer())->unused_property_fields() == + 0; - FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); - smi_handler = StoreHandler::TransitionToField( - isolate(), descriptor, index, representation, extend_storage); + FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); + smi_handler = StoreHandler::TransitionToField( + isolate(), descriptor, index, representation, extend_storage); + } } // |holder| is either a receiver if the property is non-existent or // one of the prototypes. @@ -1877,7 +1705,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); if (validity_cell.is_null()) { DCHECK_EQ(0, checks_count); - validity_cell = handle(Smi::FromInt(0), isolate()); + validity_cell = handle(Smi::kZero, isolate()); } Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition); @@ -1896,21 +1724,14 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, return handler_array; } -static Handle<Code> PropertyCellStoreHandler( - Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder, - Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) { - auto constant_type = Nothing<PropertyCellConstantType>(); - if (type == PropertyCellType::kConstantType) { - constant_type = Just(cell->GetConstantType()); - } - StoreGlobalStub stub(isolate, type, constant_type, - receiver->IsJSGlobalProxy()); - auto code = stub.GetCodeCopyFromTemplate(holder, cell); - // TODO(verwaest): Move caching of these NORMAL stubs outside as well. - HeapObject::UpdateMapCodeCache(receiver, name, code); - return code; +namespace { + +Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) { + return isolate->factory()->NewWeakCell(cell); } +} // namespace + Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); @@ -1923,7 +1744,8 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { case LookupIterator::TRANSITION: { auto store_target = lookup->GetStoreTarget(); if (store_target->IsJSGlobalObject()) { - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH); + return StoreGlobal(isolate(), lookup->transition_cell()); } // Currently not handled by CompileStoreTransition. if (!holder->HasFastProperties()) { @@ -1931,6 +1753,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } + DCHECK(lookup->IsCacheableTransition()); Handle<Map> transition = lookup->transition_map(); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH); @@ -1971,10 +1794,6 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); } - if (info->is_sloppy() && !receiver->IsJSReceiver()) { - TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); - return slow_stub(); - } break; // Custom-compiled handler. } else if (accessors->IsAccessorPair()) { Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), @@ -2003,11 +1822,12 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { DCHECK_EQ(kData, lookup->property_details().kind()); if (lookup->is_dictionary_holder()) { if (holder->IsJSGlobalObject()) { - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH); + return StoreGlobal(isolate(), lookup->GetPropertyCell()); } - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal); + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH); DCHECK(holder.is_identical_to(receiver)); - return isolate()->builtins()->StoreIC_Normal(); + return StoreHandler::StoreNormal(isolate()); } // -------------- Fields -------------- @@ -2015,8 +1835,13 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH); int descriptor = lookup->GetFieldDescriptorIndex(); FieldIndex index = lookup->GetFieldIndex(); - return StoreHandler::StoreField(isolate(), descriptor, index, - lookup->constness(), + PropertyConstness constness = lookup->constness(); + if (constness == kConst && IsStoreOwnICKind(nexus()->kind())) { + // StoreOwnICs are used for initializing object literals therefore + // we must store the value unconditionally even to kConst fields. + constness = kMutable; + } + return StoreHandler::StoreField(isolate(), descriptor, index, constness, lookup->representation()); } @@ -2036,104 +1861,55 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { return Handle<Code>::null(); } -Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup, - Handle<Object> value, - CacheHolderFlag cache_holder) { - DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); +Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup) { + DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state()); // This is currently guaranteed by checks in StoreIC::Store. Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); Handle<JSObject> holder = lookup->GetHolder<JSObject>(); DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate()); - switch (lookup->state()) { - case LookupIterator::TRANSITION: { - auto store_target = lookup->GetStoreTarget(); - if (store_target->IsJSGlobalObject()) { - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition); - Handle<PropertyCell> cell = lookup->transition_cell(); - cell->set_value(*value); - Handle<Code> code = PropertyCellStoreHandler( - isolate(), store_target, Handle<JSGlobalObject>::cast(store_target), - lookup->name(), cell, PropertyCellType::kConstant); - cell->set_value(isolate()->heap()->the_hole_value()); - return code; - } - UNREACHABLE(); - } - - case LookupIterator::INTERCEPTOR: - UNREACHABLE(); - - case LookupIterator::ACCESSOR: { - DCHECK(holder->HasFastProperties()); - Handle<Object> accessors = lookup->GetAccessors(); - if (accessors->IsAccessorInfo()) { - Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); - DCHECK(v8::ToCData<Address>(info->setter()) != 0); - DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() || - lookup->HolderIsReceiverOrHiddenPrototype()); - DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, - receiver_map())); - DCHECK(!info->is_sloppy() || receiver->IsJSReceiver()); - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback); - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); - // TODO(ishell): don't hard-code language mode into the handler because - // this handler can be re-used through megamorphic stub cache for wrong - // language mode. - // Better pass vector/slot to Runtime::kStoreCallbackProperty and - // let it decode the language mode from the IC kind. - Handle<Code> code = compiler.CompileStoreCallback( - receiver, lookup->name(), info, language_mode()); - return code; - } else { - DCHECK(accessors->IsAccessorPair()); - Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), - isolate()); - DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo()); - CallOptimization call_optimization(setter); - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); - if (call_optimization.is_simple_api_call()) { - DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder)); - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback); - Handle<Code> code = compiler.CompileStoreCallback( - receiver, lookup->name(), call_optimization, - lookup->GetAccessorIndex(), slow_stub()); - return code; - } - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter); - int expected_arguments = JSFunction::cast(*setter) - ->shared() - ->internal_formal_parameter_count(); - return compiler.CompileStoreViaSetter(receiver, lookup->name(), - lookup->GetAccessorIndex(), - expected_arguments); - } - } - - case LookupIterator::DATA: { - 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; - } + DCHECK(holder->HasFastProperties()); + Handle<Object> accessors = lookup->GetAccessors(); - case LookupIterator::INTEGER_INDEXED_EXOTIC: - case LookupIterator::ACCESS_CHECK: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - UNREACHABLE(); - } - UNREACHABLE(); - return slow_stub(); + if (accessors->IsAccessorInfo()) { + Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); + DCHECK(v8::ToCData<Address>(info->setter()) != 0); + DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() || + lookup->HolderIsReceiverOrHiddenPrototype()); + DCHECK( + AccessorInfo::IsCompatibleReceiverMap(isolate(), info, receiver_map())); + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback); + NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); + // TODO(ishell): don't hard-code language mode into the handler because + // this handler can be re-used through megamorphic stub cache for wrong + // language mode. + // Better pass vector/slot to Runtime::kStoreCallbackProperty and + // let it decode the language mode from the IC kind. + Handle<Code> code = compiler.CompileStoreCallback(receiver, lookup->name(), + info, language_mode()); + return code; + } + + DCHECK(accessors->IsAccessorPair()); + Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), + isolate()); + DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo()); + CallOptimization call_optimization(setter); + NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); + if (call_optimization.is_simple_api_call()) { + DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder)); + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback); + Handle<Code> code = compiler.CompileStoreCallback( + receiver, lookup->name(), call_optimization, lookup->GetAccessorIndex(), + slow_stub()); + return code; + } + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter); + int expected_arguments = + JSFunction::cast(*setter)->shared()->internal_formal_parameter_count(); + return compiler.CompileStoreViaSetter( + receiver, lookup->name(), lookup->GetAccessorIndex(), expected_arguments); } void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, @@ -2246,11 +2022,9 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, } } - MapHandleList transitioned_maps(target_receiver_maps.length()); List<Handle<Object>> handlers(target_receiver_maps.length()); - StoreElementPolymorphicHandlers(&target_receiver_maps, &transitioned_maps, - &handlers, store_mode); - ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); + StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode); + ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers); } @@ -2289,6 +2063,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( store_mode == STORE_AND_GROW_NO_TRANSITION || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || store_mode == STORE_NO_TRANSITION_HANDLE_COW); + DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly()); ElementsKind elements_kind = receiver_map->elements_kind(); bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; @@ -2309,15 +2084,13 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( } Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); - if (validity_cell.is_null()) { - return stub; - } + if (validity_cell.is_null()) return stub; return isolate()->factory()->NewTuple2(validity_cell, stub); } void KeyedStoreIC::StoreElementPolymorphicHandlers( - MapHandleList* receiver_maps, MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) { + MapHandleList* receiver_maps, List<Handle<Object>>* handlers, + KeyedAccessStoreMode store_mode) { DCHECK(store_mode == STANDARD_STORE || store_mode == STORE_AND_GROW_NO_TRANSITION || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || @@ -2327,45 +2100,55 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( Handle<Map> receiver_map(receiver_maps->at(i)); Handle<Object> handler; Handle<Map> transitioned_map; - { - Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps); - if (tmap != nullptr) transitioned_map = handle(tmap); - } - - // TODO(mvstanton): The code below is doing pessimistic elements - // transitions. I would like to stop doing that and rely on Allocation Site - // Tracking to do a better job of ensuring the data types are what they need - // to be. Not all the elements are in place yet, pessimistic elements - // transitions are still important for performance. - if (!transitioned_map.is_null()) { - bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; - ElementsKind elements_kind = receiver_map->elements_kind(); - TRACE_HANDLER_STATS(isolate(), - KeyedStoreIC_ElementsTransitionAndStoreStub); - Handle<Code> stub = - ElementsTransitionAndStoreStub(isolate(), elements_kind, - transitioned_map->elements_kind(), - is_js_array, store_mode) - .GetCode(); - Handle<Object> validity_cell = - Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); - if (validity_cell.is_null()) { - handler = stub; - } else { - handler = isolate()->factory()->NewTuple2(validity_cell, stub); - } - } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { + if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE || + receiver_map->DictionaryElementsInPrototypeChainOnly()) { // TODO(mvstanton): Consider embedding store_mode in the state of the slow // keyed store ic for uniformity. TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub); handler = isolate()->builtins()->KeyedStoreIC_Slow(); + } else { - handler = StoreElementHandler(receiver_map, store_mode); + { + Map* tmap = + receiver_map->FindElementsKindTransitionedMap(receiver_maps); + if (tmap != nullptr) { + if (receiver_map->is_stable()) { + receiver_map->NotifyLeafMapLayoutChange(); + } + transitioned_map = handle(tmap); + } + } + + // TODO(mvstanton): The code below is doing pessimistic elements + // transitions. I would like to stop doing that and rely on Allocation + // Site Tracking to do a better job of ensuring the data types are what + // they need to be. Not all the elements are in place yet, pessimistic + // elements transitions are still important for performance. + if (!transitioned_map.is_null()) { + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; + ElementsKind elements_kind = receiver_map->elements_kind(); + TRACE_HANDLER_STATS(isolate(), + KeyedStoreIC_ElementsTransitionAndStoreStub); + Handle<Code> stub = + ElementsTransitionAndStoreStub(isolate(), elements_kind, + transitioned_map->elements_kind(), + is_js_array, store_mode) + .GetCode(); + Handle<Object> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (validity_cell.is_null()) { + validity_cell = handle(Smi::kZero, isolate()); + } + Handle<WeakCell> transition = Map::WeakCellForMap(transitioned_map); + handler = + isolate()->factory()->NewTuple3(transition, stub, validity_cell); + } else { + handler = StoreElementHandler(receiver_map, store_mode); + } } DCHECK(!handler.is_null()); handlers->Add(handler); - transitioned_maps->Add(transitioned_map); } } @@ -2561,7 +2344,8 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); } else if (IsLoadGlobalICKind(kind)) { - DCHECK_EQ(*isolate->global_object(), *receiver); + DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver); + receiver = isolate->global_object(); LoadGlobalICNexus nexus(vector, vector_slot); LoadGlobalIC ic(isolate, &nexus); ic.UpdateState(receiver, key); @@ -2672,6 +2456,11 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { StoreIC ic(isolate, &nexus); ic.UpdateState(receiver, key); RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); + } else if (IsStoreGlobalICKind(kind)) { + StoreICNexus nexus(vector, vector_slot); + StoreGlobalIC ic(isolate, &nexus); + ic.UpdateState(receiver, key); + RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); } else { DCHECK(IsKeyedStoreICKind(kind)); KeyedStoreICNexus nexus(vector, vector_slot); @@ -3061,56 +2850,15 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { /** - * Attempts to load a property with an interceptor (which must be present), - * but doesn't search the prototype chain. - * - * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't - * provide any value for the given name. - */ -RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) { - DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); - Handle<Name> name = - args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); - Handle<Object> receiver = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); - Handle<JSObject> holder = - args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); - HandleScope scope(isolate); - - if (!receiver->IsJSReceiver()) { - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, receiver, Object::ConvertReceiver(isolate, receiver)); - } - - InterceptorInfo* interceptor = holder->GetNamedInterceptor(); - PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, - *holder, Object::DONT_THROW); - - v8::GenericNamedPropertyGetterCallback getter = - v8::ToCData<v8::GenericNamedPropertyGetterCallback>( - interceptor->getter()); - Handle<Object> result = arguments.Call(getter, name); - - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); - - if (!result.is_null()) return *result; - return isolate->heap()->no_interceptor_result_sentinel(); -} - - -/** * Loads a property with an interceptor performing post interceptor * lookup if interceptor failed. */ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { HandleScope scope(isolate); - DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2); - Handle<Name> name = - args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); - Handle<Object> receiver = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); - Handle<JSObject> holder = - args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); + DCHECK_EQ(5, args.length()); + Handle<Name> name = args.at<Name>(0); + Handle<Object> receiver = args.at(1); + Handle<JSObject> holder = args.at<JSObject>(2); if (!receiver->IsJSReceiver()) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index c9818f5a5b..4649bc0b0e 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -26,6 +26,10 @@ class IC { // or with a single extra frame for supporting calls. enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 }; + // A polymorphic IC can handle at most 4 distinct maps before transitioning + // to megamorphic state. + static constexpr int kMaxPolymorphicMapCount = 4; + // Construct the IC structure with the given number of extra // JavaScript frames on the stack. IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL); @@ -51,26 +55,8 @@ class IC { return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC(); } bool IsAnyStore() const { - return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC(); - } - - static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map, - bool receiver_is_holder, - Isolate* isolate, - CacheHolderFlag* flag); - static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map, - Isolate* isolate, - CacheHolderFlag* flag); - - static bool ICUseVector(Code::Kind kind) { - return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC || - kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC || - kind == Code::KEYED_STORE_IC; - } - static bool ICUseVector(FeedbackSlotKind kind) { - return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) || - IsKeyedLoadICKind(kind) || IsStoreICKind(kind) || - IsStoreOwnICKind(kind) || IsKeyedStoreICKind(kind); + return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() || + IsKeyedStoreIC(); } // The ICs that don't pass slot and vector through the stack have to @@ -104,13 +90,6 @@ class IC { inline void set_target(Code* code); bool is_vector_set() { return vector_set_; } - bool UseVector() const { - bool use = ICUseVector(kind()); - // If we are supposed to use the nexus, verify the nexus is non-null. - DCHECK(!use || nexus_ != nullptr); - return use; - } - // Configure for most states. void ConfigureVectorState(IC::State new_state, Handle<Object> key); // Configure the vector for MONOMORPHIC. @@ -119,11 +98,6 @@ class IC { // Configure the vector for POLYMORPHIC. void ConfigureVectorState(Handle<Name> name, MapHandleList* maps, List<Handle<Object>>* handlers); - // Configure the vector for POLYMORPHIC with transitions (only for element - // keyed stores). - void ConfigureVectorState(MapHandleList* maps, - MapHandleList* transitioned_maps, - List<Handle<Object>>* handlers); char TransitionMarkFromState(IC::State state); void TraceIC(const char* type, Handle<Object> name); @@ -144,17 +118,14 @@ class IC { void TraceHandlerCacheHitStats(LookupIterator* lookup); // Compute the handler either by compiling or by retrieving a cached version. - Handle<Object> ComputeHandler(LookupIterator* lookup, - Handle<Object> value = Handle<Code>::null()); + Handle<Object> ComputeHandler(LookupIterator* lookup); virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) { UNREACHABLE(); return Handle<Code>::null(); } - virtual Handle<Object> CompileHandler(LookupIterator* lookup, - Handle<Object> value, - CacheHolderFlag cache_holder) { + virtual Handle<Code> CompileHandler(LookupIterator* lookup) { UNREACHABLE(); - return Handle<Object>::null(); + return Handle<Code>::null(); } void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name); @@ -170,6 +141,7 @@ class IC { bool IsLoadIC() const { return IsLoadICKind(kind_); } bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); } bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); } + bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); } bool IsStoreIC() const { return IsStoreICKind(kind_); } bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); } bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); } @@ -225,7 +197,6 @@ class IC { void FindTargetMaps() { if (target_maps_set_) return; target_maps_set_ = true; - DCHECK(UseVector()); nexus()->ExtractMaps(&target_maps_); } @@ -302,22 +273,24 @@ class LoadIC : public IC { Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override; - Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> unused, - CacheHolderFlag cache_holder) override; + Handle<Code> CompileHandler(LookupIterator* lookup) override; private: // Creates a data handler that represents a load of a field by given index. - static Handle<Object> SimpleFieldLoad(Isolate* isolate, FieldIndex index); + static Handle<Smi> 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. // Can be used only if GetPrototypeCheckCount() returns non negative value. Handle<Object> LoadFromPrototype(Handle<Map> receiver_map, Handle<JSObject> holder, Handle<Name> name, - Handle<Object> smi_handler); + Handle<Smi> smi_handler); // Creates a data handler that represents a load of a non-existent property. - Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name); + // {holder} is the object from which the property is loaded. If no holder is + // needed (e.g., for "nonexistent"), null_value() may be passed in. + Handle<Object> LoadFullChain(Handle<Map> receiver_map, Handle<Object> holder, + Handle<Name> name, Handle<Smi> smi_handler); friend class IC; friend class NamedLoadHandlerCompiler; @@ -352,6 +325,11 @@ class KeyedLoadIC : public LoadIC { private: friend class IC; + + Handle<Object> LoadElementHandler(Handle<Map> receiver_map); + + void LoadElementPolymorphicHandlers(MapHandleList* receiver_maps, + List<Handle<Object>>* handlers); }; @@ -377,7 +355,7 @@ class StoreIC : public IC { protected: // Stub accessors. Handle<Code> slow_stub() const { - // StoreIC and KeyedStoreIC share the same slow stub. + // All StoreICs share the same slow stub. return isolate()->builtins()->KeyedStoreIC_Slow(); } @@ -386,8 +364,7 @@ class StoreIC : public IC { void UpdateCaches(LookupIterator* lookup, Handle<Object> value, JSReceiver::StoreFromKeyed store_mode); Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override; - Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> value, - CacheHolderFlag cache_holder) override; + Handle<Code> CompileHandler(LookupIterator* lookup) override; private: Handle<Object> StoreTransition(Handle<Map> receiver_map, @@ -397,6 +374,15 @@ class StoreIC : public IC { friend class IC; }; +class StoreGlobalIC : public StoreIC { + public: + StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus) + : StoreIC(isolate, nexus) {} + + MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object, + Handle<Name> name, + Handle<Object> value); +}; enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap }; @@ -429,7 +415,6 @@ class KeyedStoreIC : public StoreIC { KeyedAccessStoreMode store_mode); void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps, - MapHandleList* transitioned_maps, List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode); diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc index 8962386c93..29d666d620 100644 --- a/deps/v8/src/ic/keyed-store-generic.cc +++ b/deps/v8/src/ic/keyed-store-generic.cc @@ -24,6 +24,8 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { void KeyedStoreGeneric(LanguageMode language_mode); + void StoreIC_Uninitialized(LanguageMode language_mode); + private: enum UpdateLength { kDontChangeLength, @@ -31,13 +33,16 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { kBumpLengthWithGap }; + enum UseStubCache { kUseStubCache, kDontUseStubCache }; + void EmitGenericElementStore(Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index, Node* value, Node* context, Label* slow); void EmitGenericPropertyStore(Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, - LanguageMode language_mode); + LanguageMode language_mode, + UseStubCache use_stub_cache = kUseStubCache); void BranchIfPrototypesHaveNonFastElements(Node* receiver_map, Label* non_fast_elements, @@ -67,7 +72,6 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout); - void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name, Label* accessor, Variable* var_accessor_pair, @@ -88,14 +92,20 @@ void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, assembler.KeyedStoreGeneric(language_mode); } +void StoreICUninitializedGenerator::Generate( + compiler::CodeAssemblerState* state, LanguageMode language_mode) { + KeyedStoreGenericAssembler assembler(state); + assembler.StoreIC_Uninitialized(language_mode); +} + void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { - Variable var_map(this, MachineRepresentation::kTagged); + VARIABLE(var_map, MachineRepresentation::kTagged); var_map.Bind(receiver_map); Label loop_body(this, &var_map); Goto(&loop_body); - Bind(&loop_body); + BIND(&loop_body); { Node* map = var_map.value(); Node* prototype = LoadMapPrototype(map); @@ -126,7 +136,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements( TrapAllocationMemento(receiver, bailout); } Label perform_transition(this), check_holey_map(this); - Variable var_target_map(this, MachineRepresentation::kTagged); + VARIABLE(var_target_map, MachineRepresentation::kTagged); // Check if the receiver has the default |from_kind| map. { Node* packed_map = @@ -138,7 +148,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements( } // Check if the receiver has the default |holey_from_kind| map. - Bind(&check_holey_map); + BIND(&check_holey_map); { Node* holey_map = LoadContextElement( native_context, Context::ArrayMapIndex(holey_from_kind)); @@ -149,7 +159,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements( } // Found a supported transition target map, perform the transition! - Bind(&perform_transition); + BIND(&perform_transition); { if (IsFastDoubleElementsKind(from_kind) != IsFastDoubleElementsKind(to_kind)) { @@ -189,7 +199,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMap( Node* native_context = LoadNativeContext(context); TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind, holey_kind, &already_holey, bailout, bailout); - Bind(&already_holey); + BIND(&already_holey); } void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti( @@ -209,11 +219,11 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti( TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind, holey_kind, &already_holey, &check_other_kind, bailout); - Bind(&check_other_kind); + BIND(&check_other_kind); TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind_2, holey_kind_2, &already_holey, bailout, bailout); - Bind(&already_holey); + BIND(&already_holey); } void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn( @@ -267,7 +277,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( } BranchIfPrototypesHaveNonFastElements(receiver_map, slow, &hole_check_passed); - Bind(&hole_check_passed); + BIND(&hole_check_passed); } // Check if the value we're storing matches the elements_kind. Smis @@ -284,7 +294,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( value); MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length); - Bind(&non_smi_value); + BIND(&non_smi_value); } // Check if we already have object elements; just do the store if so. @@ -302,7 +312,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( Store(elements, offset, value); MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length); - Bind(&must_transition); + BIND(&must_transition); } // Transition to the required ElementsKind. @@ -311,7 +321,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( Node* native_context = LoadNativeContext(context); Branch(WordEqual(LoadMap(value), LoadRoot(Heap::kHeapNumberMapRootIndex)), &transition_to_double, &transition_to_object); - Bind(&transition_to_double); + BIND(&transition_to_double); { // If we're adding holes at the end, always transition to a holey // elements kind, otherwise try to remain packed. @@ -332,7 +342,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( update_length); } - Bind(&transition_to_object); + BIND(&transition_to_object); { // If we're adding holes at the end, always transition to a holey // elements kind, otherwise try to remain packed. @@ -350,7 +360,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( } } - Bind(&check_double_elements); + BIND(&check_double_elements); Node* fixed_double_array_map = LoadRoot(Heap::kFixedDoubleArrayMapRootIndex); GotoIf(WordNotEqual(elements_map, fixed_double_array_map), &check_cow_elements); @@ -369,11 +379,11 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( LoadDoubleWithHoleCheck(elements, offset, &found_hole, MachineType::None()); Goto(&hole_check_passed); - Bind(&found_hole); + BIND(&found_hole); } BranchIfPrototypesHaveNonFastElements(receiver_map, slow, &hole_check_passed); - Bind(&hole_check_passed); + BIND(&hole_check_passed); } // Try to store the value as a double. @@ -392,7 +402,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( double_value); MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length); - Bind(&non_number_value); + BIND(&non_number_value); } // Transition to object elements. @@ -412,7 +422,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity( } } - Bind(&check_cow_elements); + BIND(&check_cow_elements); { // TODO(jkummerow): Use GrowElementsCapacity instead of bailing out. Goto(slow); @@ -428,7 +438,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( Node* elements = LoadElements(receiver); Node* elements_kind = LoadMapElementsKind(receiver_map); Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast); - Bind(&if_fast); + BIND(&if_fast); Label if_array(this); GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), &if_array); @@ -436,7 +446,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements)); Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds, &if_grow); } - Bind(&if_array); + BIND(&if_array); { Node* length = SmiUntag(LoadJSArrayLength(receiver)); GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds); @@ -446,21 +456,21 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( &if_bump_length_with_gap); } - Bind(&if_in_bounds); + BIND(&if_in_bounds); { StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind, intptr_index, value, context, slow, kDontChangeLength); } - Bind(&if_increment_length_by_one); + BIND(&if_increment_length_by_one); { StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind, intptr_index, value, context, slow, kIncrementLengthByOne); } - Bind(&if_bump_length_with_gap); + BIND(&if_bump_length_with_gap); { StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind, intptr_index, value, context, slow, @@ -471,7 +481,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( // an ElementsKind transition might be necessary. // The index can also be negative at this point! Jump to the runtime in that // case to convert it to a named property. - Bind(&if_grow); + BIND(&if_grow); { Comment("Grow backing store"); // TODO(jkummerow): Support inline backing store growth. @@ -479,7 +489,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( } // Any ElementsKind > LAST_FAST_ELEMENTS_KIND jumps here for further dispatch. - Bind(&if_nonfast); + BIND(&if_nonfast); { STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); GotoIf(Int32GreaterThanOrEqual( @@ -491,14 +501,14 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore( Goto(slow); } - Bind(&if_dictionary); + BIND(&if_dictionary); { Comment("Dictionary"); // TODO(jkummerow): Support storing to dictionary elements. Goto(slow); } - Bind(&if_typed_array); + BIND(&if_typed_array); { Comment("Typed array"); // TODO(jkummerow): Support typed arrays. @@ -506,31 +516,20 @@ 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); + VARIABLE(var_holder, MachineRepresentation::kTagged); var_holder.Bind(LoadMapPrototype(receiver_map)); - Variable var_holder_map(this, MachineRepresentation::kTagged); + VARIABLE(var_holder_map, 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); + BIND(&loop); { Node* holder = var_holder.value(); Node* holder_map = var_holder_map.value(); @@ -538,12 +537,12 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( 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()); + VARIABLE(var_meta_storage, MachineRepresentation::kTagged); + VARIABLE(var_entry, 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); + BIND(&found_fast); { Node* descriptors = var_meta_storage.value(); Node* name_index = var_entry.value(); @@ -553,14 +552,14 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( // Accessor case. // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. - Variable var_details(this, MachineRepresentation::kWord32); + VARIABLE(var_details, MachineRepresentation::kWord32); LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, &var_details, var_accessor_pair); var_accessor_holder->Bind(holder); Goto(accessor); } - Bind(&found_dict); + BIND(&found_dict); { Node* dictionary = var_meta_storage.value(); Node* entry = var_entry.value(); @@ -575,7 +574,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( Goto(accessor); } - Bind(&found_global); + BIND(&found_global); { Node* dictionary = var_meta_storage.value(); Node* entry = var_entry.value(); @@ -595,7 +594,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( } } - Bind(&next_proto); + BIND(&next_proto); // Bailout if it can be an integer indexed exotic case. GotoIf(Word32Equal(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), bailout); @@ -605,7 +604,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain( var_holder_map.Bind(LoadMap(proto)); Goto(&loop); } - Bind(&ok_to_write); + BIND(&ok_to_write); } void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, @@ -629,10 +628,10 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, Int32Constant(Representation::kTagged))); Goto(&all_fine); - Bind(&r_smi); + BIND(&r_smi); { Branch(TaggedIsSmi(value), &all_fine, bailout); } - Bind(&r_double); + BIND(&r_double); { GotoIf(TaggedIsSmi(value), &all_fine); Node* value_map = LoadMap(value); @@ -644,7 +643,7 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, Branch(IsHeapNumberMap(value_map), &all_fine, bailout); } - Bind(&r_heapobject); + BIND(&r_heapobject); { GotoIf(TaggedIsSmi(value), bailout); Node* field_type = @@ -663,7 +662,7 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); } - Bind(&all_fine); + BIND(&all_fine); } void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( @@ -696,7 +695,7 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, &backing_store); - Bind(&inobject); + BIND(&inobject); { Node* field_offset = IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), @@ -705,7 +704,7 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( Label tagged_rep(this), double_rep(this); Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), &double_rep, &tagged_rep); - Bind(&double_rep); + BIND(&double_rep); { Node* double_value = ChangeNumberToFloat64(value); if (FLAG_unbox_double_fields) { @@ -718,20 +717,20 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( Goto(&done); } - Bind(&tagged_rep); + BIND(&tagged_rep); { StoreObjectField(object, field_offset, value); Goto(&done); } } - Bind(&backing_store); + BIND(&backing_store); { Node* backing_store_index = IntPtrSub(field_index, inobject_properties); Label tagged_rep(this), double_rep(this); Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), &double_rep, &tagged_rep); - Bind(&double_rep); + BIND(&double_rep); { Node* double_value = ChangeNumberToFloat64(value); Node* mutable_heap_number = @@ -739,20 +738,20 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( StoreHeapNumberValue(mutable_heap_number, double_value); Goto(&done); } - Bind(&tagged_rep); + BIND(&tagged_rep); { StoreFixedArrayElement(properties, backing_store_index, value); Goto(&done); } } - Bind(&done); + BIND(&done); } void KeyedStoreGenericAssembler::EmitGenericPropertyStore( 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); + LanguageMode language_mode, UseStubCache use_stub_cache) { + VARIABLE(var_accessor_pair, MachineRepresentation::kTagged); + VARIABLE(var_accessor_holder, MachineRepresentation::kTagged); Label stub_cache(this), fast_properties(this), dictionary_properties(this), accessor(this), readonly(this); Node* properties = LoadProperties(receiver); @@ -760,19 +759,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), &dictionary_properties, &fast_properties); - Bind(&fast_properties); + BIND(&fast_properties); { Comment("fast property store"); Node* bitfield3 = LoadMapBitField3(receiver_map); Node* descriptors = LoadMapDescriptors(receiver_map); Label descriptor_found(this); - Variable var_name_index(this, MachineType::PointerRepresentation()); + VARIABLE(var_name_index, MachineType::PointerRepresentation()); // TODO(jkummerow): Maybe look for existing map transitions? - Label* notfound = &stub_cache; + Label* notfound = use_stub_cache == kUseStubCache ? &stub_cache : slow; DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, &var_name_index, notfound); - Bind(&descriptor_found); + BIND(&descriptor_found); { Node* name_index = var_name_index.value(); Node* details = @@ -782,13 +781,13 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( // Accessor case. // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. - Variable var_details(this, MachineRepresentation::kWord32); + VARIABLE(var_details, MachineRepresentation::kWord32); LoadPropertyFromFastObject(receiver, receiver_map, descriptors, name_index, &var_details, &var_accessor_pair); var_accessor_holder.Bind(receiver); Goto(&accessor); - Bind(&data_property); + BIND(&data_property); { OverwriteExistingFastProperty(receiver, receiver_map, properties, descriptors, name_index, details, @@ -798,17 +797,17 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( } } - Bind(&dictionary_properties); + BIND(&dictionary_properties); { 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()); + VARIABLE(var_name_index, 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); + BIND(&dictionary_found); { Label overwrite(this); Node* details = LoadDetailsByKeyIndex<NameDictionary>( @@ -821,7 +820,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( var_accessor_holder.Bind(receiver); Goto(&accessor); - Bind(&overwrite); + BIND(&overwrite); { StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(), p->value); @@ -829,8 +828,15 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( } } - Bind(¬_found); + BIND(¬_found); { + Label extensible(this); + GotoIf(IsPrivateSymbol(p->name), &extensible); + Node* bitfield2 = LoadMapBitField2(receiver_map); + Branch(IsSetWord32(bitfield2, 1 << Map::kIsExtensible), &extensible, + slow); + + BIND(&extensible); LookupPropertyOnPrototypeChain(receiver_map, p->name, &accessor, &var_accessor_pair, &var_accessor_holder, &readonly, slow); @@ -839,7 +845,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( } } - Bind(&accessor); + BIND(&accessor); { Label not_callable(this); Node* accessor_pair = var_accessor_pair.value(); @@ -855,7 +861,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( CallJS(callable, p->context, setter, receiver, p->value); Return(p->value); - Bind(¬_callable); + BIND(¬_callable); { if (language_mode == STRICT) { Node* message = @@ -869,12 +875,12 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( } } - Bind(&readonly); + BIND(&readonly); { if (language_mode == STRICT) { Node* message = SmiConstant(Smi::FromInt(MessageTemplate::kStrictReadOnlyProperty)); - Node* type = Typeof(p->receiver, p->context); + Node* type = Typeof(p->receiver); TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name, type, p->receiver); } else { @@ -883,19 +889,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( } } - Bind(&stub_cache); - { + if (use_stub_cache == kUseStubCache) { + BIND(&stub_cache); Comment("stub cache probe"); - Variable var_handler(this, MachineRepresentation::kTagged); + VARIABLE(var_handler, 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); + BIND(&found_handler); { Comment("KeyedStoreGeneric found handler"); HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss); } - Bind(&stub_cache_miss); + BIND(&stub_cache_miss); { Comment("KeyedStoreGeneric_miss"); TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, @@ -914,8 +920,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { Node* vector = Parameter(Descriptor::kVector); Node* context = Parameter(Descriptor::kContext); - Variable var_index(this, MachineType::PointerRepresentation()); - Variable var_unique(this, MachineRepresentation::kTagged); + VARIABLE(var_index, MachineType::PointerRepresentation()); + VARIABLE(var_unique, MachineRepresentation::kTagged); var_unique.Bind(name); // Dummy initialization. Label if_index(this), if_unique_name(this), slow(this); @@ -930,14 +936,14 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, &slow); - Bind(&if_index); + BIND(&if_index); { Comment("integer index"); EmitGenericElementStore(receiver, receiver_map, instance_type, var_index.value(), value, context, &slow); } - Bind(&if_unique_name); + BIND(&if_unique_name); { Comment("key is unique name"); StoreICParameters p(context, receiver, var_unique.value(), value, slot, @@ -945,7 +951,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode); } - Bind(&slow); + BIND(&slow); { Comment("KeyedStoreGeneric_slow"); TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, @@ -953,5 +959,47 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { } } +void KeyedStoreGenericAssembler::StoreIC_Uninitialized( + 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); + + Label miss(this); + + GotoIf(TaggedIsSmi(receiver), &miss); + 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_SPECIAL_RECEIVER_TYPE)), + &miss); + + // Optimistically write the state transition to the vector. + StoreFixedArrayElement(vector, slot, + LoadRoot(Heap::kpremonomorphic_symbolRootIndex), + SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); + + StoreICParameters p(context, receiver, name, value, slot, vector); + EmitGenericPropertyStore(receiver, receiver_map, &p, &miss, language_mode, + kDontUseStubCache); + + BIND(&miss); + { + // Undo the optimistic state transition. + StoreFixedArrayElement(vector, slot, + LoadRoot(Heap::kuninitialized_symbolRootIndex), + SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS); + TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector, + receiver, name); + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h index 8028736aa1..70f87f83ad 100644 --- a/deps/v8/src/ic/keyed-store-generic.h +++ b/deps/v8/src/ic/keyed-store-generic.h @@ -20,6 +20,12 @@ class KeyedStoreGenericGenerator { LanguageMode language_mode); }; +class StoreICUninitializedGenerator { + public: + static void Generate(compiler::CodeAssemblerState* state, + LanguageMode language_mode); +}; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc index c14652cf47..6e581a5bf2 100644 --- a/deps/v8/src/ic/mips/handler-compiler-mips.cc +++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc @@ -17,43 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- a0 : receiver - // -- a2 : name - // -- ra : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(cp); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ lw(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_GETTER); - __ li(a0, Operand(0)); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(cp); } @@ -190,22 +160,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -276,12 +230,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ lw(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -330,8 +278,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -396,15 +343,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -413,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ Branch(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -428,91 +372,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ Branch(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method). - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ Branch(&interceptor_failed, eq, v0, Operand(scratch1())); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver(), holder_reg, this->name()); - } else { - __ Pop(holder_reg, this->name()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -549,42 +414,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - __ Branch(&miss, eq, result, Operand(at)); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, a1, a3); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(USE_DELAY_SLOT); - __ Move(v0, result); // Ensure the stub returns correct value. - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc index 1a38d329e7..99ca45a136 100644 --- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc +++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc @@ -17,43 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- a0 : receiver - // -- a2 : name - // -- ra : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(cp); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ld(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_GETTER); - __ li(a0, Operand(V8_INT64_C(0))); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(cp); } @@ -190,22 +160,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -276,12 +230,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ ld(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -330,8 +278,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -396,15 +343,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -413,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ Branch(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -428,91 +372,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ Branch(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method). - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ Branch(&interceptor_failed, eq, v0, Operand(scratch1())); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver(), holder_reg, this->name()); - } else { - __ Pop(holder_reg, this->name()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -549,42 +414,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ ld(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - __ Branch(&miss, eq, result, Operand(at)); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, a1, a3); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(USE_DELAY_SLOT); - __ Move(v0, result); // Ensure the stub returns correct value. - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc index 3da558d10e..5736c12ffc 100644 --- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc +++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc @@ -17,43 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- r3 : receiver - // -- r5 : name - // -- lr : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(cp); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ LoadP(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER); - __ li(r3, Operand::Zero()); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(cp); } @@ -195,22 +165,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -282,13 +236,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } - // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -341,8 +288,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -412,15 +358,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -429,10 +374,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -444,92 +387,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ cmp(r3, scratch1()); - __ beq(&interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -567,41 +430,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(result, ip); - __ beq(&miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc index 9f087977a1..bfca871bab 100644 --- a/deps/v8/src/ic/s390/handler-compiler-s390.cc +++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc @@ -17,42 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- r2 : receiver - // -- r4 : name - // -- lr : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(cp); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ LoadP(scratch, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ Push(receiver); - __ LoadAccessor(r3, holder, accessor_index, ACCESSOR_GETTER); - __ LoadImmP(r2, Operand::Zero()); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(cp); } @@ -186,21 +157,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ bne(miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -272,13 +228,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } - // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); @@ -330,8 +279,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -396,15 +344,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { @@ -412,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -426,90 +371,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ b(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ CompareRoot(r2, Heap::kNoInterceptorResultSentinelRootIndex); - __ beq(&interceptor_failed, Label::kNear); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ Pop(this->name()); - __ Pop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -545,39 +412,6 @@ Register NamedStoreHandlerCompiler::value() { return StoreDescriptor::ValueRegister(); } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - __ beq(&miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r3, r5); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc index 5fc8cc318d..d62aceec96 100644 --- a/deps/v8/src/ic/stub-cache.cc +++ b/deps/v8/src/ic/stub-cache.cc @@ -42,9 +42,9 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map, DCHECK(IC::IsHandler(handler)); if (handler->IsCode()) { Code* code = Code::cast(handler); - Code::Flags expected_flags = Code::RemoveHolderFromFlags( - Code::ComputeHandlerFlags(stub_cache->ic_kind())); - Code::Flags flags = Code::RemoveHolderFromFlags(code->flags()); + Code::Flags expected_flags = + Code::ComputeHandlerFlags(stub_cache->ic_kind()); + Code::Flags flags = code->flags(); DCHECK_EQ(expected_flags, flags); DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(code->flags())); } diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc index 425ed4762e..cd831c8b5f 100644 --- a/deps/v8/src/ic/x64/handler-compiler-x64.cc +++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc @@ -83,24 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name); - __ Push(receiver); - __ Push(holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -176,13 +158,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the fast handler if present. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } - // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); __ Move(api_function_address, function_address, @@ -257,43 +232,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( __ ret(0); } - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { - // ----------- S t a t e ------------- - // -- rax : receiver - // -- rcx : name - // -- rsp[0] : return address - // ----------------------------------- +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ pushq(rsi); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ movp(scratch, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ Push(receiver); - __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER); - __ Set(rax, 0); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // Remember the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ popq(rsi); } @@ -337,8 +281,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -406,15 +349,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -423,10 +365,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ jmp(&success); __ bind(miss); - if (IC::ICUseVector(kind())) { - DCHECK(kind() == Code::LOAD_IC); - PopVectorAndSlot(); - } + DCHECK(kind() == Code::LOAD_IC); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } @@ -438,102 +378,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { Label success; __ jmp(&success); GenerateRestoreName(miss, name); - if (IC::ICUseVector(kind())) PopVectorAndSlot(); + PopVectorAndSlot(); TailCallBuiltin(masm(), MissBuiltin(kind())); __ bind(&success); } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ Push(receiver()); - } - __ Push(holder_reg); - __ Push(this->name()); - InterceptorVectorSlotPush(holder_reg); - - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); - __ j(equal, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ Pop(this->name()); - __ Pop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(receiver()); - __ Push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot()); - __ Push(vector()); - } else { - __ Push(scratch3()); // slot - __ Push(scratch2()); // vector - } - __ Push(Operand(rsp, 4 * kPointerSize)); // return address - __ movp(Operand(rsp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } @@ -572,43 +422,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ICUseVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - __ j(equal, &miss); - } else if (FLAG_debug_code) { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1); - if (IC::ICUseVector(kind())) { - DiscardVectorAndSlot(); - } - __ ret(0); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc index 5a61eee163..dc572a19cc 100644 --- a/deps/v8/src/ic/x87/handler-compiler-x87.cc +++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc @@ -17,38 +17,13 @@ namespace internal { #define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder, - int accessor_index, int expected_arguments, Register scratch) { +void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( + MacroAssembler* masm) { { FrameScope scope(masm, StackFrame::INTERNAL); - - // Save context register - __ push(esi); - - if (accessor_index >= 0) { - DCHECK(!holder.is(scratch)); - DCHECK(!receiver.is(scratch)); - // Call the JavaScript getter with the receiver on the stack. - if (map->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(scratch, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - receiver = scratch; - } - __ push(receiver); - __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER); - __ Set(eax, 0); - __ Call(masm->isolate()->builtins()->CallFunction( - ConvertReceiverMode::kNotNullOrUndefined), - RelocInfo::CODE_TARGET); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); // Restore context register. __ pop(esi); } @@ -201,12 +176,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall( __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset)); } - if (api_call_info->fast_handler()->IsCode()) { - // Just tail call into the code. - __ Jump(handle(Code::cast(api_call_info->fast_handler())), - RelocInfo::CODE_TARGET); - return; - } // Put api_function_address in place. Address function_address = v8::ToCData<Address>(api_call_info->callback()); __ mov(api_function_address, Immediate(function_address)); @@ -293,23 +262,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - #undef __ #define __ ACCESS_MASM(masm()) @@ -347,8 +299,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck( Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - ReturnHolder return_what) { + Register scratch2, Handle<Name> name, Label* miss) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -413,15 +364,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - bool return_holder = return_what == RETURN_HOLDER; - if (return_holder && depth != 0) { + if (depth != 0) { Handle<WeakCell> weak_cell = Map::GetOrCreatePrototypeWeakCell(current, isolate()); __ LoadWeakValue(reg, weak_cell, miss); } // Return the register containing the holder. - return return_holder ? reg : no_reg; + return reg; } @@ -451,102 +401,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Compile the interceptor call, followed by inline code to load the - // property from further up the prototype chain if the call fails. - // Check that the maps haven't changed. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder<JSObject>()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ push(receiver()); - } - __ push(holder_reg); - __ push(this->name()); - InterceptorVectorSlotPush(holder_reg); - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor( - masm(), receiver(), holder_reg, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ cmp(eax, factory()->no_interceptor_result_sentinel()); - __ j(equal, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - // Clobber registers when generating debug-code to provoke errors. - __ bind(&interceptor_failed); - if (FLAG_debug_code) { - __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue))); - __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue))); - __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue))); - } - - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - // Call the runtime system to load the interceptor. - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(receiver()); - __ push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ push(slot()); - __ push(vector()); - } else { - __ push(scratch3()); // slot - __ push(scratch2()); // vector - } - __ push(Operand(esp, 4 * kPointerSize)); // return address - __ mov(Operand(esp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { // Zap register aliases of the arguments passed on the stack to ensure they // are properly loaded by the handler (debug-only). @@ -595,43 +449,6 @@ Register NamedStoreHandlerCompiler::value() { } -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - if (IC::ShouldPushPopSlotAndVector(kind())) { - PushVectorAndSlot(); - } - FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); - // Get the value from the cell. - Register result = StoreDescriptor::ValueRegister(); - Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); - __ LoadWeakValue(result, weak_cell, &miss); - __ mov(result, FieldOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ cmp(result, factory()->the_hole_value()); - __ j(equal, &miss); - } else if (FLAG_debug_code) { - __ cmp(result, factory()->the_hole_value()); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->ic_named_load_global_stub(), 1); - // The code above already loads the result into the return register. - if (IC::ShouldPushPopSlotAndVector(kind())) { - DiscardVectorAndSlot(); - } - __ ret(0); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), name); -} - - #undef __ } // namespace internal } // namespace v8 |