diff options
Diffstat (limited to 'deps/v8/src/codegen/code-stub-assembler.cc')
-rw-r--r-- | deps/v8/src/codegen/code-stub-assembler.cc | 2529 |
1 files changed, 1046 insertions, 1483 deletions
diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index 7dad8cb95e..3051ce3662 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -7,9 +7,11 @@ #include "include/v8-internal.h" #include "src/base/macros.h" #include "src/codegen/code-factory.h" +#include "src/codegen/tnode.h" #include "src/common/globals.h" #include "src/execution/frames-inl.h" #include "src/execution/frames.h" +#include "src/execution/protectors.h" #include "src/heap/heap-inl.h" // For Page/MemoryChunk. TODO(jkummerow): Drop. #include "src/logging/counters.h" #include "src/objects/api-callbacks.h" @@ -17,6 +19,7 @@ #include "src/objects/descriptor-array.h" #include "src/objects/function-kind.h" #include "src/objects/heap-number.h" +#include "src/objects/js-generator.h" #include "src/objects/oddball.h" #include "src/objects/ordered-hash-table-inl.h" #include "src/objects/property-cell.h" @@ -26,10 +29,6 @@ namespace v8 { namespace internal { using compiler::Node; -template <class T> -using TNode = compiler::TNode<T>; -template <class T> -using SloppyTNode = compiler::SloppyTNode<T>; CodeStubAssembler::CodeStubAssembler(compiler::CodeAssemblerState* state) : compiler::CodeAssembler(state), @@ -135,6 +134,148 @@ void CodeStubAssembler::Check(SloppyTNode<Word32T> condition_node, Check(branch, message, file, line, extra_nodes); } +template <> +TNode<Smi> CodeStubAssembler::IntPtrToParameter<Smi>(TNode<IntPtrT> value) { + return SmiTag(value); +} +template <> +TNode<IntPtrT> CodeStubAssembler::IntPtrToParameter<IntPtrT>( + TNode<IntPtrT> value) { + return value; +} + +void CodeStubAssembler::CollectCallableFeedback( + TNode<Object> maybe_target, TNode<Context> context, + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot_id) { + Label extra_checks(this, Label::kDeferred), done(this); + + // Check if we have monomorphic {target} feedback already. + TNode<MaybeObject> feedback = + LoadFeedbackVectorSlot(feedback_vector, slot_id); + Comment("check if monomorphic"); + TNode<BoolT> is_monomorphic = IsWeakReferenceToObject(feedback, maybe_target); + GotoIf(is_monomorphic, &done); + + // Check if it is a megamorphic {target}. + Comment("check if megamorphic"); + TNode<BoolT> is_megamorphic = TaggedEqual( + feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate()))); + Branch(is_megamorphic, &done, &extra_checks); + + BIND(&extra_checks); + { + Label initialize(this), mark_megamorphic(this); + + Comment("check if weak reference"); + TNode<BoolT> is_uninitialized = TaggedEqual( + feedback, + HeapConstant(FeedbackVector::UninitializedSentinel(isolate()))); + GotoIf(is_uninitialized, &initialize); + CSA_ASSERT(this, IsWeakOrCleared(feedback)); + + // If the weak reference is cleared, we have a new chance to become + // monomorphic. + Comment("check if weak reference is cleared"); + Branch(IsCleared(feedback), &initialize, &mark_megamorphic); + + BIND(&initialize); + { + Comment("check if function in same native context"); + GotoIf(TaggedIsSmi(maybe_target), &mark_megamorphic); + TNode<HeapObject> target = CAST(maybe_target); + // Check if the {target} is a JSFunction or JSBoundFunction + // in the current native context. + TVARIABLE(HeapObject, var_current, target); + Label loop(this, &var_current), done_loop(this); + Goto(&loop); + BIND(&loop); + { + Label if_boundfunction(this), if_function(this); + TNode<HeapObject> current = var_current.value(); + TNode<Uint16T> current_instance_type = LoadInstanceType(current); + GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE), + &if_boundfunction); + Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE), + &if_function, &mark_megamorphic); + + BIND(&if_function); + { + // Check that the JSFunction {current} is in the current native + // context. + TNode<Context> current_context = + CAST(LoadObjectField(current, JSFunction::kContextOffset)); + TNode<NativeContext> current_native_context = + LoadNativeContext(current_context); + Branch( + TaggedEqual(LoadNativeContext(context), current_native_context), + &done_loop, &mark_megamorphic); + } + BIND(&if_boundfunction); + { + // Continue with the [[BoundTargetFunction]] of {target}. + var_current = LoadObjectField<HeapObject>( + current, JSBoundFunction::kBoundTargetFunctionOffset); + Goto(&loop); + } + } + BIND(&done_loop); + StoreWeakReferenceInFeedbackVector(feedback_vector, slot_id, target); + ReportFeedbackUpdate(feedback_vector, slot_id, "Call:Initialize"); + Goto(&done); + } + + BIND(&mark_megamorphic); + { + // MegamorphicSentinel is an immortal immovable object so + // write-barrier is not needed. + Comment("transition to megamorphic"); + DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kmegamorphic_symbol)); + StoreFeedbackVectorSlot( + feedback_vector, slot_id, + HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())), + SKIP_WRITE_BARRIER); + ReportFeedbackUpdate(feedback_vector, slot_id, + "Call:TransitionMegamorphic"); + Goto(&done); + } + } + + BIND(&done); +} + +void CodeStubAssembler::CollectCallFeedback( + TNode<Object> maybe_target, TNode<Context> context, + TNode<HeapObject> maybe_feedback_vector, TNode<UintPtrT> slot_id) { + Label feedback_done(this); + // If feedback_vector is not valid, then nothing to do. + GotoIf(IsUndefined(maybe_feedback_vector), &feedback_done); + + // Increment the call count. + TNode<FeedbackVector> feedback_vector = CAST(maybe_feedback_vector); + IncrementCallCount(feedback_vector, slot_id); + + // Collect the callable {target} feedback. + CollectCallableFeedback(maybe_target, context, feedback_vector, slot_id); + Goto(&feedback_done); + + BIND(&feedback_done); +} + +void CodeStubAssembler::IncrementCallCount( + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot_id) { + Comment("increment call count"); + TNode<Smi> call_count = + CAST(LoadFeedbackVectorSlot(feedback_vector, slot_id, kTaggedSize)); + // The lowest {FeedbackNexus::CallCountField::kShift} bits of the call + // count are used as flags. To increment the call count by 1 we hence + // have to increment by 1 << {FeedbackNexus::CallCountField::kShift}. + TNode<Smi> new_count = SmiAdd( + call_count, SmiConstant(1 << FeedbackNexus::CallCountField::kShift)); + // Count is Smi, so we don't need a write barrier. + StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count, + SKIP_WRITE_BARRIER, kTaggedSize); +} + void CodeStubAssembler::FastCheck(TNode<BoolT> condition) { Label ok(this), not_ok(this, Label::kDeferred); Branch(condition, &ok, ¬_ok); @@ -221,7 +362,7 @@ TNode<Object> CodeStubAssembler::NoContextConstant() { } #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ - compiler::TNode<std::remove_pointer<std::remove_reference<decltype( \ + TNode<std::remove_pointer<std::remove_reference<decltype( \ std::declval<Heap>().rootAccessorName())>::type>::type> \ CodeStubAssembler::name##Constant() { \ return UncheckedCast<std::remove_pointer<std::remove_reference<decltype( \ @@ -232,7 +373,7 @@ HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR) #undef HEAP_CONSTANT_ACCESSOR #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ - compiler::TNode<std::remove_pointer<std::remove_reference<decltype( \ + TNode<std::remove_pointer<std::remove_reference<decltype( \ std::declval<ReadOnlyRoots>().rootAccessorName())>::type>::type> \ CodeStubAssembler::name##Constant() { \ return UncheckedCast<std::remove_pointer<std::remove_reference<decltype( \ @@ -242,14 +383,12 @@ HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR) HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR) #undef HEAP_CONSTANT_ACCESSOR -#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \ - compiler::TNode<BoolT> CodeStubAssembler::Is##name( \ - SloppyTNode<Object> value) { \ - return TaggedEqual(value, name##Constant()); \ - } \ - compiler::TNode<BoolT> CodeStubAssembler::IsNot##name( \ - SloppyTNode<Object> value) { \ - return TaggedNotEqual(value, name##Constant()); \ +#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \ + TNode<BoolT> CodeStubAssembler::Is##name(SloppyTNode<Object> value) { \ + return TaggedEqual(value, name##Constant()); \ + } \ + TNode<BoolT> CodeStubAssembler::IsNot##name(SloppyTNode<Object> value) { \ + return TaggedNotEqual(value, name##Constant()); \ } HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST) #undef HEAP_CONSTANT_TEST @@ -264,6 +403,21 @@ TNode<BInt> CodeStubAssembler::BIntConstant(int value) { #endif } +template <> +TNode<Smi> CodeStubAssembler::IntPtrOrSmiConstant<Smi>(int value) { + return SmiConstant(value); +} + +template <> +TNode<IntPtrT> CodeStubAssembler::IntPtrOrSmiConstant<IntPtrT>(int value) { + return IntPtrConstant(value); +} + +template <> +TNode<RawPtrT> CodeStubAssembler::IntPtrOrSmiConstant<RawPtrT>(int value) { + return ReinterpretCast<RawPtrT>(IntPtrConstant(value)); +} + Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) { if (mode == SMI_PARAMETERS) { return SmiConstant(value); @@ -273,41 +427,29 @@ Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) { } } -TNode<BoolT> CodeStubAssembler::IntPtrOrSmiEqual(Node* left, Node* right, - ParameterMode mode) { - if (mode == SMI_PARAMETERS) { - return SmiEqual(CAST(left), CAST(right)); - } else { - DCHECK_EQ(INTPTR_PARAMETERS, mode); - return IntPtrEqual(UncheckedCast<IntPtrT>(left), - UncheckedCast<IntPtrT>(right)); +bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(TNode<Smi> test) { + Smi smi_test; + if (ToSmiConstant(test, &smi_test) && smi_test.value() == 0) { + return true; } + return false; } -TNode<BoolT> CodeStubAssembler::IntPtrOrSmiNotEqual(Node* left, Node* right, - ParameterMode mode) { - if (mode == SMI_PARAMETERS) { - return SmiNotEqual(CAST(left), CAST(right)); - } else { - DCHECK_EQ(INTPTR_PARAMETERS, mode); - return WordNotEqual(UncheckedCast<IntPtrT>(left), - UncheckedCast<IntPtrT>(right)); +bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(TNode<IntPtrT> test) { + int32_t constant_test; + if (ToInt32Constant(test, &constant_test) && constant_test == 0) { + return true; } + return false; } bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(Node* test, ParameterMode mode) { - int32_t constant_test; - Smi smi_test; if (mode == INTPTR_PARAMETERS) { - if (ToInt32Constant(test, &constant_test) && constant_test == 0) { - return true; - } + return IsIntPtrOrSmiConstantZero(UncheckedCast<IntPtrT>(test)); } else { DCHECK_EQ(mode, SMI_PARAMETERS); - if (ToSmiConstant(test, &smi_test) && smi_test.value() == 0) { - return true; - } + return IsIntPtrOrSmiConstantZero(UncheckedCast<Smi>(test)); } return false; } @@ -352,6 +494,10 @@ Node* CodeStubAssembler::MatchesParameterMode(Node* value, ParameterMode mode) { } TNode<BoolT> CodeStubAssembler::WordIsPowerOfTwo(SloppyTNode<IntPtrT> value) { + intptr_t constant; + if (ToIntPtrConstant(value, &constant)) { + return BoolConstant(base::bits::IsPowerOfTwo(constant)); + } // value && !(value & (value - 1)) return IntPtrEqual( Select<IntPtrT>( @@ -578,21 +724,44 @@ TNode<Float64T> CodeStubAssembler::Float64Trunc(SloppyTNode<Float64T> x) { TNode<BoolT> CodeStubAssembler::IsValidSmi(TNode<Smi> smi) { if (SmiValuesAre32Bits() && kSystemPointerSize == kInt64Size) { // Check that the Smi value is zero in the lower bits. - TNode<IntPtrT> value = BitcastTaggedSignedToWord(smi); + TNode<IntPtrT> value = BitcastTaggedToWordForTagAndSmiBits(smi); return Word32Equal(Int32Constant(0), TruncateIntPtrToInt32(value)); } return Int32TrueConstant(); } -Node* CodeStubAssembler::SmiShiftBitsConstant() { - return IntPtrConstant(kSmiShiftSize + kSmiTagSize); +TNode<BoolT> CodeStubAssembler::IsValidSmiIndex(TNode<Smi> smi) { + if (COMPRESS_POINTERS_BOOL) { + return WordEqual( + BitcastTaggedToWordForTagAndSmiBits(smi), + BitcastTaggedToWordForTagAndSmiBits(NormalizeSmiIndex(smi))); + } + return Int32TrueConstant(); +} + +TNode<Smi> CodeStubAssembler::NormalizeSmiIndex(TNode<Smi> smi_index) { + if (COMPRESS_POINTERS_BOOL) { + TNode<Int32T> raw = + TruncateWordToInt32(BitcastTaggedToWordForTagAndSmiBits(smi_index)); + smi_index = BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(raw)); + } + return smi_index; } TNode<Smi> CodeStubAssembler::SmiFromInt32(SloppyTNode<Int32T> value) { - TNode<IntPtrT> value_intptr = ChangeInt32ToIntPtr(value); - TNode<Smi> smi = - BitcastWordToTaggedSigned(WordShl(value_intptr, SmiShiftBitsConstant())); - return smi; + if (COMPRESS_POINTERS_BOOL) { + static_assert(!COMPRESS_POINTERS_BOOL || (kSmiShiftSize + kSmiTagSize == 1), + "Use shifting instead of add"); + return BitcastWordToTaggedSigned( + ChangeUint32ToWord(Int32Add(value, value))); + } + return SmiTag(ChangeInt32ToIntPtr(value)); +} + +TNode<Smi> CodeStubAssembler::SmiFromUint32(TNode<Uint32T> value) { + CSA_ASSERT(this, IntPtrLessThan(ChangeUint32ToWord(value), + IntPtrConstant(Smi::kMaxValue))); + return SmiFromInt32(Signed(value)); } TNode<BoolT> CodeStubAssembler::IsValidPositiveSmi(TNode<IntPtrT> value) { @@ -612,6 +781,9 @@ TNode<Smi> CodeStubAssembler::SmiTag(SloppyTNode<IntPtrT> value) { if (ToInt32Constant(value, &constant_value) && Smi::IsValid(constant_value)) { return SmiConstant(constant_value); } + if (COMPRESS_POINTERS_BOOL) { + return SmiFromInt32(TruncateIntPtrToInt32(value)); + } TNode<Smi> smi = BitcastWordToTaggedSigned(WordShl(value, SmiShiftBitsConstant())); return smi; @@ -622,11 +794,19 @@ TNode<IntPtrT> CodeStubAssembler::SmiUntag(SloppyTNode<Smi> value) { if (ToIntPtrConstant(value, &constant_value)) { return IntPtrConstant(constant_value >> (kSmiShiftSize + kSmiTagSize)); } - return Signed( - WordSar(BitcastTaggedSignedToWord(value), SmiShiftBitsConstant())); + if (COMPRESS_POINTERS_BOOL) { + return ChangeInt32ToIntPtr(SmiToInt32(value)); + } + return Signed(WordSar(BitcastTaggedToWordForTagAndSmiBits(value), + SmiShiftBitsConstant())); } TNode<Int32T> CodeStubAssembler::SmiToInt32(SloppyTNode<Smi> value) { + if (COMPRESS_POINTERS_BOOL) { + return Signed(Word32Sar( + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(value)), + SmiShiftBitsConstant32())); + } TNode<IntPtrT> result = SmiUntag(value); return TruncateIntPtrToInt32(result); } @@ -673,13 +853,13 @@ TNode<Smi> CodeStubAssembler::TrySmiAdd(TNode<Smi> lhs, TNode<Smi> rhs, Label* if_overflow) { if (SmiValuesAre32Bits()) { return BitcastWordToTaggedSigned( - TryIntPtrAdd(BitcastTaggedSignedToWord(lhs), - BitcastTaggedSignedToWord(rhs), if_overflow)); + TryIntPtrAdd(BitcastTaggedToWordForTagAndSmiBits(lhs), + BitcastTaggedToWordForTagAndSmiBits(rhs), if_overflow)); } else { DCHECK(SmiValuesAre31Bits()); TNode<PairT<Int32T, BoolT>> pair = Int32AddWithOverflow( - TruncateIntPtrToInt32(BitcastTaggedSignedToWord(lhs)), - TruncateIntPtrToInt32(BitcastTaggedSignedToWord(rhs))); + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(lhs)), + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(rhs))); TNode<BoolT> overflow = Projection<1>(pair); GotoIf(overflow, if_overflow); TNode<Int32T> result = Projection<0>(pair); @@ -690,8 +870,9 @@ TNode<Smi> CodeStubAssembler::TrySmiAdd(TNode<Smi> lhs, TNode<Smi> rhs, TNode<Smi> CodeStubAssembler::TrySmiSub(TNode<Smi> lhs, TNode<Smi> rhs, Label* if_overflow) { if (SmiValuesAre32Bits()) { - TNode<PairT<IntPtrT, BoolT>> pair = IntPtrSubWithOverflow( - BitcastTaggedSignedToWord(lhs), BitcastTaggedSignedToWord(rhs)); + TNode<PairT<IntPtrT, BoolT>> pair = + IntPtrSubWithOverflow(BitcastTaggedToWordForTagAndSmiBits(lhs), + BitcastTaggedToWordForTagAndSmiBits(rhs)); TNode<BoolT> overflow = Projection<1>(pair); GotoIf(overflow, if_overflow); TNode<IntPtrT> result = Projection<0>(pair); @@ -699,8 +880,8 @@ TNode<Smi> CodeStubAssembler::TrySmiSub(TNode<Smi> lhs, TNode<Smi> rhs, } else { DCHECK(SmiValuesAre31Bits()); TNode<PairT<Int32T, BoolT>> pair = Int32SubWithOverflow( - TruncateIntPtrToInt32(BitcastTaggedSignedToWord(lhs)), - TruncateIntPtrToInt32(BitcastTaggedSignedToWord(rhs))); + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(lhs)), + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(rhs))); TNode<BoolT> overflow = Projection<1>(pair); GotoIf(overflow, if_overflow); TNode<Int32T> result = Projection<0>(pair); @@ -878,7 +1059,7 @@ TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) { } BIND(&answer_zero); { - TNode<Word32T> or_result = Word32Or(lhs32, rhs32); + TNode<Int32T> or_result = Word32Or(lhs32, rhs32); Label if_should_be_negative_zero(this), if_should_be_zero(this); Branch(Int32LessThan(or_result, zero), &if_should_be_negative_zero, &if_should_be_zero); @@ -982,41 +1163,27 @@ TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32( return ReinterpretCast<Int32T>(value); } -TNode<BoolT> CodeStubAssembler::TaggedIsSmi(SloppyTNode<Object> a) { - STATIC_ASSERT(kSmiTagMask < kMaxUInt32); - return Word32Equal(Word32And(TruncateIntPtrToInt32(BitcastTaggedToWord(a)), - Int32Constant(kSmiTagMask)), - Int32Constant(0)); -} - TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) { STATIC_ASSERT(kSmiTagMask < kMaxUInt32); return Word32Equal( - Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(a)), + Word32And(TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), Int32Constant(kSmiTagMask)), Int32Constant(0)); } -TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<Object> a) { - // Although BitcastTaggedSignedToWord is generally unsafe on HeapObjects, we - // can nonetheless use it to inspect the Smi tag. The assumption here is that - // the GC will not exchange Smis for HeapObjects or vice-versa. - TNode<IntPtrT> a_bitcast = BitcastTaggedSignedToWord(UncheckedCast<Smi>(a)); - STATIC_ASSERT(kSmiTagMask < kMaxUInt32); - return Word32NotEqual( - Word32And(TruncateIntPtrToInt32(a_bitcast), Int32Constant(kSmiTagMask)), - Int32Constant(0)); +TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(TNode<MaybeObject> a) { + return Word32BinaryNot(TaggedIsSmi(a)); } TNode<BoolT> CodeStubAssembler::TaggedIsPositiveSmi(SloppyTNode<Object> a) { #if defined(V8_HOST_ARCH_32_BIT) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH) return Word32Equal( Word32And( - TruncateIntPtrToInt32(BitcastTaggedToWord(a)), - Uint32Constant(kSmiTagMask | static_cast<int32_t>(kSmiSignMask))), + TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), + Uint32Constant(static_cast<uint32_t>(kSmiTagMask | kSmiSignMask))), Int32Constant(0)); #else - return WordEqual(WordAnd(BitcastTaggedToWord(a), + return WordEqual(WordAnd(BitcastTaggedToWordForTagAndSmiBits(a), IntPtrConstant(kSmiTagMask | kSmiSignMask)), IntPtrConstant(0)); #endif @@ -1052,55 +1219,6 @@ TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck( INTPTR_PARAMETERS, if_hole); } -void CodeStubAssembler::BranchIfPrototypesHaveNoElements( - Node* receiver_map, Label* definitely_no_elements, - Label* possibly_elements) { - CSA_SLOW_ASSERT(this, IsMap(receiver_map)); - VARIABLE(var_map, MachineRepresentation::kTagged, receiver_map); - Label loop_body(this, &var_map); - TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant(); - TNode<NumberDictionary> empty_slow_element_dictionary = - EmptySlowElementDictionaryConstant(); - Goto(&loop_body); - - BIND(&loop_body); - { - Node* map = var_map.value(); - TNode<HeapObject> prototype = LoadMapPrototype(map); - GotoIf(IsNull(prototype), definitely_no_elements); - TNode<Map> prototype_map = LoadMap(prototype); - TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map); - - // Pessimistically assume elements if a Proxy, Special API Object, - // or JSPrimitiveWrapper wrapper is found on the prototype chain. After this - // instance type check, it's not necessary to check for interceptors or - // access checks. - Label if_custom(this, Label::kDeferred), if_notcustom(this); - Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type), - &if_custom, &if_notcustom); - - BIND(&if_custom); - { - // For string JSPrimitiveWrapper wrappers we still support the checks as - // long as they wrap the empty string. - GotoIfNot( - InstanceTypeEqual(prototype_instance_type, JS_PRIMITIVE_WRAPPER_TYPE), - possibly_elements); - Node* prototype_value = LoadJSPrimitiveWrapperValue(prototype); - Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements); - } - - BIND(&if_notcustom); - { - TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype)); - var_map.Bind(prototype_map); - GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body); - Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary), - &loop_body, possibly_elements); - } - } -} - void CodeStubAssembler::BranchIfJSReceiver(SloppyTNode<Object> object, Label* if_true, Label* if_false) { GotoIf(TaggedIsSmi(object), if_false); @@ -1118,19 +1236,6 @@ void CodeStubAssembler::GotoIfForceSlowPath(Label* if_true) { #endif } -void CodeStubAssembler::GotoIfDebugExecutionModeChecksSideEffects( - Label* if_true) { - STATIC_ASSERT(sizeof(DebugInfo::ExecutionMode) >= sizeof(int32_t)); - - TNode<ExternalReference> execution_mode_address = ExternalConstant( - ExternalReference::debug_execution_mode_address(isolate())); - TNode<Int32T> execution_mode = - UncheckedCast<Int32T>(Load(MachineType::Int32(), execution_mode_address)); - - GotoIf(Word32Equal(execution_mode, Int32Constant(DebugInfo::kSideEffects)), - if_true); -} - TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes, AllocationFlags flags, TNode<RawPtrT> top_address, @@ -1557,7 +1662,7 @@ void CodeStubAssembler::GotoIfMapHasSlowProperties(TNode<Map> map, } TNode<HeapObject> CodeStubAssembler::LoadFastProperties( - SloppyTNode<JSObject> object) { + SloppyTNode<JSReceiver> object) { CSA_SLOW_ASSERT(this, Word32BinaryNot(IsDictionaryMap(LoadMap(object)))); TNode<Object> properties = LoadJSReceiverPropertiesOrHash(object); return Select<HeapObject>( @@ -1566,7 +1671,7 @@ TNode<HeapObject> CodeStubAssembler::LoadFastProperties( } TNode<HeapObject> CodeStubAssembler::LoadSlowProperties( - SloppyTNode<JSObject> object) { + SloppyTNode<JSReceiver> object) { CSA_SLOW_ASSERT(this, IsDictionaryMap(LoadMap(object))); TNode<Object> properties = LoadJSReceiverPropertiesOrHash(object); return Select<HeapObject>( @@ -1862,18 +1967,8 @@ TNode<Uint32T> CodeStubAssembler::LoadStringLengthAsWord32( return LoadObjectField<Uint32T>(string, String::kLengthOffset); } -Node* CodeStubAssembler::PointerToSeqStringData(Node* seq_string) { - CSA_ASSERT(this, IsString(seq_string)); - CSA_ASSERT(this, - IsSequentialStringInstanceType(LoadInstanceType(seq_string))); - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - return IntPtrAdd( - BitcastTaggedToWord(seq_string), - IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); -} - -Node* CodeStubAssembler::LoadJSPrimitiveWrapperValue(Node* object) { - CSA_ASSERT(this, IsJSPrimitiveWrapper(object)); +TNode<Object> CodeStubAssembler::LoadJSPrimitiveWrapperValue( + TNode<JSPrimitiveWrapper> object) { return LoadObjectField(object, JSPrimitiveWrapper::kValueOffset); } @@ -1887,15 +1982,9 @@ void CodeStubAssembler::DispatchMaybeObject(TNode<MaybeObject> maybe_object, GotoIf(IsCleared(maybe_object), if_cleared); - GotoIf(Word32Equal(Word32And(TruncateIntPtrToInt32( - BitcastMaybeObjectToWord(maybe_object)), - Int32Constant(kHeapObjectTagMask)), - Int32Constant(kHeapObjectTag)), - &inner_if_strong); + GotoIf(IsStrong(maybe_object), &inner_if_strong); - *extracted = - BitcastWordToTagged(WordAnd(BitcastMaybeObjectToWord(maybe_object), - IntPtrConstant(~kWeakHeapObjectMask))); + *extracted = GetHeapObjectAssumeWeak(maybe_object); Goto(if_weak); BIND(&inner_if_smi); @@ -1908,10 +1997,10 @@ void CodeStubAssembler::DispatchMaybeObject(TNode<MaybeObject> maybe_object, } TNode<BoolT> CodeStubAssembler::IsStrong(TNode<MaybeObject> value) { - return Word32Equal( - Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)), - Int32Constant(kHeapObjectTagMask)), - Int32Constant(kHeapObjectTag)); + return Word32Equal(Word32And(TruncateIntPtrToInt32( + BitcastTaggedToWordForTagAndSmiBits(value)), + Int32Constant(kHeapObjectTagMask)), + Int32Constant(kHeapObjectTag)); } TNode<HeapObject> CodeStubAssembler::GetHeapObjectIfStrong( @@ -1921,10 +2010,10 @@ TNode<HeapObject> CodeStubAssembler::GetHeapObjectIfStrong( } TNode<BoolT> CodeStubAssembler::IsWeakOrCleared(TNode<MaybeObject> value) { - return Word32Equal( - Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)), - Int32Constant(kHeapObjectTagMask)), - Int32Constant(kWeakHeapObjectTag)); + return Word32Equal(Word32And(TruncateIntPtrToInt32( + BitcastTaggedToWordForTagAndSmiBits(value)), + Int32Constant(kHeapObjectTagMask)), + Int32Constant(kWeakHeapObjectTag)); } TNode<BoolT> CodeStubAssembler::IsCleared(TNode<MaybeObject> value) { @@ -1932,11 +2021,6 @@ TNode<BoolT> CodeStubAssembler::IsCleared(TNode<MaybeObject> value) { Int32Constant(kClearedWeakHeapObjectLower32)); } -TNode<BoolT> CodeStubAssembler::IsNotCleared(TNode<MaybeObject> value) { - return Word32NotEqual(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)), - Int32Constant(kClearedWeakHeapObjectLower32)); -} - TNode<HeapObject> CodeStubAssembler::GetHeapObjectAssumeWeak( TNode<MaybeObject> value) { CSA_ASSERT(this, IsWeakOrCleared(value)); @@ -1951,43 +2035,41 @@ TNode<HeapObject> CodeStubAssembler::GetHeapObjectAssumeWeak( return GetHeapObjectAssumeWeak(value); } -TNode<BoolT> CodeStubAssembler::IsWeakReferenceTo(TNode<MaybeObject> object, - TNode<Object> value) { -#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_COMPRESS_POINTERS) - STATIC_ASSERT(kTaggedSize == kInt32Size); - return Word32Equal( - Word32And(TruncateWordToInt32(BitcastMaybeObjectToWord(object)), - Uint32Constant( - static_cast<uint32_t>(~kWeakHeapObjectMask & kMaxUInt32))), - TruncateWordToInt32(BitcastTaggedToWord(value))); -#else - return WordEqual(WordAnd(BitcastMaybeObjectToWord(object), - IntPtrConstant(~kWeakHeapObjectMask)), - BitcastTaggedToWord(value)); - -#endif -} - -TNode<BoolT> CodeStubAssembler::IsStrongReferenceTo(TNode<MaybeObject> object, - TNode<Object> value) { - return TaggedEqual(BitcastWordToTagged(BitcastMaybeObjectToWord(object)), - value); -} - -TNode<BoolT> CodeStubAssembler::IsNotWeakReferenceTo(TNode<MaybeObject> object, - TNode<Object> value) { -#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_COMPRESS_POINTERS) - return Word32NotEqual( - Word32And(TruncateWordToInt32(BitcastMaybeObjectToWord(object)), - Uint32Constant( - static_cast<uint32_t>(~kWeakHeapObjectMask & kMaxUInt32))), - TruncateWordToInt32(BitcastTaggedToWord(value))); -#else - return WordNotEqual(WordAnd(BitcastMaybeObjectToWord(object), - IntPtrConstant(~kWeakHeapObjectMask)), - BitcastTaggedToWord(value)); - -#endif +// This version generates +// (maybe_object & ~mask) == value +// It works for non-Smi |maybe_object| and for both Smi and HeapObject values +// but requires a big constant for ~mask. +TNode<BoolT> CodeStubAssembler::IsWeakReferenceToObject( + TNode<MaybeObject> maybe_object, TNode<Object> value) { + CSA_ASSERT(this, TaggedIsNotSmi(maybe_object)); + if (COMPRESS_POINTERS_BOOL) { + return Word32Equal( + Word32And(TruncateWordToInt32(BitcastMaybeObjectToWord(maybe_object)), + Uint32Constant(~static_cast<uint32_t>(kWeakHeapObjectMask))), + TruncateWordToInt32(BitcastTaggedToWord(value))); + } else { + return WordEqual(WordAnd(BitcastMaybeObjectToWord(maybe_object), + IntPtrConstant(~kWeakHeapObjectMask)), + BitcastTaggedToWord(value)); + } +} + +// This version generates +// maybe_object == (heap_object | mask) +// It works for any |maybe_object| values and generates a better code because it +// uses a small constant for mask. +TNode<BoolT> CodeStubAssembler::IsWeakReferenceTo( + TNode<MaybeObject> maybe_object, TNode<HeapObject> heap_object) { + if (COMPRESS_POINTERS_BOOL) { + return Word32Equal( + TruncateWordToInt32(BitcastMaybeObjectToWord(maybe_object)), + Word32Or(TruncateWordToInt32(BitcastTaggedToWord(heap_object)), + Int32Constant(kWeakHeapObjectMask))); + } else { + return WordEqual(BitcastMaybeObjectToWord(maybe_object), + WordOr(BitcastTaggedToWord(heap_object), + IntPtrConstant(kWeakHeapObjectMask))); + } } TNode<MaybeObject> CodeStubAssembler::MakeWeak(TNode<HeapObject> value) { @@ -2123,16 +2205,27 @@ TNode<IntPtrT> CodeStubAssembler::LoadPropertyArrayLength( return Signed(DecodeWord<PropertyArray::LengthField>(value)); } -TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayBackingStore( +TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayDataPtr( TNode<JSTypedArray> typed_array) { - // Backing store = external_pointer + base_pointer. - Node* external_pointer = - LoadObjectField(typed_array, JSTypedArray::kExternalPointerOffset, - MachineType::Pointer()); - TNode<Object> base_pointer = - LoadObjectField(typed_array, JSTypedArray::kBasePointerOffset); - return UncheckedCast<RawPtrT>( - IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer))); + // Data pointer = external_pointer + static_cast<Tagged_t>(base_pointer). + TNode<RawPtrT> external_pointer = LoadObjectField<RawPtrT>( + typed_array, JSTypedArray::kExternalPointerOffset); + + TNode<IntPtrT> base_pointer; + if (COMPRESS_POINTERS_BOOL) { + TNode<Int32T> compressed_base = + LoadObjectField<Int32T>(typed_array, JSTypedArray::kBasePointerOffset); + // Zero-extend TaggedT to WordT according to current compression scheme + // so that the addition with |external_pointer| (which already contains + // compensated offset value) below will decompress the tagged value. + // See JSTypedArray::ExternalPointerCompensationForOnHeapArray() for + // details. + base_pointer = Signed(ChangeUint32ToWord(compressed_base)); + } else { + base_pointer = + LoadObjectField<IntPtrT>(typed_array, JSTypedArray::kBasePointerOffset); + } + return RawPtrAdd(external_pointer, base_pointer); } TNode<BigInt> CodeStubAssembler::LoadFixedBigInt64ArrayElementAsTagged( @@ -2267,8 +2360,7 @@ TNode<BigInt> CodeStubAssembler::BigIntFromInt64(TNode<IntPtrT> value) { return var_result.value(); } -compiler::TNode<BigInt> -CodeStubAssembler::LoadFixedBigUint64ArrayElementAsTagged( +TNode<BigInt> CodeStubAssembler::LoadFixedBigUint64ArrayElementAsTagged( SloppyTNode<RawPtrT> data_pointer, SloppyTNode<IntPtrT> offset) { Label if_zero(this), done(this); if (Is64()) { @@ -2416,59 +2508,30 @@ TNode<Numeric> CodeStubAssembler::LoadFixedTypedArrayElementAsTagged( return var_result.value(); } -void CodeStubAssembler::StoreJSTypedArrayElementFromTagged( - TNode<Context> context, TNode<JSTypedArray> typed_array, - TNode<Smi> index_node, TNode<Object> value, ElementsKind elements_kind) { - TNode<RawPtrT> data_pointer = LoadJSTypedArrayBackingStore(typed_array); - switch (elements_kind) { - case UINT8_ELEMENTS: - case UINT8_CLAMPED_ELEMENTS: - case INT8_ELEMENTS: - case UINT16_ELEMENTS: - case INT16_ELEMENTS: - StoreElement(data_pointer, elements_kind, index_node, - SmiToInt32(CAST(value)), SMI_PARAMETERS); - break; - case UINT32_ELEMENTS: - case INT32_ELEMENTS: - StoreElement(data_pointer, elements_kind, index_node, - TruncateTaggedToWord32(context, value), SMI_PARAMETERS); - break; - case FLOAT32_ELEMENTS: - StoreElement(data_pointer, elements_kind, index_node, - TruncateFloat64ToFloat32(LoadHeapNumberValue(CAST(value))), - SMI_PARAMETERS); - break; - case FLOAT64_ELEMENTS: - StoreElement(data_pointer, elements_kind, index_node, - LoadHeapNumberValue(CAST(value)), SMI_PARAMETERS); - break; - case BIGUINT64_ELEMENTS: - case BIGINT64_ELEMENTS: - StoreElement(data_pointer, elements_kind, index_node, - UncheckedCast<BigInt>(value), SMI_PARAMETERS); - break; - default: - UNREACHABLE(); - } -} - +template <typename TIndex> TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot( - Node* object, Node* slot_index_node, int additional_offset, - ParameterMode parameter_mode) { - CSA_SLOW_ASSERT(this, IsFeedbackVector(object)); - CSA_SLOW_ASSERT(this, MatchesParameterMode(slot_index_node, parameter_mode)); + TNode<FeedbackVector> feedback_vector, TNode<TIndex> slot, + int additional_offset) { int32_t header_size = FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag; - TNode<IntPtrT> offset = ElementOffsetFromIndex( - slot_index_node, HOLEY_ELEMENTS, parameter_mode, header_size); + TNode<IntPtrT> offset = + ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, header_size); CSA_SLOW_ASSERT( - this, IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(object)), + this, IsOffsetInBounds(offset, LoadFeedbackVectorLength(feedback_vector), FeedbackVector::kHeaderSize)); - return UncheckedCast<MaybeObject>( - Load(MachineType::AnyTagged(), object, offset)); + return Load<MaybeObject>(feedback_vector, offset); } +template TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot( + TNode<FeedbackVector> feedback_vector, TNode<Smi> slot, + int additional_offset); +template TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot( + TNode<FeedbackVector> feedback_vector, TNode<IntPtrT> slot, + int additional_offset); +template TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot( + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot, + int additional_offset); + template <typename Array> TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ArrayElement( TNode<Array> object, int array_header_size, Node* index_node, @@ -2617,6 +2680,13 @@ TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck( return UncheckedCast<Float64T>(Load(machine_type, base, offset)); } +TNode<BoolT> CodeStubAssembler::LoadContextHasExtensionField( + SloppyTNode<Context> context) { + TNode<IntPtrT> value = + LoadAndUntagObjectField(context, Context::kLengthOffset); + return IsSetWord<Context::HasExtensionField>(value); +} + TNode<Object> CodeStubAssembler::LoadContextElement( SloppyTNode<Context> context, int slot_index) { int offset = Context::SlotOffset(slot_index); @@ -2626,15 +2696,15 @@ TNode<Object> CodeStubAssembler::LoadContextElement( TNode<Object> CodeStubAssembler::LoadContextElement( SloppyTNode<Context> context, SloppyTNode<IntPtrT> slot_index) { - TNode<IntPtrT> offset = ElementOffsetFromIndex( - slot_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, Context::SlotOffset(0)); + TNode<IntPtrT> offset = ElementOffsetFromIndex(slot_index, PACKED_ELEMENTS, + Context::SlotOffset(0)); return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset)); } TNode<Object> CodeStubAssembler::LoadContextElement(TNode<Context> context, TNode<Smi> slot_index) { - TNode<IntPtrT> offset = ElementOffsetFromIndex( - slot_index, PACKED_ELEMENTS, SMI_PARAMETERS, Context::SlotOffset(0)); + TNode<IntPtrT> offset = ElementOffsetFromIndex(slot_index, PACKED_ELEMENTS, + Context::SlotOffset(0)); return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset)); } @@ -2949,33 +3019,30 @@ void CodeStubAssembler::StoreFixedDoubleArrayElement( StoreNoWriteBarrier(rep, object, offset, value_silenced); } -void CodeStubAssembler::StoreFeedbackVectorSlot(Node* object, - Node* slot_index_node, - Node* value, - WriteBarrierMode barrier_mode, - int additional_offset, - ParameterMode parameter_mode) { - CSA_SLOW_ASSERT(this, IsFeedbackVector(object)); - CSA_SLOW_ASSERT(this, MatchesParameterMode(slot_index_node, parameter_mode)); +void CodeStubAssembler::StoreFeedbackVectorSlot( + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot, + TNode<AnyTaggedT> value, WriteBarrierMode barrier_mode, + int additional_offset) { DCHECK(IsAligned(additional_offset, kTaggedSize)); DCHECK(barrier_mode == SKIP_WRITE_BARRIER || barrier_mode == UNSAFE_SKIP_WRITE_BARRIER || barrier_mode == UPDATE_WRITE_BARRIER); int header_size = FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag; - TNode<IntPtrT> offset = ElementOffsetFromIndex( - slot_index_node, HOLEY_ELEMENTS, parameter_mode, header_size); - // Check that slot_index_node <= object.length. + TNode<IntPtrT> offset = + ElementOffsetFromIndex(Signed(slot), HOLEY_ELEMENTS, header_size); + // Check that slot <= feedback_vector.length. CSA_ASSERT(this, - IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(object)), + IsOffsetInBounds(offset, LoadFeedbackVectorLength(feedback_vector), FeedbackVector::kHeaderSize)); if (barrier_mode == SKIP_WRITE_BARRIER) { - StoreNoWriteBarrier(MachineRepresentation::kTagged, object, offset, value); + StoreNoWriteBarrier(MachineRepresentation::kTagged, feedback_vector, offset, + value); } else if (barrier_mode == UNSAFE_SKIP_WRITE_BARRIER) { - UnsafeStoreNoWriteBarrier(MachineRepresentation::kTagged, object, offset, - value); + UnsafeStoreNoWriteBarrier(MachineRepresentation::kTagged, feedback_vector, + offset, value); } else { - Store(object, offset, value); + Store(feedback_vector, offset, value); } } @@ -3045,33 +3112,29 @@ TNode<Smi> CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Label success(this); TVARIABLE(Smi, var_tagged_length); ParameterMode mode = OptimalParameterMode(); - VARIABLE(var_length, OptimalParameterRepresentation(), - TaggedToParameter(LoadFastJSArrayLength(array), mode)); - VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array)); + TVARIABLE(BInt, var_length, SmiToBInt(LoadFastJSArrayLength(array))); + TVARIABLE(FixedArrayBase, var_elements, LoadElements(array)); // Resize the capacity of the fixed array if it doesn't fit. TNode<IntPtrT> first = arg_index->value(); - Node* growth = IntPtrToParameter( - IntPtrSub(UncheckedCast<IntPtrT>(args->GetLength(INTPTR_PARAMETERS)), - first), - mode); + TNode<BInt> growth = IntPtrToBInt(IntPtrSub(args->GetLength(), first)); PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(), &var_elements, growth, &pre_bailout); // Push each argument onto the end of the array now that there is enough // capacity. CodeStubAssembler::VariableList push_vars({&var_length}, zone()); - Node* elements = var_elements.value(); + TNode<FixedArrayBase> elements = var_elements.value(); args->ForEach( push_vars, - [this, kind, mode, elements, &var_length, &pre_bailout](Node* arg) { + [&](TNode<Object> arg) { TryStoreArrayElement(kind, mode, &pre_bailout, elements, var_length.value(), arg); - Increment(&var_length, 1, mode); + Increment(&var_length); }, - first, nullptr); + first); { - TNode<Smi> length = ParameterToTagged(var_length.value(), mode); + TNode<Smi> length = BIntToSmi(var_length.value()); var_tagged_length = length; StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); Goto(&success); @@ -3111,8 +3174,7 @@ void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, CSA_SLOW_ASSERT(this, IsJSArray(array)); Comment("BuildAppendJSArray: ", ElementsKindToString(kind)); ParameterMode mode = OptimalParameterMode(); - VARIABLE(var_length, OptimalParameterRepresentation(), - TaggedToParameter(LoadFastJSArrayLength(array), mode)); + TVARIABLE(BInt, var_length, SmiToBInt(LoadFastJSArrayLength(array))); VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array)); // Resize the capacity of the fixed array if it doesn't fit. @@ -3124,9 +3186,9 @@ void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, // capacity. TryStoreArrayElement(kind, mode, bailout, var_elements.value(), var_length.value(), value); - Increment(&var_length, 1, mode); + Increment(&var_length); - TNode<Smi> length = ParameterToTagged(var_length.value(), mode); + TNode<Smi> length = BIntToSmi(var_length.value()); StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); } @@ -3138,7 +3200,7 @@ Node* CodeStubAssembler::AllocateCellWithValue(Node* value, return result; } -Node* CodeStubAssembler::LoadCellValue(Node* cell) { +TNode<Object> CodeStubAssembler::LoadCellValue(Node* cell) { CSA_SLOW_ASSERT(this, HasInstanceType(cell, CELL_TYPE)); return LoadObjectField(cell, Cell::kValueOffset); } @@ -3278,7 +3340,8 @@ TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length, TNode<IntPtrT> raw_size = GetArrayAllocationSize(Signed(length), UINT8_ELEMENTS, INTPTR_PARAMETERS, ByteArray::kHeaderSize + kObjectAlignmentMask); - TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); + TNode<IntPtrT> size = + WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), &if_sizeissmall, &if_notsizeissmall); @@ -3352,7 +3415,8 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString( TNode<IntPtrT> raw_size = GetArrayAllocationSize( Signed(ChangeUint32ToWord(length)), UINT8_ELEMENTS, INTPTR_PARAMETERS, SeqOneByteString::kHeaderSize + kObjectAlignmentMask); - TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); + TNode<IntPtrT> size = + WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), &if_sizeissmall, &if_notsizeissmall); @@ -3423,7 +3487,8 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString( TNode<IntPtrT> raw_size = GetArrayAllocationSize( Signed(ChangeUint32ToWord(length)), UINT16_ELEMENTS, INTPTR_PARAMETERS, SeqOneByteString::kHeaderSize + kObjectAlignmentMask); - TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); + TNode<IntPtrT> size = + WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), &if_sizeissmall, &if_notsizeissmall); @@ -3496,35 +3561,6 @@ TNode<String> CodeStubAssembler::AllocateSlicedTwoByteString( offset); } -TNode<String> CodeStubAssembler::AllocateConsString(TNode<Uint32T> length, - TNode<String> left, - TNode<String> right) { - // Added string can be a cons string. - Comment("Allocating ConsString"); - TNode<Int32T> left_instance_type = LoadInstanceType(left); - TNode<Int32T> right_instance_type = LoadInstanceType(right); - - // Determine the resulting ConsString map to use depending on whether - // any of {left} or {right} has two byte encoding. - STATIC_ASSERT(kOneByteStringTag != 0); - STATIC_ASSERT(kTwoByteStringTag == 0); - TNode<Int32T> combined_instance_type = - Word32And(left_instance_type, right_instance_type); - TNode<Map> result_map = CAST(Select<Object>( - IsSetWord32(combined_instance_type, kStringEncodingMask), - [=] { return ConsOneByteStringMapConstant(); }, - [=] { return ConsStringMapConstant(); })); - TNode<HeapObject> result = AllocateInNewSpace(ConsString::kSize); - StoreMapNoWriteBarrier(result, result_map); - StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length, - MachineRepresentation::kWord32); - StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset, - Int32Constant(String::kEmptyHashField), - MachineRepresentation::kWord32); - StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, left); - StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, right); - return CAST(result); -} TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionary( int at_least_space_for) { @@ -3762,106 +3798,26 @@ template V8_EXPORT_PRIVATE TNode<SmallOrderedHashSet> CodeStubAssembler::AllocateSmallOrderedHashTable<SmallOrderedHashSet>( TNode<IntPtrT> capacity); -template <typename CollectionType> -void CodeStubAssembler::FindOrderedHashTableEntry( - Node* table, Node* hash, - const std::function<void(TNode<Object>, Label*, Label*)>& key_compare, - Variable* entry_start_position, Label* entry_found, Label* not_found) { - // Get the index of the bucket. - TNode<IntPtrT> const number_of_buckets = - SmiUntag(CAST(UnsafeLoadFixedArrayElement( - CAST(table), CollectionType::NumberOfBucketsIndex()))); - TNode<WordT> const bucket = - WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1))); - TNode<IntPtrT> const first_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement( - CAST(table), bucket, - CollectionType::HashTableStartIndex() * kTaggedSize))); - - // Walk the bucket chain. - TNode<IntPtrT> entry_start; - Label if_key_found(this); - { - TVARIABLE(IntPtrT, var_entry, first_entry); - Label loop(this, {&var_entry, entry_start_position}), - continue_next_entry(this); - Goto(&loop); - BIND(&loop); - - // If the entry index is the not-found sentinel, we are done. - GotoIf(IntPtrEqual(var_entry.value(), - IntPtrConstant(CollectionType::kNotFound)), - not_found); - - // Make sure the entry index is within range. - CSA_ASSERT( - this, - UintPtrLessThan( - var_entry.value(), - SmiUntag(SmiAdd( - CAST(UnsafeLoadFixedArrayElement( - CAST(table), CollectionType::NumberOfElementsIndex())), - CAST(UnsafeLoadFixedArrayElement( - CAST(table), - CollectionType::NumberOfDeletedElementsIndex())))))); - - // Compute the index of the entry relative to kHashTableStartIndex. - entry_start = - IntPtrAdd(IntPtrMul(var_entry.value(), - IntPtrConstant(CollectionType::kEntrySize)), - number_of_buckets); - - // Load the key from the entry. - TNode<Object> const candidate_key = UnsafeLoadFixedArrayElement( - CAST(table), entry_start, - CollectionType::HashTableStartIndex() * kTaggedSize); - - key_compare(candidate_key, &if_key_found, &continue_next_entry); - - BIND(&continue_next_entry); - // Load the index of the next entry in the bucket chain. - var_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement( - CAST(table), entry_start, - (CollectionType::HashTableStartIndex() + CollectionType::kChainOffset) * - kTaggedSize))); - - Goto(&loop); - } - - BIND(&if_key_found); - entry_start_position->Bind(entry_start); - Goto(entry_found); -} - -template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashMap>( - Node* table, Node* hash, - const std::function<void(TNode<Object>, Label*, Label*)>& key_compare, - Variable* entry_start_position, Label* entry_found, Label* not_found); -template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashSet>( - Node* table, Node* hash, - const std::function<void(TNode<Object>, Label*, Label*)>& key_compare, - Variable* entry_start_position, Label* entry_found, Label* not_found); - Node* CodeStubAssembler::AllocateStruct(Node* map, AllocationFlags flags) { Comment("AllocateStruct"); CSA_ASSERT(this, IsMap(map)); TNode<IntPtrT> size = TimesTaggedSize(LoadMapInstanceSizeInWords(map)); TNode<HeapObject> object = Allocate(size, flags); StoreMapNoWriteBarrier(object, map); - InitializeStructBody(object, map, size, Struct::kHeaderSize); + InitializeStructBody(object, size, Struct::kHeaderSize); return object; } -void CodeStubAssembler::InitializeStructBody(Node* object, Node* map, - Node* size, int start_offset) { - CSA_SLOW_ASSERT(this, IsMap(map)); +void CodeStubAssembler::InitializeStructBody(TNode<HeapObject> object, + TNode<IntPtrT> size, + int start_offset) { Comment("InitializeStructBody"); TNode<Oddball> filler = UndefinedConstant(); // Calculate the untagged field addresses. - object = BitcastTaggedToWord(object); - TNode<WordT> start_address = - IntPtrAdd(object, IntPtrConstant(start_offset - kHeapObjectTag)); - TNode<WordT> end_address = - IntPtrSub(IntPtrAdd(object, size), IntPtrConstant(kHeapObjectTag)); + TNode<IntPtrT> start_address = + IntPtrAdd(BitcastTaggedToWord(object), + IntPtrConstant(start_offset - kHeapObjectTag)); + TNode<IntPtrT> end_address = IntPtrAdd(start_address, size); StoreFieldsNoWriteBarrier(start_address, end_address, filler); } @@ -3883,8 +3839,9 @@ TNode<JSObject> CodeStubAssembler::AllocateJSObjectFromMap( } void CodeStubAssembler::InitializeJSObjectFromMap( - Node* object, Node* map, Node* instance_size, Node* properties, - Node* elements, SlackTrackingMode slack_tracking_mode) { + SloppyTNode<HeapObject> object, SloppyTNode<Map> map, + SloppyTNode<IntPtrT> instance_size, Node* properties, Node* elements, + SlackTrackingMode slack_tracking_mode) { CSA_SLOW_ASSERT(this, IsMap(map)); // This helper assumes that the object is in new-space, as guarded by the // check in AllocatedJSObjectFromMap. @@ -3915,7 +3872,8 @@ void CodeStubAssembler::InitializeJSObjectFromMap( } void CodeStubAssembler::InitializeJSObjectBodyNoSlackTracking( - Node* object, Node* map, Node* instance_size, int start_offset) { + SloppyTNode<HeapObject> object, SloppyTNode<Map> map, + SloppyTNode<IntPtrT> instance_size, int start_offset) { STATIC_ASSERT(Map::kNoSlackTracking == 0); CSA_ASSERT( this, IsClearWord32<Map::ConstructionCounterBits>(LoadMapBitField3(map))); @@ -3924,8 +3882,8 @@ void CodeStubAssembler::InitializeJSObjectBodyNoSlackTracking( } void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking( - Node* object, Node* map, Node* instance_size) { - CSA_SLOW_ASSERT(this, IsMap(map)); + SloppyTNode<HeapObject> object, SloppyTNode<Map> map, + SloppyTNode<IntPtrT> instance_size) { Comment("InitializeJSObjectBodyNoSlackTracking"); // Perform in-object slack tracking if requested. @@ -3953,9 +3911,9 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking( // The object still has in-object slack therefore the |unsed_or_unused| // field contain the "used" value. - TNode<UintPtrT> used_size = TimesTaggedSize(ChangeUint32ToWord( + TNode<IntPtrT> used_size = Signed(TimesTaggedSize(ChangeUint32ToWord( LoadObjectField(map, Map::kUsedOrUnusedInstanceSizeInWordsOffset, - MachineType::Uint8()))); + MachineType::Uint8())))); Comment("iInitialize filler fields"); InitializeFieldsWithRoot(object, used_size, instance_size, @@ -3984,19 +3942,19 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking( BIND(&end); } -void CodeStubAssembler::StoreFieldsNoWriteBarrier(Node* start_address, - Node* end_address, - Node* value) { +void CodeStubAssembler::StoreFieldsNoWriteBarrier(TNode<IntPtrT> start_address, + TNode<IntPtrT> end_address, + TNode<Object> value) { Comment("StoreFieldsNoWriteBarrier"); CSA_ASSERT(this, WordIsAligned(start_address, kTaggedSize)); CSA_ASSERT(this, WordIsAligned(end_address, kTaggedSize)); - BuildFastLoop( + BuildFastLoop<IntPtrT>( start_address, end_address, - [this, value](Node* current) { + [=](TNode<IntPtrT> current) { UnsafeStoreNoWriteBarrier(MachineRepresentation::kTagged, current, value); }, - kTaggedSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); + kTaggedSize, IndexAdvanceMode::kPost); } TNode<BoolT> CodeStubAssembler::IsValidFastJSArrayCapacity( @@ -4008,12 +3966,12 @@ TNode<BoolT> CodeStubAssembler::IsValidFastJSArrayCapacity( TNode<JSArray> CodeStubAssembler::AllocateJSArray( TNode<Map> array_map, TNode<FixedArrayBase> elements, TNode<Smi> length, - Node* allocation_site, int array_header_size) { + TNode<AllocationSite> allocation_site, int array_header_size) { Comment("begin allocation of JSArray passing in elements"); CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); int base_size = array_header_size; - if (allocation_site != nullptr) { + if (!allocation_site.is_null()) { base_size += AllocationMemento::kSize; } @@ -4027,8 +3985,9 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray( std::pair<TNode<JSArray>, TNode<FixedArrayBase>> CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ElementsKind kind, TNode<Map> array_map, TNode<Smi> length, - Node* allocation_site, Node* capacity, ParameterMode capacity_mode, - AllocationFlags allocation_flags, int array_header_size) { + TNode<AllocationSite> allocation_site, Node* capacity, + ParameterMode capacity_mode, AllocationFlags allocation_flags, + int array_header_size) { Comment("begin allocation of JSArray with elements"); CHECK_EQ(allocation_flags & ~kAllowLargeObjectAllocation, 0); CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); @@ -4065,7 +4024,9 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( BIND(&nonempty); { int base_size = array_header_size; - if (allocation_site != nullptr) base_size += AllocationMemento::kSize; + if (!allocation_site.is_null()) { + base_size += AllocationMemento::kSize; + } const int elements_offset = base_size; @@ -4138,8 +4099,8 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( } TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArray( - TNode<Map> array_map, TNode<Smi> length, Node* allocation_site, - TNode<IntPtrT> size_in_bytes) { + TNode<Map> array_map, TNode<Smi> length, + TNode<AllocationSite> allocation_site, TNode<IntPtrT> size_in_bytes) { CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); // Allocate space for the JSArray and the elements FixedArray in one go. @@ -4150,7 +4111,7 @@ TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArray( StoreObjectFieldRoot(array, JSArray::kPropertiesOrHashOffset, RootIndex::kEmptyFixedArray); - if (allocation_site != nullptr) { + if (!allocation_site.is_null()) { InitializeAllocationMemento(array, IntPtrConstant(JSArray::kSize), allocation_site); } @@ -4160,7 +4121,7 @@ TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArray( TNode<JSArray> CodeStubAssembler::AllocateJSArray( ElementsKind kind, TNode<Map> array_map, Node* capacity, TNode<Smi> length, - Node* allocation_site, ParameterMode capacity_mode, + TNode<AllocationSite> allocation_site, ParameterMode capacity_mode, AllocationFlags allocation_flags) { CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, capacity_mode)); @@ -4189,10 +4150,9 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray( return array; } -Node* CodeStubAssembler::ExtractFastJSArray(Node* context, Node* array, - Node* begin, Node* count, - ParameterMode mode, Node* capacity, - Node* allocation_site) { +Node* CodeStubAssembler::ExtractFastJSArray( + TNode<Context> context, TNode<JSArray> array, Node* begin, Node* count, + ParameterMode mode, Node* capacity, TNode<AllocationSite> allocation_site) { TNode<Map> original_array_map = LoadMap(array); TNode<Int32T> elements_kind = LoadMapElementsKind(original_array_map); @@ -4209,18 +4169,16 @@ Node* CodeStubAssembler::ExtractFastJSArray(Node* context, Node* array, return result; } -Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array, - ParameterMode mode, - Node* allocation_site, - HoleConversionMode convert_holes) { +TNode<JSArray> CodeStubAssembler::CloneFastJSArray( + TNode<Context> context, TNode<JSArray> array, ParameterMode mode, + TNode<AllocationSite> allocation_site, HoleConversionMode convert_holes) { // TODO(dhai): we should be able to assert IsFastJSArray(array) here, but this // function is also used to copy boilerplates even when the no-elements // protector is invalid. This function should be renamed to reflect its uses. - CSA_ASSERT(this, IsJSArray(array)); TNode<Number> length = LoadJSArrayLength(array); - Node* new_elements = nullptr; - VARIABLE(var_new_elements, MachineRepresentation::kTagged); + TNode<FixedArrayBase> new_elements; + TVARIABLE(FixedArrayBase, var_new_elements); TVARIABLE(Int32T, var_elements_kind, LoadMapElementsKind(LoadMap(array))); Label allocate_jsarray(this), holey_extract(this), @@ -4240,7 +4198,7 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array, TaggedToParameter(CAST(length), mode), nullptr, ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW, mode, nullptr, var_elements_kind.value()); - var_new_elements.Bind(new_elements); + var_new_elements = new_elements; Goto(&allocate_jsarray); if (need_conversion) { @@ -4257,7 +4215,7 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array, LoadElements(array), IntPtrOrSmiConstant(0, mode), TaggedToParameter(CAST(length), mode), nullptr, ExtractFixedArrayFlag::kAllFixedArrays, mode, &var_holes_converted); - var_new_elements.Bind(new_elements); + var_new_elements = new_elements; // If the array type didn't change, use the original elements kind. GotoIfNot(var_holes_converted.value(), &allocate_jsarray); // Otherwise use PACKED_ELEMENTS for the target's elements kind. @@ -4283,8 +4241,8 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array, TNode<Map> array_map = LoadJSArrayElementsMap(var_elements_kind.value(), native_context); - TNode<JSArray> result = AllocateJSArray( - array_map, CAST(var_new_elements.value()), CAST(length), allocation_site); + TNode<JSArray> result = AllocateJSArray(array_map, var_new_elements.value(), + CAST(length), allocation_site); return result; } @@ -4555,14 +4513,14 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedDoubleArrayFillingHoles( const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag; TNode<IntPtrT> first_from_element_offset = ElementOffsetFromIndex(first, kind, mode, 0); - TNode<WordT> limit_offset = IntPtrAdd(first_from_element_offset, - IntPtrConstant(first_element_offset)); + TNode<IntPtrT> limit_offset = IntPtrAdd(first_from_element_offset, + IntPtrConstant(first_element_offset)); TVARIABLE(IntPtrT, var_from_offset, ElementOffsetFromIndex(IntPtrOrSmiAdd(first, count, mode), kind, mode, first_element_offset)); Label decrement(this, {&var_from_offset}), done(this); - TNode<WordT> to_array_adjusted = + TNode<IntPtrT> to_array_adjusted = IntPtrSub(BitcastTaggedToWord(to_elements), first_from_element_offset); Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement); @@ -4908,12 +4866,10 @@ void CodeStubAssembler::MoveElements(ElementsKind kind, TNode<IntPtrT> elements_intptr = BitcastTaggedToWord(elements); TNode<IntPtrT> target_data_ptr = IntPtrAdd(elements_intptr, - ElementOffsetFromIndex(dst_index, kind, INTPTR_PARAMETERS, - fa_base_data_offset)); + ElementOffsetFromIndex(dst_index, kind, fa_base_data_offset)); TNode<IntPtrT> source_data_ptr = IntPtrAdd(elements_intptr, - ElementOffsetFromIndex(src_index, kind, INTPTR_PARAMETERS, - fa_base_data_offset)); + ElementOffsetFromIndex(src_index, kind, fa_base_data_offset)); TNode<ExternalReference> memmove = ExternalConstant(ExternalReference::libc_memmove_function()); CallCFunction(memmove, MachineType::Pointer(), @@ -4997,10 +4953,10 @@ void CodeStubAssembler::CopyElements(ElementsKind kind, IntPtrMul(length, IntPtrConstant(ElementsKindToByteSize(kind))); static const int32_t fa_base_data_offset = FixedArrayBase::kHeaderSize - kHeapObjectTag; - TNode<IntPtrT> src_offset_start = ElementOffsetFromIndex( - src_index, kind, INTPTR_PARAMETERS, fa_base_data_offset); - TNode<IntPtrT> dst_offset_start = ElementOffsetFromIndex( - dst_index, kind, INTPTR_PARAMETERS, fa_base_data_offset); + TNode<IntPtrT> src_offset_start = + ElementOffsetFromIndex(src_index, kind, fa_base_data_offset); + TNode<IntPtrT> dst_offset_start = + ElementOffsetFromIndex(dst_index, kind, fa_base_data_offset); TNode<IntPtrT> src_elements_intptr = BitcastTaggedToWord(src_elements); TNode<IntPtrT> source_data_ptr = IntPtrAdd(src_elements_intptr, src_offset_start); @@ -5283,65 +5239,6 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array, Comment("] CopyPropertyArrayValues"); } -void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string, - TNode<IntPtrT> from_index, - TNode<IntPtrT> to_index, - TNode<IntPtrT> character_count, - String::Encoding from_encoding, - String::Encoding to_encoding) { - // Cannot assert IsString(from_string) and IsString(to_string) here because - // CSA::SubString can pass in faked sequential strings when handling external - // subject strings. - bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING; - bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING; - DCHECK_IMPLIES(to_one_byte, from_one_byte); - Comment("CopyStringCharacters ", - from_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING", " -> ", - to_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING"); - - ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; - ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag; - TNode<IntPtrT> from_offset = ElementOffsetFromIndex( - from_index, from_kind, INTPTR_PARAMETERS, header_size); - TNode<IntPtrT> to_offset = - ElementOffsetFromIndex(to_index, to_kind, INTPTR_PARAMETERS, header_size); - TNode<IntPtrT> byte_count = - ElementOffsetFromIndex(character_count, from_kind, INTPTR_PARAMETERS); - TNode<WordT> limit_offset = IntPtrAdd(from_offset, byte_count); - - // Prepare the fast loop - MachineType type = - from_one_byte ? MachineType::Uint8() : MachineType::Uint16(); - MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8 - : MachineRepresentation::kWord16; - int from_increment = 1 << ElementsKindToShiftSize(from_kind); - int to_increment = 1 << ElementsKindToShiftSize(to_kind); - - VARIABLE(current_to_offset, MachineType::PointerRepresentation(), to_offset); - VariableList vars({¤t_to_offset}, zone()); - int to_index_constant = 0, from_index_constant = 0; - bool index_same = (from_encoding == to_encoding) && - (from_index == to_index || - (ToInt32Constant(from_index, &from_index_constant) && - ToInt32Constant(to_index, &to_index_constant) && - from_index_constant == to_index_constant)); - BuildFastLoop( - vars, from_offset, limit_offset, - [this, from_string, to_string, ¤t_to_offset, to_increment, type, - rep, index_same](Node* offset) { - Node* value = Load(type, from_string, offset); - StoreNoWriteBarrier(rep, to_string, - index_same ? offset : current_to_offset.value(), - value); - if (!index_same) { - Increment(¤t_to_offset, to_increment); - } - }, - from_increment, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); -} - Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, Node* offset, ElementsKind from_kind, @@ -5381,9 +5278,9 @@ Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity, return IntPtrOrSmiAdd(new_capacity, padding, mode); } -Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements, - ElementsKind kind, Node* key, - Label* bailout) { +TNode<FixedArrayBase> CodeStubAssembler::TryGrowElementsCapacity( + Node* object, Node* elements, ElementsKind kind, Node* key, + Label* bailout) { CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(elements, kind)); CSA_SLOW_ASSERT(this, TaggedIsSmi(key)); @@ -5395,11 +5292,9 @@ Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements, TaggedToParameter(capacity, mode), mode, bailout); } -Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements, - ElementsKind kind, Node* key, - Node* capacity, - ParameterMode mode, - Label* bailout) { +TNode<FixedArrayBase> CodeStubAssembler::TryGrowElementsCapacity( + Node* object, Node* elements, ElementsKind kind, Node* key, Node* capacity, + ParameterMode mode, Label* bailout) { Comment("TryGrowElementsCapacity"); CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(elements, kind)); @@ -5418,7 +5313,7 @@ Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements, new_capacity, mode, bailout); } -Node* CodeStubAssembler::GrowElementsCapacity( +TNode<FixedArrayBase> CodeStubAssembler::GrowElementsCapacity( Node* object, Node* elements, ElementsKind from_kind, ElementsKind to_kind, Node* capacity, Node* new_capacity, ParameterMode mode, Label* bailout) { Comment("[ GrowElementsCapacity"); @@ -5471,45 +5366,22 @@ void CodeStubAssembler::InitializeAllocationMemento(Node* base, Comment("]"); } -Node* CodeStubAssembler::TryTaggedToFloat64(Node* value, - Label* if_valueisnotnumber) { - Label out(this); - VARIABLE(var_result, MachineRepresentation::kFloat64); - - // Check if the {value} is a Smi or a HeapObject. - Label if_valueissmi(this), if_valueisnotsmi(this); - Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi); - - BIND(&if_valueissmi); - { - // Convert the Smi {value}. - var_result.Bind(SmiToFloat64(value)); - Goto(&out); - } - - BIND(&if_valueisnotsmi); - { - // Check if {value} is a HeapNumber. - Label if_valueisheapnumber(this); - Branch(IsHeapNumber(value), &if_valueisheapnumber, if_valueisnotnumber); - - BIND(&if_valueisheapnumber); - { - // Load the floating point value. - var_result.Bind(LoadHeapNumberValue(value)); - Goto(&out); - } - } - BIND(&out); - return var_result.value(); +TNode<Float64T> CodeStubAssembler::TryTaggedToFloat64( + TNode<Object> value, Label* if_valueisnotnumber) { + return Select<Float64T>( + TaggedIsSmi(value), [&]() { return SmiToFloat64(CAST(value)); }, + [&]() { + GotoIfNot(IsHeapNumber(CAST(value)), if_valueisnotnumber); + return LoadHeapNumberValue(CAST(value)); + }); } -Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) { +TNode<Float64T> CodeStubAssembler::TruncateTaggedToFloat64( + SloppyTNode<Context> context, SloppyTNode<Object> value) { // We might need to loop once due to ToNumber conversion. - VARIABLE(var_value, MachineRepresentation::kTagged); - VARIABLE(var_result, MachineRepresentation::kFloat64); + TVARIABLE(Object, var_value, value); + TVARIABLE(Float64T, var_result); Label loop(this, &var_value), done_loop(this, &var_result); - var_value.Bind(value); Goto(&loop); BIND(&loop); { @@ -5520,14 +5392,13 @@ Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) { // Convert {value} to Float64 if it is a number and convert it to a number // otherwise. - Node* const result = TryTaggedToFloat64(value, &if_valueisnotnumber); - var_result.Bind(result); + var_result = TryTaggedToFloat64(value, &if_valueisnotnumber); Goto(&done_loop); BIND(&if_valueisnotnumber); { // Convert the {value} to a Number first. - var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value)); + var_value = CallBuiltin(Builtins::kNonNumberToNumber, context, value); Goto(&loop); } } @@ -5535,8 +5406,9 @@ Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) { return var_result.value(); } -Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) { - VARIABLE(var_result, MachineRepresentation::kWord32); +TNode<Word32T> CodeStubAssembler::TruncateTaggedToWord32( + SloppyTNode<Context> context, SloppyTNode<Object> value) { + TVARIABLE(Word32T, var_result); Label done(this); TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumber>(context, value, &done, &var_result); @@ -5546,38 +5418,33 @@ Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) { // Truncate {value} to word32 and jump to {if_number} if it is a Number, // or find that it is a BigInt and jump to {if_bigint}. -void CodeStubAssembler::TaggedToWord32OrBigInt(Node* context, Node* value, - Label* if_number, - Variable* var_word32, - Label* if_bigint, - Variable* var_bigint) { +void CodeStubAssembler::TaggedToWord32OrBigInt( + TNode<Context> context, TNode<Object> value, Label* if_number, + TVariable<Word32T>* var_word32, Label* if_bigint, + TVariable<Object>* var_maybe_bigint) { TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumeric>( - context, value, if_number, var_word32, if_bigint, var_bigint); + context, value, if_number, var_word32, if_bigint, var_maybe_bigint); } // Truncate {value} to word32 and jump to {if_number} if it is a Number, // or find that it is a BigInt and jump to {if_bigint}. In either case, // store the type feedback in {var_feedback}. void CodeStubAssembler::TaggedToWord32OrBigIntWithFeedback( - Node* context, Node* value, Label* if_number, Variable* var_word32, - Label* if_bigint, Variable* var_bigint, Variable* var_feedback) { + TNode<Context> context, TNode<Object> value, Label* if_number, + TVariable<Word32T>* var_word32, Label* if_bigint, + TVariable<Object>* var_maybe_bigint, TVariable<Smi>* var_feedback) { TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumeric>( - context, value, if_number, var_word32, if_bigint, var_bigint, + context, value, if_number, var_word32, if_bigint, var_maybe_bigint, var_feedback); } template <Object::Conversion conversion> void CodeStubAssembler::TaggedToWord32OrBigIntImpl( - Node* context, Node* value, Label* if_number, Variable* var_word32, - Label* if_bigint, Variable* var_bigint, Variable* var_feedback) { - DCHECK(var_word32->rep() == MachineRepresentation::kWord32); - DCHECK(var_bigint == nullptr || - var_bigint->rep() == MachineRepresentation::kTagged); - DCHECK(var_feedback == nullptr || - var_feedback->rep() == MachineRepresentation::kTaggedSigned); - + TNode<Context> context, TNode<Object> value, Label* if_number, + TVariable<Word32T>* var_word32, Label* if_bigint, + TVariable<Object>* var_maybe_bigint, TVariable<Smi>* var_feedback) { // We might need to loop after conversion. - VARIABLE(var_value, MachineRepresentation::kTagged, value); + TVARIABLE(Object, var_value, value); OverwriteFeedback(var_feedback, BinaryOperationFeedback::kNone); Variable* loop_vars[] = {&var_value, var_feedback}; int num_vars = @@ -5592,12 +5459,13 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl( GotoIf(TaggedIsNotSmi(value), ¬_smi); // {value} is a Smi. - var_word32->Bind(SmiToInt32(value)); + *var_word32 = SmiToInt32(CAST(value)); CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall); Goto(if_number); BIND(¬_smi); - TNode<Map> map = LoadMap(value); + TNode<HeapObject> value_heap_object = CAST(value); + TNode<Map> map = LoadMap(value_heap_object); GotoIf(IsHeapNumberMap(map), &is_heap_number); TNode<Uint16T> instance_type = LoadMapInstanceType(map); if (conversion == Object::Conversion::kToNumeric) { @@ -5610,7 +5478,7 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl( // We do not require an Or with earlier feedback here because once we // convert the value to a Numeric, we cannot reach this path. We can // only reach this path on the first pass when the feedback is kNone. - CSA_ASSERT(this, SmiEqual(CAST(var_feedback->value()), + CSA_ASSERT(this, SmiEqual(var_feedback->value(), SmiConstant(BinaryOperationFeedback::kNone))); } GotoIf(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &is_oddball); @@ -5618,25 +5486,25 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl( auto builtin = conversion == Object::Conversion::kToNumeric ? Builtins::kNonNumberToNumeric : Builtins::kNonNumberToNumber; - var_value.Bind(CallBuiltin(builtin, context, value)); + var_value = CallBuiltin(builtin, context, value); OverwriteFeedback(var_feedback, BinaryOperationFeedback::kAny); Goto(&loop); BIND(&is_oddball); - var_value.Bind(LoadObjectField(value, Oddball::kToNumberOffset)); + var_value = LoadObjectField(value_heap_object, Oddball::kToNumberOffset); OverwriteFeedback(var_feedback, BinaryOperationFeedback::kNumberOrOddball); Goto(&loop); } BIND(&is_heap_number); - var_word32->Bind(TruncateHeapNumberValueToWord32(CAST(value))); + *var_word32 = TruncateHeapNumberValueToWord32(CAST(value)); CombineFeedback(var_feedback, BinaryOperationFeedback::kNumber); Goto(if_number); if (conversion == Object::Conversion::kToNumeric) { BIND(&is_bigint); - var_bigint->Bind(value); + *var_maybe_bigint = value; CombineFeedback(var_feedback, BinaryOperationFeedback::kBigInt); Goto(if_bigint); } @@ -5650,14 +5518,14 @@ TNode<Int32T> CodeStubAssembler::TruncateHeapNumberValueToWord32( } void CodeStubAssembler::TryHeapNumberToSmi(TNode<HeapNumber> number, - TVariable<Smi>& var_result_smi, + TVariable<Smi>* var_result_smi, Label* if_smi) { TNode<Float64T> value = LoadHeapNumberValue(number); TryFloat64ToSmi(value, var_result_smi, if_smi); } void CodeStubAssembler::TryFloat64ToSmi(TNode<Float64T> value, - TVariable<Smi>& var_result_smi, + TVariable<Smi>* var_result_smi, Label* if_smi) { TNode<Int32T> value32 = RoundFloat64ToInt32(value); TNode<Float64T> value64 = ChangeInt32ToFloat64(value32); @@ -5674,13 +5542,13 @@ void CodeStubAssembler::TryFloat64ToSmi(TNode<Float64T> value, BIND(&if_int32); { if (SmiValuesAre32Bits()) { - var_result_smi = SmiTag(ChangeInt32ToIntPtr(value32)); + *var_result_smi = SmiTag(ChangeInt32ToIntPtr(value32)); } else { DCHECK(SmiValuesAre31Bits()); TNode<PairT<Int32T, BoolT>> pair = Int32AddWithOverflow(value32, value32); TNode<BoolT> overflow = Projection<1>(pair); GotoIf(overflow, &if_heap_number); - var_result_smi = + *var_result_smi = BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Projection<0>(pair))); } Goto(if_smi); @@ -5693,7 +5561,7 @@ TNode<Number> CodeStubAssembler::ChangeFloat64ToTagged( Label if_smi(this), done(this); TVARIABLE(Smi, var_smi_result); TVARIABLE(Number, var_result); - TryFloat64ToSmi(value, var_smi_result, &if_smi); + TryFloat64ToSmi(value, &var_smi_result, &if_smi); var_result = AllocateHeapNumberWithValue(value); Goto(&done); @@ -6144,42 +6012,42 @@ TNode<BoolT> CodeStubAssembler::IsUndetectableMap(SloppyTNode<Map> map) { } TNode<BoolT> CodeStubAssembler::IsNoElementsProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = NoElementsProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsArrayIteratorProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = ArrayIteratorProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsPromiseResolveProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); - TNode<Cell> cell = PromiseResolveProtectorConstant(); - TNode<Object> cell_value = LoadObjectField(cell, Cell::kValueOffset); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); + TNode<PropertyCell> cell = PromiseResolveProtectorConstant(); + TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsPromiseThenProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = PromiseThenProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = ArraySpeciesProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = TypedArraySpeciesProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); @@ -6190,12 +6058,12 @@ TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid( TNode<PropertyCell> cell = CAST(LoadContextElement( native_context, Context::REGEXP_SPECIES_PROTECTOR_INDEX)); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); return TaggedEqual(cell_value, invalid); } TNode<BoolT> CodeStubAssembler::IsPromiseSpeciesProtectorCellInvalid() { - TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid); + TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid); TNode<PropertyCell> cell = PromiseSpeciesProtectorConstant(); TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); @@ -6394,6 +6262,10 @@ TNode<BoolT> CodeStubAssembler::IsJSGlobalProxy( return IsJSGlobalProxyMap(LoadMap(object)); } +TNode<BoolT> CodeStubAssembler::IsJSGeneratorMap(TNode<Map> map) { + return InstanceTypeEqual(LoadMapInstanceType(map), JS_GENERATOR_OBJECT_TYPE); +} + TNode<BoolT> CodeStubAssembler::IsJSObjectInstanceType( SloppyTNode<Int32T> instance_type) { STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); @@ -6428,6 +6300,11 @@ TNode<BoolT> CodeStubAssembler::IsJSStringIterator( return HasInstanceType(object, JS_STRING_ITERATOR_TYPE); } +TNode<BoolT> CodeStubAssembler::IsJSRegExpStringIterator( + SloppyTNode<HeapObject> object) { + return HasInstanceType(object, JS_REG_EXP_STRING_ITERATOR_TYPE); +} + TNode<BoolT> CodeStubAssembler::IsMap(SloppyTNode<HeapObject> map) { return IsMetaMap(LoadMap(map)); } @@ -6656,7 +6533,7 @@ TNode<BoolT> CodeStubAssembler::IsBigInt(SloppyTNode<HeapObject> object) { TNode<BoolT> CodeStubAssembler::IsPrimitiveInstanceType( SloppyTNode<Int32T> instance_type) { return Int32LessThanOrEqual(instance_type, - Int32Constant(LAST_PRIMITIVE_TYPE)); + Int32Constant(LAST_PRIMITIVE_HEAP_OBJECT_TYPE)); } TNode<BoolT> CodeStubAssembler::IsPrivateSymbol( @@ -6716,8 +6593,7 @@ TNode<BoolT> CodeStubAssembler::IsNumberDictionary( return HasInstanceType(object, NUMBER_DICTIONARY_TYPE); } -TNode<BoolT> CodeStubAssembler::IsJSGeneratorObject( - SloppyTNode<HeapObject> object) { +TNode<BoolT> CodeStubAssembler::IsJSGeneratorObject(TNode<HeapObject> object) { return HasInstanceType(object, JS_GENERATOR_OBJECT_TYPE); } @@ -6762,7 +6638,7 @@ TNode<BoolT> CodeStubAssembler::IsJSDataView(TNode<HeapObject> object) { } TNode<BoolT> CodeStubAssembler::IsJSRegExp(SloppyTNode<HeapObject> object) { - return HasInstanceType(object, JS_REGEXP_TYPE); + return HasInstanceType(object, JS_REG_EXP_TYPE); } TNode<BoolT> CodeStubAssembler::IsNumber(SloppyTNode<Object> object) { @@ -7011,189 +6887,6 @@ TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) { return CAST(var_result.value()); } -// A wrapper around CopyStringCharacters which determines the correct string -// encoding, allocates a corresponding sequential string, and then copies the -// given character range using CopyStringCharacters. -// |from_string| must be a sequential string. -// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. -TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters( - Node* from, Node* from_instance_type, TNode<IntPtrT> from_index, - TNode<IntPtrT> character_count) { - Label end(this), one_byte_sequential(this), two_byte_sequential(this); - TVARIABLE(String, var_result); - - Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential, - &two_byte_sequential); - - // The subject string is a sequential one-byte string. - BIND(&one_byte_sequential); - { - TNode<String> result = AllocateSeqOneByteString( - Unsigned(TruncateIntPtrToInt32(character_count))); - CopyStringCharacters(from, result, from_index, IntPtrConstant(0), - character_count, String::ONE_BYTE_ENCODING, - String::ONE_BYTE_ENCODING); - var_result = result; - Goto(&end); - } - - // The subject string is a sequential two-byte string. - BIND(&two_byte_sequential); - { - TNode<String> result = AllocateSeqTwoByteString( - Unsigned(TruncateIntPtrToInt32(character_count))); - CopyStringCharacters(from, result, from_index, IntPtrConstant(0), - character_count, String::TWO_BYTE_ENCODING, - String::TWO_BYTE_ENCODING); - var_result = result; - Goto(&end); - } - - BIND(&end); - return var_result.value(); -} - -TNode<String> CodeStubAssembler::SubString(TNode<String> string, - TNode<IntPtrT> from, - TNode<IntPtrT> to) { - TVARIABLE(String, var_result); - ToDirectStringAssembler to_direct(state(), string); - Label end(this), runtime(this); - - TNode<IntPtrT> const substr_length = IntPtrSub(to, from); - TNode<IntPtrT> const string_length = LoadStringLengthAsWord(string); - - // Begin dispatching based on substring length. - - Label original_string_or_invalid_length(this); - GotoIf(UintPtrGreaterThanOrEqual(substr_length, string_length), - &original_string_or_invalid_length); - - // A real substring (substr_length < string_length). - Label empty(this); - GotoIf(IntPtrEqual(substr_length, IntPtrConstant(0)), &empty); - - Label single_char(this); - GotoIf(IntPtrEqual(substr_length, IntPtrConstant(1)), &single_char); - - // Deal with different string types: update the index if necessary - // and extract the underlying string. - - TNode<String> direct_string = to_direct.TryToDirect(&runtime); - TNode<IntPtrT> offset = IntPtrAdd(from, to_direct.offset()); - TNode<Int32T> const instance_type = to_direct.instance_type(); - - // The subject string can only be external or sequential string of either - // encoding at this point. - Label external_string(this); - { - if (FLAG_string_slices) { - Label next(this); - - // Short slice. Copy instead of slicing. - GotoIf(IntPtrLessThan(substr_length, - IntPtrConstant(SlicedString::kMinLength)), - &next); - - // Allocate new sliced string. - - Counters* counters = isolate()->counters(); - IncrementCounter(counters->sub_string_native(), 1); - - Label one_byte_slice(this), two_byte_slice(this); - Branch(IsOneByteStringInstanceType(to_direct.instance_type()), - &one_byte_slice, &two_byte_slice); - - BIND(&one_byte_slice); - { - var_result = AllocateSlicedOneByteString( - Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string, - SmiTag(offset)); - Goto(&end); - } - - BIND(&two_byte_slice); - { - var_result = AllocateSlicedTwoByteString( - Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string, - SmiTag(offset)); - Goto(&end); - } - - BIND(&next); - } - - // The subject string can only be external or sequential string of either - // encoding at this point. - GotoIf(to_direct.is_external(), &external_string); - - var_result = AllocAndCopyStringCharacters(direct_string, instance_type, - offset, substr_length); - - Counters* counters = isolate()->counters(); - IncrementCounter(counters->sub_string_native(), 1); - - Goto(&end); - } - - // Handle external string. - BIND(&external_string); - { - TNode<RawPtrT> const fake_sequential_string = - to_direct.PointerToString(&runtime); - - var_result = AllocAndCopyStringCharacters( - fake_sequential_string, instance_type, offset, substr_length); - - Counters* counters = isolate()->counters(); - IncrementCounter(counters->sub_string_native(), 1); - - Goto(&end); - } - - BIND(&empty); - { - var_result = EmptyStringConstant(); - Goto(&end); - } - - // Substrings of length 1 are generated through CharCodeAt and FromCharCode. - BIND(&single_char); - { - TNode<Int32T> char_code = StringCharCodeAt(string, from); - var_result = StringFromSingleCharCode(char_code); - Goto(&end); - } - - BIND(&original_string_or_invalid_length); - { - CSA_ASSERT(this, IntPtrEqual(substr_length, string_length)); - - // Equal length - check if {from, to} == {0, str.length}. - GotoIf(UintPtrGreaterThan(from, IntPtrConstant(0)), &runtime); - - // Return the original string (substr_length == string_length). - - Counters* counters = isolate()->counters(); - IncrementCounter(counters->sub_string_native(), 1); - - var_result = string; - Goto(&end); - } - - // Fall back to a runtime call. - BIND(&runtime); - { - var_result = - CAST(CallRuntime(Runtime::kStringSubstring, NoContextConstant(), string, - SmiTag(from), SmiTag(to))); - Goto(&end); - } - - BIND(&end); - return var_result.value(); -} - ToDirectStringAssembler::ToDirectStringAssembler( compiler::CodeAssemblerState* state, TNode<String> string, Flags flags) : CodeStubAssembler(state), @@ -7204,8 +6897,7 @@ ToDirectStringAssembler::ToDirectStringAssembler( flags_(flags) {} TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) { - VariableList vars({&var_string_, &var_offset_, &var_instance_type_}, zone()); - Label dispatch(this, vars); + Label dispatch(this, {&var_string_, &var_offset_, &var_instance_type_}); Label if_iscons(this); Label if_isexternal(this); Label if_issliced(this); @@ -7333,232 +7025,6 @@ TNode<RawPtrT> ToDirectStringAssembler::TryToSequential( return var_result.value(); } -void CodeStubAssembler::BranchIfCanDerefIndirectString( - TNode<String> string, TNode<Int32T> instance_type, Label* can_deref, - Label* cannot_deref) { - TNode<Int32T> representation = - Word32And(instance_type, Int32Constant(kStringRepresentationMask)); - GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), can_deref); - GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), - cannot_deref); - // Cons string. - TNode<String> rhs = - LoadObjectField<String>(string, ConsString::kSecondOffset); - GotoIf(IsEmptyString(rhs), can_deref); - Goto(cannot_deref); -} - -TNode<String> CodeStubAssembler::DerefIndirectString( - TNode<String> string, TNode<Int32T> instance_type, Label* cannot_deref) { - Label deref(this); - BranchIfCanDerefIndirectString(string, instance_type, &deref, cannot_deref); - BIND(&deref); - STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) == - static_cast<int>(ConsString::kFirstOffset)); - return LoadObjectField<String>(string, ThinString::kActualOffset); -} - -void CodeStubAssembler::DerefIndirectString(TVariable<String>* var_string, - TNode<Int32T> instance_type) { -#ifdef DEBUG - Label can_deref(this), cannot_deref(this); - BranchIfCanDerefIndirectString(var_string->value(), instance_type, &can_deref, - &cannot_deref); - BIND(&cannot_deref); - DebugBreak(); // Should be able to dereference string. - Goto(&can_deref); - BIND(&can_deref); -#endif // DEBUG - - STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) == - static_cast<int>(ConsString::kFirstOffset)); - *var_string = - LoadObjectField<String>(var_string->value(), ThinString::kActualOffset); -} - -void CodeStubAssembler::MaybeDerefIndirectString(TVariable<String>* var_string, - TNode<Int32T> instance_type, - Label* did_deref, - Label* cannot_deref) { - Label deref(this); - BranchIfCanDerefIndirectString(var_string->value(), instance_type, &deref, - cannot_deref); - - BIND(&deref); - { - DerefIndirectString(var_string, instance_type); - Goto(did_deref); - } -} - -void CodeStubAssembler::MaybeDerefIndirectStrings( - TVariable<String>* var_left, TNode<Int32T> left_instance_type, - TVariable<String>* var_right, TNode<Int32T> right_instance_type, - Label* did_something) { - Label did_nothing_left(this), did_something_left(this), - didnt_do_anything(this); - MaybeDerefIndirectString(var_left, left_instance_type, &did_something_left, - &did_nothing_left); - - BIND(&did_something_left); - { - MaybeDerefIndirectString(var_right, right_instance_type, did_something, - did_something); - } - - BIND(&did_nothing_left); - { - MaybeDerefIndirectString(var_right, right_instance_type, did_something, - &didnt_do_anything); - } - - BIND(&didnt_do_anything); - // Fall through if neither string was an indirect string. -} - -TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left, - TNode<String> right) { - TVARIABLE(String, result); - Label check_right(this), runtime(this, Label::kDeferred), cons(this), - done(this, &result), done_native(this, &result); - Counters* counters = isolate()->counters(); - - TNode<Uint32T> left_length = LoadStringLengthAsWord32(left); - GotoIfNot(Word32Equal(left_length, Uint32Constant(0)), &check_right); - result = right; - Goto(&done_native); - - BIND(&check_right); - TNode<Uint32T> right_length = LoadStringLengthAsWord32(right); - GotoIfNot(Word32Equal(right_length, Uint32Constant(0)), &cons); - result = left; - Goto(&done_native); - - BIND(&cons); - { - TNode<Uint32T> new_length = Uint32Add(left_length, right_length); - - // If new length is greater than String::kMaxLength, goto runtime to - // throw. Note: we also need to invalidate the string length protector, so - // can't just throw here directly. - GotoIf(Uint32GreaterThan(new_length, Uint32Constant(String::kMaxLength)), - &runtime); - - TVARIABLE(String, var_left, left); - TVARIABLE(String, var_right, right); - Variable* input_vars[2] = {&var_left, &var_right}; - Label non_cons(this, 2, input_vars); - Label slow(this, Label::kDeferred); - GotoIf(Uint32LessThan(new_length, Uint32Constant(ConsString::kMinLength)), - &non_cons); - - result = - AllocateConsString(new_length, var_left.value(), var_right.value()); - Goto(&done_native); - - BIND(&non_cons); - - Comment("Full string concatenate"); - TNode<Int32T> left_instance_type = LoadInstanceType(var_left.value()); - TNode<Int32T> right_instance_type = LoadInstanceType(var_right.value()); - // Compute intersection and difference of instance types. - - TNode<Int32T> ored_instance_types = - Word32Or(left_instance_type, right_instance_type); - TNode<Word32T> xored_instance_types = - Word32Xor(left_instance_type, right_instance_type); - - // Check if both strings have the same encoding and both are sequential. - GotoIf(IsSetWord32(xored_instance_types, kStringEncodingMask), &runtime); - GotoIf(IsSetWord32(ored_instance_types, kStringRepresentationMask), &slow); - - TNode<IntPtrT> word_left_length = Signed(ChangeUint32ToWord(left_length)); - TNode<IntPtrT> word_right_length = Signed(ChangeUint32ToWord(right_length)); - - Label two_byte(this); - GotoIf(Word32Equal(Word32And(ored_instance_types, - Int32Constant(kStringEncodingMask)), - Int32Constant(kTwoByteStringTag)), - &two_byte); - // One-byte sequential string case - result = AllocateSeqOneByteString(new_length); - CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0), - IntPtrConstant(0), word_left_length, - String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING); - CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0), - word_left_length, word_right_length, - String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING); - Goto(&done_native); - - BIND(&two_byte); - { - // Two-byte sequential string case - result = AllocateSeqTwoByteString(new_length); - CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0), - IntPtrConstant(0), word_left_length, - String::TWO_BYTE_ENCODING, - String::TWO_BYTE_ENCODING); - CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0), - word_left_length, word_right_length, - String::TWO_BYTE_ENCODING, - String::TWO_BYTE_ENCODING); - Goto(&done_native); - } - - BIND(&slow); - { - // Try to unwrap indirect strings, restart the above attempt on success. - MaybeDerefIndirectStrings(&var_left, left_instance_type, &var_right, - right_instance_type, &non_cons); - Goto(&runtime); - } - } - BIND(&runtime); - { - result = CAST(CallRuntime(Runtime::kStringAdd, context, left, right)); - Goto(&done); - } - - BIND(&done_native); - { - IncrementCounter(counters->string_add_native(), 1); - Goto(&done); - } - - BIND(&done); - return result.value(); -} - -TNode<String> CodeStubAssembler::StringFromSingleUTF16EncodedCodePoint( - TNode<Int32T> codepoint) { - VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant()); - - Label if_isword16(this), if_isword32(this), return_result(this); - - Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16, - &if_isword32); - - BIND(&if_isword16); - { - var_result.Bind(StringFromSingleCharCode(codepoint)); - Goto(&return_result); - } - - BIND(&if_isword32); - { - TNode<String> value = AllocateSeqTwoByteString(2); - StoreNoWriteBarrier( - MachineRepresentation::kWord32, value, - IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), - codepoint); - var_result.Bind(value); - Goto(&return_result); - } - - BIND(&return_result); - return CAST(var_result.value()); -} - TNode<Number> CodeStubAssembler::StringToNumber(TNode<String> input) { Label runtime(this, Label::kDeferred); Label end(this); @@ -7585,22 +7051,22 @@ TNode<Number> CodeStubAssembler::StringToNumber(TNode<String> input) { return var_result.value(); } -TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) { +TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input, + Label* bailout) { TVARIABLE(String, result); TVARIABLE(Smi, smi_input); - Label runtime(this, Label::kDeferred), if_smi(this), if_heap_number(this), - done(this, &result); + Label if_smi(this), if_heap_number(this), done(this, &result); // Load the number string cache. TNode<FixedArray> number_string_cache = NumberStringCacheConstant(); // Make the hash mask from the length of the number string cache. It // contains two elements (number and string) for each cache entry. - // TODO(ishell): cleanup mask handling. - TNode<IntPtrT> mask = - BitcastTaggedSignedToWord(LoadFixedArrayBaseLength(number_string_cache)); - TNode<IntPtrT> one = IntPtrConstant(1); - mask = IntPtrSub(mask, one); + TNode<IntPtrT> number_string_cache_length = + LoadAndUntagFixedArrayBaseLength(number_string_cache); + TNode<Int32T> one = Int32Constant(1); + TNode<Word32T> mask = Int32Sub( + Word32Shr(TruncateWordToInt32(number_string_cache_length), one), one); GotoIfNot(TaggedIsSmi(input), &if_heap_number); smi_input = CAST(input); @@ -7611,36 +7077,35 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) { Comment("NumberToString - HeapNumber"); TNode<HeapNumber> heap_number_input = CAST(input); // Try normalizing the HeapNumber. - TryHeapNumberToSmi(heap_number_input, smi_input, &if_smi); + TryHeapNumberToSmi(heap_number_input, &smi_input, &if_smi); // Make a hash from the two 32-bit values of the double. TNode<Int32T> low = LoadObjectField<Int32T>(heap_number_input, HeapNumber::kValueOffset); TNode<Int32T> high = LoadObjectField<Int32T>( heap_number_input, HeapNumber::kValueOffset + kIntSize); - TNode<Word32T> hash = Word32Xor(low, high); - TNode<IntPtrT> word_hash = WordShl(ChangeInt32ToIntPtr(hash), one); - TNode<WordT> index = - WordAnd(word_hash, WordSar(mask, SmiShiftBitsConstant())); + TNode<Word32T> hash = Word32And(Word32Xor(low, high), mask); + TNode<IntPtrT> entry_index = + Signed(ChangeUint32ToWord(Int32Add(hash, hash))); // Cache entry's key must be a heap number TNode<Object> number_key = - UnsafeLoadFixedArrayElement(number_string_cache, index); - GotoIf(TaggedIsSmi(number_key), &runtime); + UnsafeLoadFixedArrayElement(number_string_cache, entry_index); + GotoIf(TaggedIsSmi(number_key), bailout); TNode<HeapObject> number_key_heap_object = CAST(number_key); - GotoIfNot(IsHeapNumber(number_key_heap_object), &runtime); + GotoIfNot(IsHeapNumber(number_key_heap_object), bailout); // Cache entry's key must match the heap number value we're looking for. TNode<Int32T> low_compare = LoadObjectField<Int32T>( number_key_heap_object, HeapNumber::kValueOffset); TNode<Int32T> high_compare = LoadObjectField<Int32T>( number_key_heap_object, HeapNumber::kValueOffset + kIntSize); - GotoIfNot(Word32Equal(low, low_compare), &runtime); - GotoIfNot(Word32Equal(high, high_compare), &runtime); + GotoIfNot(Word32Equal(low, low_compare), bailout); + GotoIfNot(Word32Equal(high, high_compare), bailout); // Heap number match, return value from cache entry. - result = CAST( - UnsafeLoadFixedArrayElement(number_string_cache, index, kTaggedSize)); + result = CAST(UnsafeLoadFixedArrayElement(number_string_cache, entry_index, + kTaggedSize)); Goto(&done); } @@ -7648,17 +7113,28 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) { { Comment("NumberToString - Smi"); // Load the smi key, make sure it matches the smi we're looking for. - TNode<Object> smi_index = BitcastWordToTagged(WordAnd( - WordShl(BitcastTaggedSignedToWord(smi_input.value()), one), mask)); + TNode<Word32T> hash = Word32And(SmiToInt32(smi_input.value()), mask); + TNode<IntPtrT> entry_index = + Signed(ChangeUint32ToWord(Int32Add(hash, hash))); TNode<Object> smi_key = UnsafeLoadFixedArrayElement( - number_string_cache, smi_index, 0, SMI_PARAMETERS); - GotoIf(TaggedNotEqual(smi_key, smi_input.value()), &runtime); + number_string_cache, entry_index, 0, INTPTR_PARAMETERS); + GotoIf(TaggedNotEqual(smi_key, smi_input.value()), bailout); // Smi match, return value from cache entry. - result = CAST(UnsafeLoadFixedArrayElement(number_string_cache, smi_index, - kTaggedSize, SMI_PARAMETERS)); + result = CAST(UnsafeLoadFixedArrayElement(number_string_cache, entry_index, + kTaggedSize, INTPTR_PARAMETERS)); Goto(&done); } + BIND(&done); + return result.value(); +} + +TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) { + TVARIABLE(String, result); + Label runtime(this, Label::kDeferred), done(this, &result); + + result = NumberToString(input, &runtime); + Goto(&done); BIND(&runtime); { @@ -8290,102 +7766,129 @@ void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) { } } -void CodeStubAssembler::Increment(Variable* variable, int value, - ParameterMode mode) { - DCHECK_IMPLIES(mode == INTPTR_PARAMETERS, - variable->rep() == MachineType::PointerRepresentation()); - DCHECK_IMPLIES(mode == SMI_PARAMETERS, CanBeTaggedSigned(variable->rep())); - variable->Bind(IntPtrOrSmiAdd(variable->value(), - IntPtrOrSmiConstant(value, mode), mode)); +template <typename TIndex> +void CodeStubAssembler::Increment(TVariable<TIndex>* variable, int value) { + *variable = + IntPtrOrSmiAdd(variable->value(), IntPtrOrSmiConstant<TIndex>(value)); } +// Instantiate Increment for Smi and IntPtrT. +// TODO(v8:9708): Consider renaming to [Smi|IntPtrT|RawPtrT]Increment. +template void CodeStubAssembler::Increment<Smi>(TVariable<Smi>* variable, + int value); +template void CodeStubAssembler::Increment<IntPtrT>( + TVariable<IntPtrT>* variable, int value); +template void CodeStubAssembler::Increment<RawPtrT>( + TVariable<RawPtrT>* variable, int value); + void CodeStubAssembler::Use(Label* label) { GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); } -void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, - Variable* var_index, Label* if_keyisunique, - Variable* var_unique, Label* if_bailout, +void CodeStubAssembler::TryToName(SloppyTNode<Object> key, Label* if_keyisindex, + TVariable<IntPtrT>* var_index, + Label* if_keyisunique, + TVariable<Name>* var_unique, + Label* if_bailout, Label* if_notinternalized) { - DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); - DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep()); Comment("TryToName"); - Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this), - if_keyisother(this, Label::kDeferred); + Label if_keyisnotindex(this); // Handle Smi and HeapNumber keys. - var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); + *var_index = TryToIntptr(key, &if_keyisnotindex); Goto(if_keyisindex); BIND(&if_keyisnotindex); - TNode<Map> key_map = LoadMap(key); - var_unique->Bind(key); - // Symbols are unique. - GotoIf(IsSymbolMap(key_map), if_keyisunique); - TNode<Uint16T> key_instance_type = LoadMapInstanceType(key_map); - // Miss if |key| is not a String. - STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); - GotoIfNot(IsStringInstanceType(key_instance_type), &if_keyisother); - - // |key| is a String. Check if it has a cached array index. - TNode<Uint32T> hash = LoadNameHashField(key); - GotoIf(IsClearWord32(hash, Name::kDoesNotContainCachedArrayIndexMask), - &if_hascachedindex); - // No cached array index. If the string knows that it contains an index, - // then it must be an uncacheable index. Handle this case in the runtime. - GotoIf(IsClearWord32(hash, Name::kIsNotArrayIndexMask), if_bailout); - // Check if we have a ThinString. - GotoIf(InstanceTypeEqual(key_instance_type, THIN_STRING_TYPE), - &if_thinstring); - GotoIf(InstanceTypeEqual(key_instance_type, THIN_ONE_BYTE_STRING_TYPE), - &if_thinstring); - // Finally, check if |key| is internalized. - STATIC_ASSERT(kNotInternalizedTag != 0); - GotoIf(IsSetWord32(key_instance_type, kIsNotInternalizedMask), - if_notinternalized != nullptr ? if_notinternalized : if_bailout); - Goto(if_keyisunique); + { + Label if_symbol(this), if_string(this), + if_keyisother(this, Label::kDeferred); + TNode<HeapObject> key_heap_object = CAST(key); + TNode<Map> key_map = LoadMap(key_heap_object); - BIND(&if_thinstring); - var_unique->Bind( - LoadObjectField<String>(CAST(key), ThinString::kActualOffset)); - Goto(if_keyisunique); + GotoIf(IsSymbolMap(key_map), &if_symbol); - BIND(&if_hascachedindex); - var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); - Goto(if_keyisindex); + // Miss if |key| is not a String. + STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); + TNode<Uint16T> key_instance_type = LoadMapInstanceType(key_map); + Branch(IsStringInstanceType(key_instance_type), &if_string, &if_keyisother); + + // Symbols are unique. + BIND(&if_symbol); + { + *var_unique = CAST(key); + Goto(if_keyisunique); + } - BIND(&if_keyisother); - GotoIfNot(InstanceTypeEqual(key_instance_type, ODDBALL_TYPE), if_bailout); - var_unique->Bind(LoadObjectField(key, Oddball::kToStringOffset)); - Goto(if_keyisunique); + BIND(&if_string); + { + Label if_hascachedindex(this), if_thinstring(this); + + // |key| is a String. Check if it has a cached array index. + TNode<String> key_string = CAST(key); + TNode<Uint32T> hash = LoadNameHashField(key_string); + GotoIf(IsClearWord32(hash, Name::kDoesNotContainCachedArrayIndexMask), + &if_hascachedindex); + // No cached array index. If the string knows that it contains an index, + // then it must be an uncacheable index. Handle this case in the runtime. + GotoIf(IsClearWord32(hash, Name::kIsNotArrayIndexMask), if_bailout); + // Check if we have a ThinString. + GotoIf(InstanceTypeEqual(key_instance_type, THIN_STRING_TYPE), + &if_thinstring); + GotoIf(InstanceTypeEqual(key_instance_type, THIN_ONE_BYTE_STRING_TYPE), + &if_thinstring); + // Finally, check if |key| is internalized. + STATIC_ASSERT(kNotInternalizedTag != 0); + GotoIf(IsSetWord32(key_instance_type, kIsNotInternalizedMask), + if_notinternalized != nullptr ? if_notinternalized : if_bailout); + + *var_unique = key_string; + Goto(if_keyisunique); + + BIND(&if_thinstring); + *var_unique = + LoadObjectField<String>(key_string, ThinString::kActualOffset); + Goto(if_keyisunique); + + BIND(&if_hascachedindex); + *var_index = + Signed(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); + Goto(if_keyisindex); + } + + BIND(&if_keyisother); + { + GotoIfNot(InstanceTypeEqual(key_instance_type, ODDBALL_TYPE), if_bailout); + *var_unique = + LoadObjectField<String>(key_heap_object, Oddball::kToStringOffset); + Goto(if_keyisunique); + } + } } void CodeStubAssembler::TryInternalizeString( - Node* string, Label* if_index, Variable* var_index, Label* if_internalized, - Variable* var_internalized, Label* if_not_internalized, Label* if_bailout) { - DCHECK(var_index->rep() == MachineType::PointerRepresentation()); - DCHECK_EQ(var_internalized->rep(), MachineRepresentation::kTagged); - CSA_SLOW_ASSERT(this, IsString(string)); + SloppyTNode<String> string, Label* if_index, TVariable<IntPtrT>* var_index, + Label* if_internalized, TVariable<Name>* var_internalized, + Label* if_not_internalized, Label* if_bailout) { TNode<ExternalReference> function = ExternalConstant(ExternalReference::try_internalize_string_function()); TNode<ExternalReference> const isolate_ptr = ExternalConstant(ExternalReference::isolate_address(isolate())); - Node* result = - CallCFunction(function, MachineType::AnyTagged(), - std::make_pair(MachineType::Pointer(), isolate_ptr), - std::make_pair(MachineType::AnyTagged(), string)); + TNode<Object> result = + CAST(CallCFunction(function, MachineType::AnyTagged(), + std::make_pair(MachineType::Pointer(), isolate_ptr), + std::make_pair(MachineType::AnyTagged(), string))); Label internalized(this); GotoIf(TaggedIsNotSmi(result), &internalized); - TNode<IntPtrT> word_result = SmiUntag(result); + TNode<IntPtrT> word_result = SmiUntag(CAST(result)); GotoIf(IntPtrEqual(word_result, IntPtrConstant(ResultSentinel::kNotFound)), if_not_internalized); GotoIf(IntPtrEqual(word_result, IntPtrConstant(ResultSentinel::kUnsupported)), if_bailout); - var_index->Bind(word_result); + *var_index = word_result; Goto(if_index); BIND(&internalized); - var_internalized->Bind(result); + *var_internalized = CAST(result); Goto(if_internalized); } @@ -8712,31 +8215,6 @@ TNode<Object> CodeStubAssembler::BasicLoadNumberDictionaryElement( return LoadValueByKeyIndex<NumberDictionary>(dictionary, index); } -void CodeStubAssembler::BasicStoreNumberDictionaryElement( - TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index, - TNode<Object> value, Label* not_data, Label* if_hole, Label* read_only) { - TVARIABLE(IntPtrT, var_entry); - Label if_found(this); - NumberDictionaryLookup(dictionary, intptr_index, &if_found, &var_entry, - if_hole); - BIND(&if_found); - - // Check that the value is a data property. - TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(var_entry.value()); - TNode<Uint32T> details = - LoadDetailsByKeyIndex<NumberDictionary>(dictionary, index); - TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details); - // TODO(jkummerow): Support accessors without missing? - GotoIfNot(Word32Equal(kind, Int32Constant(kData)), not_data); - - // Check that the property is writeable. - GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), - read_only); - - // Finally, store the value. - StoreValueByKeyIndex<NumberDictionary>(dictionary, index, value); -} - template <class Dictionary> void CodeStubAssembler::FindInsertionEntry(TNode<Dictionary> dictionary, TNode<Name> key, @@ -8858,16 +8336,16 @@ void CodeStubAssembler::LookupLinear(TNode<Name> unique_name, first_inclusive, IntPtrMul(ChangeInt32ToIntPtr(number_of_valid_entries), factor)); - BuildFastLoop( + BuildFastLoop<IntPtrT>( last_exclusive, first_inclusive, - [=](SloppyTNode<IntPtrT> name_index) { + [=](TNode<IntPtrT> name_index) { TNode<MaybeObject> element = LoadArrayElement(array, Array::kHeaderSize, name_index); TNode<Name> candidate_name = CAST(element); *var_name_index = name_index; GotoIf(TaggedEqual(candidate_name, unique_name), if_found); }, - -Array::kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPre); + -Array::kEntrySize, IndexAdvanceMode::kPre); Goto(if_not_found); } @@ -9029,7 +8507,7 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty( TNode<Uint16T> type = LoadMapInstanceType(map); TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout); - TNode<DescriptorArray> descriptors = LoadMapDescriptors(map); + TVARIABLE(DescriptorArray, var_descriptors, LoadMapDescriptors(map)); TNode<Uint32T> nof_descriptors = DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3); @@ -9044,25 +8522,23 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty( // Note: var_end_key_index is exclusive for the loop TVARIABLE(IntPtrT, var_end_key_index, ToKeyIndex<DescriptorArray>(nof_descriptors)); - VariableList list( - {&var_stable, &var_has_symbol, &var_is_symbol_processing_loop, - &var_start_key_index, &var_end_key_index}, - zone()); + VariableList list({&var_descriptors, &var_stable, &var_has_symbol, + &var_is_symbol_processing_loop, &var_start_key_index, + &var_end_key_index}, + zone()); Label descriptor_array_loop( - this, {&var_stable, &var_has_symbol, &var_is_symbol_processing_loop, - &var_start_key_index, &var_end_key_index}); + this, {&var_descriptors, &var_stable, &var_has_symbol, + &var_is_symbol_processing_loop, &var_start_key_index, + &var_end_key_index}); Goto(&descriptor_array_loop); BIND(&descriptor_array_loop); - BuildFastLoop( + BuildFastLoop<IntPtrT>( list, var_start_key_index.value(), var_end_key_index.value(), - [=, &var_stable, &var_has_symbol, &var_is_symbol_processing_loop, - &var_start_key_index, &var_end_key_index](Node* index) { - TNode<IntPtrT> descriptor_key_index = - TNode<IntPtrT>::UncheckedCast(index); + [&](TNode<IntPtrT> descriptor_key_index) { TNode<Name> next_key = - LoadKeyByKeyIndex(descriptors, descriptor_key_index); + LoadKeyByKeyIndex(var_descriptors.value(), descriptor_key_index); TVARIABLE(Object, var_value, SmiConstant(0)); Label callback(this), next_iteration(this); @@ -9117,7 +8593,7 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty( // Directly decode from the descriptor array if |object| did not // change shape. var_map = map; - var_meta_storage = descriptors; + var_meta_storage = var_descriptors.value(); var_entry = Signed(descriptor_key_index); Goto(&if_found_fast); } @@ -9183,19 +8659,21 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty( BIND(&callback); body(next_key, var_value.value()); - // Check if |object| is still stable, i.e. we can proceed using - // property details from preloaded |descriptors|. - var_stable = Select<BoolT>( - var_stable.value(), - [=] { return TaggedEqual(LoadMap(object), map); }, - [=] { return Int32FalseConstant(); }); + // Check if |object| is still stable, i.e. the descriptors in the + // preloaded |descriptors| are still the same modulo in-place + // representation changes. + GotoIfNot(var_stable.value(), &next_iteration); + var_stable = TaggedEqual(LoadMap(object), map); + // Reload the descriptors just in case the actual array changed, and + // any of the field representations changed in-place. + var_descriptors = LoadMapDescriptors(map); Goto(&next_iteration); } } BIND(&next_iteration); }, - DescriptorArray::kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); + DescriptorArray::kEntrySize, IndexAdvanceMode::kPost); if (mode == kEnumerationOrder) { Label done(this); @@ -9205,14 +8683,73 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty( var_is_symbol_processing_loop = Int32TrueConstant(); // Add DescriptorArray::kEntrySize to make the var_end_key_index exclusive // as BuildFastLoop() expects. - Increment(&var_end_key_index, DescriptorArray::kEntrySize, - INTPTR_PARAMETERS); + Increment(&var_end_key_index, DescriptorArray::kEntrySize); Goto(&descriptor_array_loop); BIND(&done); } } +TNode<Object> CodeStubAssembler::GetConstructor(TNode<Map> map) { + TVARIABLE(HeapObject, var_maybe_constructor); + var_maybe_constructor = map; + Label loop(this, &var_maybe_constructor), done(this); + GotoIfNot(IsMap(var_maybe_constructor.value()), &done); + Goto(&loop); + + BIND(&loop); + { + var_maybe_constructor = CAST(LoadObjectField( + var_maybe_constructor.value(), Map::kConstructorOrBackPointerOffset)); + GotoIf(IsMap(var_maybe_constructor.value()), &loop); + Goto(&done); + } + + BIND(&done); + return var_maybe_constructor.value(); +} + +TNode<NativeContext> CodeStubAssembler::GetCreationContext( + TNode<JSReceiver> receiver, Label* if_bailout) { + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Object> constructor = GetConstructor(receiver_map); + + TVARIABLE(JSFunction, var_function); + + Label done(this), if_jsfunction(this), if_jsgenerator(this); + GotoIf(TaggedIsSmi(constructor), if_bailout); + + TNode<Map> function_map = LoadMap(CAST(constructor)); + GotoIf(IsJSFunctionMap(function_map), &if_jsfunction); + GotoIf(IsJSGeneratorMap(function_map), &if_jsgenerator); + // Remote objects don't have a creation context. + GotoIf(IsFunctionTemplateInfoMap(function_map), if_bailout); + + CSA_ASSERT(this, IsJSFunctionMap(receiver_map)); + var_function = CAST(receiver); + Goto(&done); + + BIND(&if_jsfunction); + { + var_function = CAST(constructor); + Goto(&done); + } + + BIND(&if_jsgenerator); + { + var_function = LoadJSGeneratorObjectFunction(CAST(receiver)); + Goto(&done); + } + + BIND(&done); + TNode<Context> context = LoadJSFunctionContext(var_function.value()); + + GotoIfNot(IsContext(context), if_bailout); + + TNode<NativeContext> native_context = LoadNativeContext(context); + return native_context; +} + void CodeStubAssembler::DescriptorLookup( SloppyTNode<Name> unique_name, SloppyTNode<DescriptorArray> descriptors, SloppyTNode<Uint32T> bitfield3, Label* if_found, @@ -9302,7 +8839,7 @@ void CodeStubAssembler::TryLookupPropertyInSimpleObject( } void CodeStubAssembler::TryLookupProperty( - SloppyTNode<JSObject> object, SloppyTNode<Map> map, + SloppyTNode<JSReceiver> object, SloppyTNode<Map> map, SloppyTNode<Int32T> instance_type, SloppyTNode<Name> unique_name, Label* if_found_fast, Label* if_found_dict, Label* if_found_global, TVariable<HeapObject>* var_meta_storage, TVariable<IntPtrT>* var_name_index, @@ -9310,7 +8847,7 @@ void CodeStubAssembler::TryLookupProperty( Label if_objectisspecial(this); GotoIf(IsSpecialReceiverInstanceType(instance_type), &if_objectisspecial); - TryLookupPropertyInSimpleObject(object, map, unique_name, if_found_fast, + TryLookupPropertyInSimpleObject(CAST(object), map, unique_name, if_found_fast, if_found_dict, var_meta_storage, var_name_index, if_not_found); @@ -9547,25 +9084,44 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor( // AccessorPair case. { if (mode == kCallJSGetter) { + Label if_callable(this), if_function_template_info(this); Node* accessor_pair = value; TNode<HeapObject> getter = CAST(LoadObjectField(accessor_pair, AccessorPair::kGetterOffset)); TNode<Map> getter_map = LoadMap(getter); - TNode<Uint16T> instance_type = LoadMapInstanceType(getter_map); - // FunctionTemplateInfo getters are not supported yet. - GotoIf(InstanceTypeEqual(instance_type, FUNCTION_TEMPLATE_INFO_TYPE), - if_bailout); + + GotoIf(IsCallableMap(getter_map), &if_callable); + GotoIf(IsFunctionTemplateInfoMap(getter_map), &if_function_template_info); // Return undefined if the {getter} is not callable. var_value.Bind(UndefinedConstant()); - GotoIfNot(IsCallableMap(getter_map), &done); + Goto(&done); + + BIND(&if_callable); + { + // Call the accessor. + Callable callable = CodeFactory::Call(isolate()); + Node* result = CallJS(callable, context, getter, receiver); + var_value.Bind(result); + Goto(&done); + } - // Call the accessor. - Callable callable = CodeFactory::Call(isolate()); - Node* result = CallJS(callable, context, getter, receiver); - var_value.Bind(result); + BIND(&if_function_template_info); + { + TNode<HeapObject> cached_property_name = LoadObjectField<HeapObject>( + getter, FunctionTemplateInfo::kCachedPropertyNameOffset); + GotoIfNot(IsTheHole(cached_property_name), if_bailout); + + TNode<NativeContext> creation_context = + GetCreationContext(CAST(receiver), if_bailout); + var_value.Bind(CallBuiltin( + Builtins::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver, + creation_context, getter, IntPtrConstant(0), receiver)); + Goto(&done); + } + } else { + Goto(&done); } - Goto(&done); } // AccessorInfo case. @@ -9617,10 +9173,11 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor( GotoIfNot(IsLengthString( LoadObjectField(accessor_info, AccessorInfo::kNameOffset)), if_bailout); - Node* receiver_value = LoadJSPrimitiveWrapperValue(receiver); + TNode<Object> receiver_value = + LoadJSPrimitiveWrapperValue(CAST(receiver)); GotoIfNot(TaggedIsNotSmi(receiver_value), if_bailout); - GotoIfNot(IsString(receiver_value), if_bailout); - var_value.Bind(LoadStringLengthAsSmi(receiver_value)); + GotoIfNot(IsString(CAST(receiver_value)), if_bailout); + var_value.Bind(LoadStringLengthAsSmi(CAST(receiver_value))); Goto(&done); } } @@ -9808,18 +9365,14 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, } BIND(&if_isfaststringwrapper); { - CSA_ASSERT(this, HasInstanceType(object, JS_PRIMITIVE_WRAPPER_TYPE)); - Node* string = LoadJSPrimitiveWrapperValue(object); - CSA_ASSERT(this, IsString(string)); + TNode<String> string = CAST(LoadJSPrimitiveWrapperValue(CAST(object))); TNode<IntPtrT> length = LoadStringLengthAsWord(string); GotoIf(UintPtrLessThan(intptr_index, length), if_found); Goto(&if_isobjectorsmi); } BIND(&if_isslowstringwrapper); { - CSA_ASSERT(this, HasInstanceType(object, JS_PRIMITIVE_WRAPPER_TYPE)); - Node* string = LoadJSPrimitiveWrapperValue(object); - CSA_ASSERT(this, IsString(string)); + TNode<String> string = CAST(LoadJSPrimitiveWrapperValue(CAST(object))); TNode<IntPtrT> length = LoadStringLengthAsWord(string); GotoIf(UintPtrLessThan(intptr_index, length), if_found); Goto(&if_isdictionary); @@ -9892,8 +9445,8 @@ void CodeStubAssembler::TryPrototypeChainLookup( GotoIf(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), if_proxy); } - VARIABLE(var_index, MachineType::PointerRepresentation()); - VARIABLE(var_unique, MachineRepresentation::kTagged); + TVARIABLE(IntPtrT, var_index); + TVARIABLE(Name, var_unique); Label if_keyisindex(this), if_iskeyunique(this); TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, @@ -9905,9 +9458,7 @@ void CodeStubAssembler::TryPrototypeChainLookup( TVARIABLE(Map, var_holder_map, map); TVARIABLE(Int32T, var_holder_instance_type, instance_type); - VariableList merged_variables( - {&var_holder, &var_holder_map, &var_holder_instance_type}, zone()); - Label loop(this, merged_variables); + Label loop(this, {&var_holder, &var_holder_map, &var_holder_instance_type}); Goto(&loop); BIND(&loop); { @@ -9950,9 +9501,7 @@ void CodeStubAssembler::TryPrototypeChainLookup( TVARIABLE(Map, var_holder_map, map); TVARIABLE(Int32T, var_holder_instance_type, instance_type); - VariableList merged_variables( - {&var_holder, &var_holder_map, &var_holder_instance_type}, zone()); - Label loop(this, merged_variables); + Label loop(this, {&var_holder, &var_holder_map, &var_holder_instance_type}); Goto(&loop); BIND(&loop); { @@ -9978,22 +9527,22 @@ void CodeStubAssembler::TryPrototypeChainLookup( } } -Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object, - SloppyTNode<Object> prototype) { - CSA_ASSERT(this, TaggedIsNotSmi(object)); - VARIABLE(var_result, MachineRepresentation::kTagged); +TNode<Oddball> CodeStubAssembler::HasInPrototypeChain(TNode<Context> context, + TNode<HeapObject> object, + TNode<Object> prototype) { + TVARIABLE(Oddball, var_result); Label return_false(this), return_true(this), return_runtime(this, Label::kDeferred), return_result(this); // Loop through the prototype chain looking for the {prototype}. - VARIABLE(var_object_map, MachineRepresentation::kTagged, LoadMap(object)); + TVARIABLE(Map, var_object_map, LoadMap(object)); Label loop(this, &var_object_map); Goto(&loop); BIND(&loop); { // Check if we can determine the prototype directly from the {object_map}. Label if_objectisdirect(this), if_objectisspecial(this, Label::kDeferred); - Node* object_map = var_object_map.value(); + TNode<Map> object_map = var_object_map.value(); TNode<Uint16T> object_instance_type = LoadMapInstanceType(object_map); Branch(IsSpecialReceiverInstanceType(object_instance_type), &if_objectisspecial, &if_objectisdirect); @@ -10018,22 +9567,22 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object, // Continue with the prototype. CSA_ASSERT(this, TaggedIsNotSmi(object_prototype)); - var_object_map.Bind(LoadMap(object_prototype)); + var_object_map = LoadMap(object_prototype); Goto(&loop); } BIND(&return_true); - var_result.Bind(TrueConstant()); + var_result = TrueConstant(); Goto(&return_result); BIND(&return_false); - var_result.Bind(FalseConstant()); + var_result = FalseConstant(); Goto(&return_result); BIND(&return_runtime); { // Fallback to the runtime implementation. - var_result.Bind( + var_result = CAST( CallRuntime(Runtime::kHasInPrototypeChain, context, object, prototype)); } Goto(&return_result); @@ -10042,63 +9591,67 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object, return var_result.value(); } -Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, - Node* object) { - VARIABLE(var_result, MachineRepresentation::kTagged); +TNode<Oddball> CodeStubAssembler::OrdinaryHasInstance( + TNode<Context> context, TNode<Object> callable_maybe_smi, + TNode<Object> object_maybe_smi) { + TVARIABLE(Oddball, var_result); Label return_runtime(this, Label::kDeferred), return_result(this); GotoIfForceSlowPath(&return_runtime); // Goto runtime if {object} is a Smi. - GotoIf(TaggedIsSmi(object), &return_runtime); + GotoIf(TaggedIsSmi(object_maybe_smi), &return_runtime); // Goto runtime if {callable} is a Smi. - GotoIf(TaggedIsSmi(callable), &return_runtime); - - // Load map of {callable}. - TNode<Map> callable_map = LoadMap(callable); - - // Goto runtime if {callable} is not a JSFunction. - TNode<Uint16T> callable_instance_type = LoadMapInstanceType(callable_map); - GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE), - &return_runtime); + GotoIf(TaggedIsSmi(callable_maybe_smi), &return_runtime); - GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), callable_map, - &return_runtime); - - // Get the "prototype" (or initial map) of the {callable}. - TNode<HeapObject> callable_prototype = LoadObjectField<HeapObject>( - CAST(callable), JSFunction::kPrototypeOrInitialMapOffset); { - Label no_initial_map(this), walk_prototype_chain(this); - TVARIABLE(HeapObject, var_callable_prototype, callable_prototype); + // Load map of {callable}. + TNode<HeapObject> object = CAST(object_maybe_smi); + TNode<HeapObject> callable = CAST(callable_maybe_smi); + TNode<Map> callable_map = LoadMap(callable); - // Resolve the "prototype" if the {callable} has an initial map. - GotoIfNot(IsMap(callable_prototype), &no_initial_map); - var_callable_prototype = - LoadObjectField<HeapObject>(callable_prototype, Map::kPrototypeOffset); - Goto(&walk_prototype_chain); + // Goto runtime if {callable} is not a JSFunction. + TNode<Uint16T> callable_instance_type = LoadMapInstanceType(callable_map); + GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE), + &return_runtime); - BIND(&no_initial_map); - // {callable_prototype} is the hole if the "prototype" property hasn't been - // requested so far. - Branch(TaggedEqual(callable_prototype, TheHoleConstant()), &return_runtime, - &walk_prototype_chain); + GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), callable_map, + &return_runtime); - BIND(&walk_prototype_chain); - callable_prototype = var_callable_prototype.value(); - } + // Get the "prototype" (or initial map) of the {callable}. + TNode<HeapObject> callable_prototype = LoadObjectField<HeapObject>( + callable, JSFunction::kPrototypeOrInitialMapOffset); + { + Label no_initial_map(this), walk_prototype_chain(this); + TVARIABLE(HeapObject, var_callable_prototype, callable_prototype); + + // Resolve the "prototype" if the {callable} has an initial map. + GotoIfNot(IsMap(callable_prototype), &no_initial_map); + var_callable_prototype = LoadObjectField<HeapObject>( + callable_prototype, Map::kPrototypeOffset); + Goto(&walk_prototype_chain); + + BIND(&no_initial_map); + // {callable_prototype} is the hole if the "prototype" property hasn't + // been requested so far. + Branch(TaggedEqual(callable_prototype, TheHoleConstant()), + &return_runtime, &walk_prototype_chain); + + BIND(&walk_prototype_chain); + callable_prototype = var_callable_prototype.value(); + } - // Loop through the prototype chain looking for the {callable} prototype. - CSA_ASSERT(this, IsJSReceiver(callable_prototype)); - var_result.Bind(HasInPrototypeChain(context, object, callable_prototype)); - Goto(&return_result); + // Loop through the prototype chain looking for the {callable} prototype. + var_result = HasInPrototypeChain(context, object, callable_prototype); + Goto(&return_result); + } BIND(&return_runtime); { // Fallback to the runtime implementation. - var_result.Bind( - CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object)); + var_result = CAST(CallRuntime(Runtime::kOrdinaryHasInstance, context, + callable_maybe_smi, object_maybe_smi)); } Goto(&return_result); @@ -10111,34 +9664,72 @@ TNode<IntPtrT> CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, ParameterMode mode, int base_size) { CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, mode)); + if (mode == SMI_PARAMETERS) { + return ElementOffsetFromIndex(ReinterpretCast<Smi>(index_node), kind, + base_size); + } else { + DCHECK(mode == INTPTR_PARAMETERS); + return ElementOffsetFromIndex(ReinterpretCast<IntPtrT>(index_node), kind, + base_size); + } +} + +template <typename TIndex> +TNode<IntPtrT> CodeStubAssembler::ElementOffsetFromIndex( + TNode<TIndex> index_node, ElementsKind kind, int base_size) { + // TODO(v8:9708): Remove IntPtrT variant in favor of UintPtrT. + static_assert(std::is_same<TIndex, Smi>::value || + std::is_same<TIndex, IntPtrT>::value || + std::is_same<TIndex, UintPtrT>::value, + "Only Smi, UintPtrT or IntPtrT index nodes are allowed"); int element_size_shift = ElementsKindToShiftSize(kind); int element_size = 1 << element_size_shift; int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; intptr_t index = 0; + TNode<IntPtrT> intptr_index_node; bool constant_index = false; - if (mode == SMI_PARAMETERS) { + if (std::is_same<TIndex, Smi>::value) { + TNode<Smi> smi_index_node = ReinterpretCast<Smi>(index_node); element_size_shift -= kSmiShiftBits; Smi smi_index; - constant_index = ToSmiConstant(index_node, &smi_index); - if (constant_index) index = smi_index.value(); - index_node = BitcastTaggedSignedToWord(index_node); + constant_index = ToSmiConstant(smi_index_node, &smi_index); + if (constant_index) { + index = smi_index.value(); + } else { + if (COMPRESS_POINTERS_BOOL) { + smi_index_node = NormalizeSmiIndex(smi_index_node); + } + } + intptr_index_node = BitcastTaggedToWordForTagAndSmiBits(smi_index_node); } else { - DCHECK(mode == INTPTR_PARAMETERS); - constant_index = ToIntPtrConstant(index_node, &index); + intptr_index_node = ReinterpretCast<IntPtrT>(index_node); + constant_index = ToIntPtrConstant(intptr_index_node, &index); } if (constant_index) { return IntPtrConstant(base_size + element_size * index); } - TNode<WordT> shifted_index = + TNode<IntPtrT> shifted_index = (element_size_shift == 0) - ? UncheckedCast<WordT>(index_node) + ? intptr_index_node : ((element_size_shift > 0) - ? WordShl(index_node, IntPtrConstant(element_size_shift)) - : WordSar(index_node, IntPtrConstant(-element_size_shift))); + ? WordShl(intptr_index_node, + IntPtrConstant(element_size_shift)) + : WordSar(intptr_index_node, + IntPtrConstant(-element_size_shift))); return IntPtrAdd(IntPtrConstant(base_size), Signed(shifted_index)); } +// Instantiate ElementOffsetFromIndex for Smi and IntPtrT. +template V8_EXPORT_PRIVATE TNode<IntPtrT> +CodeStubAssembler::ElementOffsetFromIndex<Smi>(TNode<Smi> index_node, + ElementsKind kind, + int base_size); +template V8_EXPORT_PRIVATE TNode<IntPtrT> +CodeStubAssembler::ElementOffsetFromIndex<IntPtrT>(TNode<IntPtrT> index_node, + ElementsKind kind, + int base_size); + TNode<BoolT> CodeStubAssembler::IsOffsetInBounds(SloppyTNode<IntPtrT> offset, SloppyTNode<IntPtrT> length, int header_size, @@ -10146,8 +9737,7 @@ TNode<BoolT> CodeStubAssembler::IsOffsetInBounds(SloppyTNode<IntPtrT> offset, // Make sure we point to the last field. int element_size = 1 << ElementsKindToShiftSize(kind); int correction = header_size - kHeapObjectTag - element_size; - TNode<IntPtrT> last_offset = - ElementOffsetFromIndex(length, kind, INTPTR_PARAMETERS, correction); + TNode<IntPtrT> last_offset = ElementOffsetFromIndex(length, kind, correction); return IntPtrLessThanOrEqual(offset, last_offset); } @@ -10203,8 +9793,9 @@ TNode<FeedbackVector> CodeStubAssembler::LoadFeedbackVectorForStub() { return CAST(LoadFeedbackVector(function)); } -void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector, - Node* slot_id) { +void CodeStubAssembler::UpdateFeedback(TNode<Smi> feedback, + TNode<HeapObject> maybe_vector, + TNode<UintPtrT> slot_id) { Label end(this); // If feedback_vector is not valid, then nothing to do. GotoIf(IsUndefined(maybe_vector), &end); @@ -10216,7 +9807,7 @@ void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector, TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(feedback_vector, slot_id); TNode<Smi> previous_feedback = CAST(feedback_element); - TNode<Smi> combined_feedback = SmiOr(previous_feedback, CAST(feedback)); + TNode<Smi> combined_feedback = SmiOr(previous_feedback, feedback); GotoIf(SmiEqual(previous_feedback, combined_feedback), &end); { @@ -10230,7 +9821,7 @@ void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector, } void CodeStubAssembler::ReportFeedbackUpdate( - SloppyTNode<FeedbackVector> feedback_vector, SloppyTNode<IntPtrT> slot_id, + TNode<FeedbackVector> feedback_vector, SloppyTNode<UintPtrT> slot_id, const char* reason) { // Reset profiler ticks. StoreObjectFieldNoWriteBarrier( @@ -10241,7 +9832,7 @@ void CodeStubAssembler::ReportFeedbackUpdate( // Trace the update. CallRuntime(Runtime::kInterpreterTraceUpdateFeedback, NoContextConstant(), LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset), - SmiTag(slot_id), StringConstant(reason)); + SmiTag(Signed(slot_id)), StringConstant(reason)); #endif // V8_TRACE_FEEDBACK_UPDATES } @@ -10285,14 +9876,16 @@ TNode<Map> CodeStubAssembler::LoadReceiverMap(SloppyTNode<Object> receiver) { [=] { return LoadMap(UncheckedCast<HeapObject>(receiver)); }); } -TNode<IntPtrT> CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { +TNode<IntPtrT> CodeStubAssembler::TryToIntptr(SloppyTNode<Object> key, + Label* miss) { TVARIABLE(IntPtrT, var_intptr_key); Label done(this, &var_intptr_key), key_is_smi(this); GotoIf(TaggedIsSmi(key), &key_is_smi); + // Try to convert a heap number to a Smi. - GotoIfNot(IsHeapNumber(key), miss); + GotoIfNot(IsHeapNumber(CAST(key)), miss); { - TNode<Float64T> value = LoadHeapNumberValue(key); + TNode<Float64T> value = LoadHeapNumberValue(CAST(key)); TNode<Int32T> int_value = RoundFloat64ToInt32(value); GotoIfNot(Float64Equal(value, ChangeInt32ToFloat64(int_value)), miss); var_intptr_key = ChangeInt32ToIntPtr(int_value); @@ -10301,7 +9894,7 @@ TNode<IntPtrT> CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { BIND(&key_is_smi); { - var_intptr_key = SmiUntag(key); + var_intptr_key = SmiUntag(CAST(key)); Goto(&done); } @@ -10354,7 +9947,7 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments( } Label if_mapped(this), if_unmapped(this), end(this, &var_result); TNode<IntPtrT> intptr_two = IntPtrConstant(2); - TNode<WordT> adjusted_length = IntPtrSub(elements_length, intptr_two); + TNode<IntPtrT> adjusted_length = IntPtrSub(elements_length, intptr_two); GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped); @@ -10510,33 +10103,35 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, } } -Node* CodeStubAssembler::Int32ToUint8Clamped(Node* int32_value) { +TNode<Uint8T> CodeStubAssembler::Int32ToUint8Clamped( + TNode<Int32T> int32_value) { Label done(this); TNode<Int32T> int32_zero = Int32Constant(0); TNode<Int32T> int32_255 = Int32Constant(255); - VARIABLE(var_value, MachineRepresentation::kWord32, int32_value); + TVARIABLE(Word32T, var_value, int32_value); GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); - var_value.Bind(int32_zero); + var_value = int32_zero; GotoIf(Int32LessThan(int32_value, int32_zero), &done); - var_value.Bind(int32_255); + var_value = int32_255; Goto(&done); BIND(&done); - return var_value.value(); + return UncheckedCast<Uint8T>(var_value.value()); } -Node* CodeStubAssembler::Float64ToUint8Clamped(Node* float64_value) { +TNode<Uint8T> CodeStubAssembler::Float64ToUint8Clamped( + TNode<Float64T> float64_value) { Label done(this); - VARIABLE(var_value, MachineRepresentation::kWord32, Int32Constant(0)); + TVARIABLE(Word32T, var_value, Int32Constant(0)); GotoIf(Float64LessThanOrEqual(float64_value, Float64Constant(0.0)), &done); - var_value.Bind(Int32Constant(255)); + var_value = Int32Constant(255); GotoIf(Float64LessThanOrEqual(Float64Constant(255.0), float64_value), &done); { TNode<Float64T> rounded_value = Float64RoundToEven(float64_value); - var_value.Bind(TruncateFloat64ToWord32(rounded_value)); + var_value = TruncateFloat64ToWord32(rounded_value); Goto(&done); } BIND(&done); - return var_value.value(); + return UncheckedCast<Uint8T>(var_value.value()); } Node* CodeStubAssembler::PrepareValueForWriteToTypedArray( @@ -10716,8 +10311,8 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, GotoIfNot(UintPtrLessThan(intptr_key, length), &update_value_and_bailout); } - TNode<RawPtrT> backing_store = LoadJSTypedArrayBackingStore(CAST(object)); - StoreElement(backing_store, elements_kind, intptr_key, converted_value, + TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object)); + StoreElement(data_ptr, elements_kind, intptr_key, converted_value, parameter_mode); Goto(&done); @@ -10807,7 +10402,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, if (IsSmiElementsKind(elements_kind)) { GotoIfNot(TaggedIsSmi(value), bailout); } else if (IsDoubleElementsKind(elements_kind)) { - value = TryTaggedToFloat64(value, bailout); + value = TryTaggedToFloat64(CAST(value), bailout); } if (IsGrowStoreMode(store_mode) && @@ -11047,7 +10642,7 @@ TNode<IntPtrT> CodeStubAssembler::PageFromAddress(TNode<IntPtrT> address) { } TNode<AllocationSite> CodeStubAssembler::CreateAllocationSiteInFeedbackVector( - SloppyTNode<FeedbackVector> feedback_vector, TNode<Smi> slot) { + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot) { TNode<IntPtrT> size = IntPtrConstant(AllocationSite::kSizeWithWeakNext); TNode<HeapObject> site = Allocate(size, CodeStubAssembler::kPretenured); StoreMapNoWriteBarrier(site, RootIndex::kAllocationSiteWithWeakNextMap); @@ -11090,19 +10685,16 @@ TNode<AllocationSite> CodeStubAssembler::CreateAllocationSiteInFeedbackVector( StoreObjectField(site, AllocationSite::kWeakNextOffset, next_site); StoreFullTaggedNoWriteBarrier(site_list, site); - StoreFeedbackVectorSlot(feedback_vector, slot, site, UPDATE_WRITE_BARRIER, 0, - SMI_PARAMETERS); + StoreFeedbackVectorSlot(feedback_vector, slot, site); return CAST(site); } TNode<MaybeObject> CodeStubAssembler::StoreWeakReferenceInFeedbackVector( - SloppyTNode<FeedbackVector> feedback_vector, Node* slot, - SloppyTNode<HeapObject> value, int additional_offset, - ParameterMode parameter_mode) { + TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot, + TNode<HeapObject> value, int additional_offset) { TNode<MaybeObject> weak_value = MakeWeak(value); StoreFeedbackVectorSlot(feedback_vector, slot, weak_value, - UPDATE_WRITE_BARRIER, additional_offset, - parameter_mode); + UPDATE_WRITE_BARRIER, additional_offset); return weak_value; } @@ -11135,14 +10727,14 @@ TNode<Int32T> CodeStubAssembler::LoadElementsKind( return elements_kind; } -Node* CodeStubAssembler::BuildFastLoop( - const CodeStubAssembler::VariableList& vars, Node* start_index, - Node* end_index, const FastLoopBody& body, int increment, - ParameterMode parameter_mode, IndexAdvanceMode advance_mode) { - CSA_SLOW_ASSERT(this, MatchesParameterMode(start_index, parameter_mode)); - CSA_SLOW_ASSERT(this, MatchesParameterMode(end_index, parameter_mode)); - MachineRepresentation index_rep = ParameterRepresentation(parameter_mode); - VARIABLE(var, index_rep, start_index); +template <typename TIndex> +TNode<TIndex> CodeStubAssembler::BuildFastLoop(const VariableList& vars, + TNode<TIndex> start_index, + TNode<TIndex> end_index, + const FastLoopBody<TIndex>& body, + int increment, + IndexAdvanceMode advance_mode) { + TVARIABLE(TIndex, var, start_index); VariableList vars_copy(vars.begin(), vars.end(), zone()); vars_copy.push_back(&var); Label loop(this, vars_copy); @@ -11154,8 +10746,7 @@ Node* CodeStubAssembler::BuildFastLoop( // to force the loop header check at the end of the loop and branch forward to // it from the pre-header). The extra branch is slower in the case that the // loop actually iterates. - TNode<BoolT> first_check = - IntPtrOrSmiEqual(var.value(), end_index, parameter_mode); + TNode<BoolT> first_check = IntPtrOrSmiEqual(var.value(), end_index); int32_t first_check_val; if (ToInt32Constant(first_check, &first_check_val)) { if (first_check_val) return var.value(); @@ -11167,19 +10758,28 @@ Node* CodeStubAssembler::BuildFastLoop( BIND(&loop); { if (advance_mode == IndexAdvanceMode::kPre) { - Increment(&var, increment, parameter_mode); + Increment(&var, increment); } body(var.value()); if (advance_mode == IndexAdvanceMode::kPost) { - Increment(&var, increment, parameter_mode); + Increment(&var, increment); } - Branch(IntPtrOrSmiNotEqual(var.value(), end_index, parameter_mode), &loop, - &after_loop); + Branch(IntPtrOrSmiNotEqual(var.value(), end_index), &loop, &after_loop); } BIND(&after_loop); return var.value(); } +// Instantiate BuildFastLoop for Smi and IntPtrT. +template TNode<Smi> CodeStubAssembler::BuildFastLoop<Smi>( + const VariableList& vars, TNode<Smi> start_index, TNode<Smi> end_index, + const FastLoopBody<Smi>& body, int increment, + IndexAdvanceMode advance_mode); +template TNode<IntPtrT> CodeStubAssembler::BuildFastLoop<IntPtrT>( + const VariableList& vars, TNode<IntPtrT> start_index, + TNode<IntPtrT> end_index, const FastLoopBody<IntPtrT>& body, int increment, + IndexAdvanceMode advance_mode); + void CodeStubAssembler::BuildFastFixedArrayForEach( const CodeStubAssembler::VariableList& vars, Node* fixed_array, ElementsKind kind, Node* first_element_inclusive, @@ -11201,17 +10801,15 @@ void CodeStubAssembler::BuildFastFixedArrayForEach( if (direction == ForEachDirection::kForward) { for (int i = first_val; i < last_val; ++i) { TNode<IntPtrT> index = IntPtrConstant(i); - TNode<IntPtrT> offset = - ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS, - FixedArray::kHeaderSize - kHeapObjectTag); + TNode<IntPtrT> offset = ElementOffsetFromIndex( + index, kind, FixedArray::kHeaderSize - kHeapObjectTag); body(fixed_array, offset); } } else { for (int i = last_val - 1; i >= first_val; --i) { TNode<IntPtrT> index = IntPtrConstant(i); - TNode<IntPtrT> offset = - ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS, - FixedArray::kHeaderSize - kHeapObjectTag); + TNode<IntPtrT> offset = ElementOffsetFromIndex( + index, kind, FixedArray::kHeaderSize - kHeapObjectTag); body(fixed_array, offset); } } @@ -11228,11 +10826,10 @@ void CodeStubAssembler::BuildFastFixedArrayForEach( if (direction == ForEachDirection::kReverse) std::swap(start, limit); int increment = IsDoubleElementsKind(kind) ? kDoubleSize : kTaggedSize; - BuildFastLoop( + BuildFastLoop<IntPtrT>( vars, start, limit, - [fixed_array, &body](Node* offset) { body(fixed_array, offset); }, + [&](TNode<IntPtrT> offset) { body(fixed_array, offset); }, direction == ForEachDirection::kReverse ? -increment : increment, - INTPTR_PARAMETERS, direction == ForEachDirection::kReverse ? IndexAdvanceMode::kPre : IndexAdvanceMode::kPost); } @@ -11243,22 +10840,21 @@ void CodeStubAssembler::GotoIfFixedArraySizeDoesntFitInNewSpace( doesnt_fit); } -void CodeStubAssembler::InitializeFieldsWithRoot(Node* object, - Node* start_offset, - Node* end_offset, +void CodeStubAssembler::InitializeFieldsWithRoot(TNode<HeapObject> object, + TNode<IntPtrT> start_offset, + TNode<IntPtrT> end_offset, RootIndex root_index) { CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); start_offset = IntPtrAdd(start_offset, IntPtrConstant(-kHeapObjectTag)); end_offset = IntPtrAdd(end_offset, IntPtrConstant(-kHeapObjectTag)); TNode<Object> root_value = LoadRoot(root_index); - BuildFastLoop( + BuildFastLoop<IntPtrT>( end_offset, start_offset, - [this, object, root_value](Node* current) { + [=](TNode<IntPtrT> current) { StoreNoWriteBarrier(MachineRepresentation::kTagged, object, current, root_value); }, - -kTaggedSize, INTPTR_PARAMETERS, - CodeStubAssembler::IndexAdvanceMode::kPre); + -kTaggedSize, CodeStubAssembler::IndexAdvanceMode::kPre); } void CodeStubAssembler::BranchIfNumberRelationalComparison( @@ -11384,11 +10980,9 @@ Operation Reverse(Operation op) { } } // anonymous namespace -Node* CodeStubAssembler::RelationalComparison(Operation op, - SloppyTNode<Object> left, - SloppyTNode<Object> right, - SloppyTNode<Context> context, - Variable* var_type_feedback) { +TNode<Oddball> CodeStubAssembler::RelationalComparison( + Operation op, TNode<Object> left, TNode<Object> right, + TNode<Context> context, TVariable<Smi>* var_type_feedback) { Label return_true(this), return_false(this), do_float_comparison(this), end(this); TVARIABLE(Oddball, var_result); // Actually only "true" or "false". @@ -11403,7 +10997,7 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, if (var_type_feedback != nullptr) { // Initialize the type feedback to None. The current feedback is combined // with the previous feedback. - var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kNone); loop_variable_list.push_back(var_type_feedback); } Label loop(this, loop_variable_list); @@ -11914,17 +11508,17 @@ void CodeStubAssembler::GenerateEqual_Same(SloppyTNode<Object> value, } // ES6 section 7.2.12 Abstract Equality Comparison -Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, - SloppyTNode<Object> right, - SloppyTNode<Context> context, - Variable* var_type_feedback) { +TNode<Oddball> CodeStubAssembler::Equal(SloppyTNode<Object> left, + SloppyTNode<Object> right, + SloppyTNode<Context> context, + TVariable<Smi>* var_type_feedback) { // This is a slightly optimized version of Object::Equals. Whenever you // change something functionality wise in here, remember to update the // Object::Equals method as well. Label if_equal(this), if_notequal(this), do_float_comparison(this), do_right_stringtonumber(this, Label::kDeferred), end(this); - VARIABLE(result, MachineRepresentation::kTagged); + TVARIABLE(Oddball, result); TVARIABLE(Float64T, var_left_float); TVARIABLE(Float64T, var_right_float); @@ -11984,7 +11578,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber); // {left} is Smi and {right} is not HeapNumber or Smi. if (var_type_feedback != nullptr) { - var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } GotoIf(IsBooleanMap(right_map), &if_right_boolean); TNode<Uint16T> right_type = LoadMapInstanceType(right_map); @@ -12009,8 +11603,8 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, BIND(&if_right_bigint); { - result.Bind(CallRuntime(Runtime::kBigIntEqualToNumber, - NoContextConstant(), right, left)); + result = CAST(CallRuntime(Runtime::kBigIntEqualToNumber, + NoContextConstant(), right, left)); Goto(&end); } @@ -12046,7 +11640,8 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, BIND(&if_left_string); { GotoIfNot(IsStringInstanceType(right_type), &use_symmetry); - result.Bind(CallBuiltin(Builtins::kStringEqual, context, left, right)); + result = + CAST(CallBuiltin(Builtins::kStringEqual, context, left, right)); CombineFeedback(var_type_feedback, SmiOr(CollectFeedbackForString(left_type), CollectFeedbackForString(right_type))); @@ -12067,8 +11662,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, { Label if_right_boolean(this); if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } GotoIf(IsStringInstanceType(right_type), &do_right_stringtonumber); GotoIf(IsBooleanMap(right_map), &if_right_boolean); @@ -12098,38 +11692,35 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, BIND(&if_right_heapnumber); { if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } - result.Bind(CallRuntime(Runtime::kBigIntEqualToNumber, - NoContextConstant(), left, right)); + result = CAST(CallRuntime(Runtime::kBigIntEqualToNumber, + NoContextConstant(), left, right)); Goto(&end); } BIND(&if_right_bigint); { CombineFeedback(var_type_feedback, CompareOperationFeedback::kBigInt); - result.Bind(CallRuntime(Runtime::kBigIntEqualToBigInt, - NoContextConstant(), left, right)); + result = CAST(CallRuntime(Runtime::kBigIntEqualToBigInt, + NoContextConstant(), left, right)); Goto(&end); } BIND(&if_right_string); { if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } - result.Bind(CallRuntime(Runtime::kBigIntEqualToString, - NoContextConstant(), left, right)); + result = CAST(CallRuntime(Runtime::kBigIntEqualToString, + NoContextConstant(), left, right)); Goto(&end); } BIND(&if_right_boolean); { if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } var_right = LoadObjectField(CAST(right), Oddball::kToNumberOffset); Goto(&loop); @@ -12154,8 +11745,8 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, if (var_type_feedback != nullptr) { // If {right} is undetectable, it must be either also // Null or Undefined, or a Receiver (aka document.all). - var_type_feedback->Bind(SmiConstant( - CompareOperationFeedback::kReceiverOrNullOrUndefined)); + *var_type_feedback = SmiConstant( + CompareOperationFeedback::kReceiverOrNullOrUndefined); } Goto(&if_equal); } @@ -12164,12 +11755,11 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, { if (var_type_feedback != nullptr) { // Track whether {right} is Null, Undefined or Receiver. - var_type_feedback->Bind(SmiConstant( - CompareOperationFeedback::kReceiverOrNullOrUndefined)); + *var_type_feedback = SmiConstant( + CompareOperationFeedback::kReceiverOrNullOrUndefined); GotoIf(IsJSReceiverInstanceType(right_type), &if_notequal); GotoIfNot(IsBooleanMap(right_map), &if_notequal); - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } Goto(&if_notequal); } @@ -12178,8 +11768,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, BIND(&if_left_boolean); { if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } // If {right} is a Boolean too, it must be a different Boolean. @@ -12200,7 +11789,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, if (var_type_feedback != nullptr) { Label if_right_symbol(this); GotoIf(IsSymbolInstanceType(right_type), &if_right_symbol); - var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); Goto(&if_notequal); BIND(&if_right_symbol); @@ -12218,8 +11807,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, // {left} is a Primitive and {right} is a JSReceiver, so swapping // the order is not observable. if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } Goto(&use_symmetry); } @@ -12254,8 +11842,8 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, // When we get here, {right} must be either Null or Undefined. CSA_ASSERT(this, IsNullOrUndefined(right)); if (var_type_feedback != nullptr) { - var_type_feedback->Bind(SmiConstant( - CompareOperationFeedback::kReceiverOrNullOrUndefined)); + *var_type_feedback = SmiConstant( + CompareOperationFeedback::kReceiverOrNullOrUndefined); } Branch(IsUndetectableMap(left_map), &if_equal, &if_notequal); } @@ -12265,8 +11853,7 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, // {right} is a Primitive, and neither Null or Undefined; // convert {left} to Primitive too. if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); + *var_type_feedback = SmiConstant(CompareOperationFeedback::kAny); } Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate()); var_left = CallStub(callable, context, left); @@ -12298,13 +11885,13 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, BIND(&if_equal); { - result.Bind(TrueConstant()); + result = TrueConstant(); Goto(&end); } BIND(&if_notequal); { - result.Bind(FalseConstant()); + result = FalseConstant(); Goto(&end); } @@ -12312,9 +11899,9 @@ Node* CodeStubAssembler::Equal(SloppyTNode<Object> left, return result.value(); } -TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs, - SloppyTNode<Object> rhs, - Variable* var_type_feedback) { +TNode<Oddball> CodeStubAssembler::StrictEqual( + SloppyTNode<Object> lhs, SloppyTNode<Object> rhs, + TVariable<Smi>* var_type_feedback) { // Pseudo-code for the algorithm below: // // if (lhs == rhs) { @@ -12482,7 +12069,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs, CollectFeedbackForString(lhs_instance_type); TNode<Smi> rhs_feedback = CollectFeedbackForString(rhs_instance_type); - var_type_feedback->Bind(SmiOr(lhs_feedback, rhs_feedback)); + *var_type_feedback = SmiOr(lhs_feedback, rhs_feedback); } result = CAST(CallBuiltin(Builtins::kStringEqual, NoContextConstant(), lhs, rhs)); @@ -12556,7 +12143,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs, BIND(&if_lhsisoddball); { - STATIC_ASSERT(LAST_PRIMITIVE_TYPE == ODDBALL_TYPE); + STATIC_ASSERT(LAST_PRIMITIVE_HEAP_OBJECT_TYPE == ODDBALL_TYPE); GotoIf(IsBooleanMap(rhs_map), &if_not_equivalent_types); GotoIf(Int32LessThan(rhs_instance_type, Int32Constant(ODDBALL_TYPE)), @@ -12855,8 +12442,8 @@ TNode<Oddball> CodeStubAssembler::HasProperty(SloppyTNode<Context> context, return result.value(); } -Node* CodeStubAssembler::Typeof(Node* value) { - VARIABLE(result_var, MachineRepresentation::kTagged); +TNode<String> CodeStubAssembler::Typeof(SloppyTNode<Object> value) { + TVARIABLE(String, result_var); Label return_number(this, Label::kDeferred), if_oddball(this), return_function(this), return_undefined(this), return_object(this), @@ -12864,7 +12451,8 @@ Node* CodeStubAssembler::Typeof(Node* value) { GotoIf(TaggedIsSmi(value), &return_number); - TNode<Map> map = LoadMap(value); + TNode<HeapObject> value_heap_object = CAST(value); + TNode<Map> map = LoadMap(value_heap_object); GotoIf(IsHeapNumberMap(map), &return_number); @@ -12890,49 +12478,50 @@ Node* CodeStubAssembler::Typeof(Node* value) { GotoIf(IsBigIntInstanceType(instance_type), &return_bigint); CSA_ASSERT(this, InstanceTypeEqual(instance_type, SYMBOL_TYPE)); - result_var.Bind(HeapConstant(isolate()->factory()->symbol_string())); + result_var = HeapConstant(isolate()->factory()->symbol_string()); Goto(&return_result); BIND(&return_number); { - result_var.Bind(HeapConstant(isolate()->factory()->number_string())); + result_var = HeapConstant(isolate()->factory()->number_string()); Goto(&return_result); } BIND(&if_oddball); { - TNode<Object> type = LoadObjectField(value, Oddball::kTypeOfOffset); - result_var.Bind(type); + TNode<String> type = + CAST(LoadObjectField(value_heap_object, Oddball::kTypeOfOffset)); + result_var = type; Goto(&return_result); } BIND(&return_function); { - result_var.Bind(HeapConstant(isolate()->factory()->function_string())); + result_var = HeapConstant(isolate()->factory()->function_string()); Goto(&return_result); } BIND(&return_undefined); { - result_var.Bind(HeapConstant(isolate()->factory()->undefined_string())); + result_var = HeapConstant(isolate()->factory()->undefined_string()); Goto(&return_result); } BIND(&return_object); { - result_var.Bind(HeapConstant(isolate()->factory()->object_string())); + result_var = HeapConstant(isolate()->factory()->object_string()); Goto(&return_result); } BIND(&return_string); { - result_var.Bind(HeapConstant(isolate()->factory()->string_string())); + result_var = HeapConstant(isolate()->factory()->string_string()); Goto(&return_result); } BIND(&return_bigint); { - result_var.Bind(HeapConstant(isolate()->factory()->bigint_string())); + result_var = HeapConstant(isolate()->factory()->bigint_string()); Goto(&return_result); } @@ -12941,7 +12530,7 @@ Node* CodeStubAssembler::Typeof(Node* value) { } TNode<Object> CodeStubAssembler::GetSuperConstructor( - SloppyTNode<Context> context, SloppyTNode<JSFunction> active_function) { + TNode<Context> context, TNode<JSFunction> active_function) { Label is_not_constructor(this, Label::kDeferred), out(this); TVARIABLE(Object, result); @@ -13004,9 +12593,10 @@ TNode<JSReceiver> CodeStubAssembler::SpeciesConstructor( return var_result.value(); } -Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, - Node* context) { - VARIABLE(var_result, MachineRepresentation::kTagged); +TNode<Oddball> CodeStubAssembler::InstanceOf(TNode<Object> object, + TNode<Object> callable, + TNode<Context> context) { + TVARIABLE(Oddball, var_result); Label if_notcallable(this, Label::kDeferred), if_notreceiver(this, Label::kDeferred), if_otherhandler(this), if_nohandler(this, Label::kDeferred), return_true(this), @@ -13014,7 +12604,7 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, // Ensure that the {callable} is actually a JSReceiver. GotoIf(TaggedIsSmi(callable), &if_notreceiver); - GotoIfNot(IsJSReceiver(callable), &if_notreceiver); + GotoIfNot(IsJSReceiver(CAST(callable)), &if_notreceiver); // Load the @@hasInstance property from {callable}. TNode<Object> inst_of_handler = @@ -13032,8 +12622,8 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, // Call to Function.prototype[@@hasInstance] directly. Callable builtin(BUILTIN_CODE(isolate(), FunctionPrototypeHasInstance), CallTrampolineDescriptor{}); - Node* result = CallJS(builtin, context, inst_of_handler, callable, object); - var_result.Bind(result); + var_result = + CAST(CallJS(builtin, context, inst_of_handler, callable, object)); Goto(&return_result); } @@ -13055,12 +12645,11 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, BIND(&if_nohandler); { // Ensure that the {callable} is actually Callable. - GotoIfNot(IsCallable(callable), &if_notcallable); + GotoIfNot(IsCallable(CAST(callable)), &if_notcallable); // Use the OrdinaryHasInstance algorithm. - TNode<Object> result = - CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable, object); - var_result.Bind(result); + var_result = CAST( + CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable, object)); Goto(&return_result); } @@ -13071,11 +12660,11 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, { ThrowTypeError(context, MessageTemplate::kNonObjectInInstanceOfCheck); } BIND(&return_true); - var_result.Bind(TrueConstant()); + var_result = TrueConstant(); Goto(&return_result); BIND(&return_false); - var_result.Bind(FalseConstant()); + var_result = FalseConstant(); Goto(&return_result); BIND(&return_result); @@ -13294,9 +12883,8 @@ TNode<JSObject> CodeStubAssembler::AllocateJSIteratorResult( return CAST(result); } -Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context, - Node* key, - Node* value) { +TNode<JSObject> CodeStubAssembler::AllocateJSIteratorResultForEntry( + TNode<Context> context, TNode<Object> key, SloppyTNode<Object> value) { TNode<NativeContext> native_context = LoadNativeContext(context); TNode<Smi> length = SmiConstant(2); int const elements_size = FixedArray::SizeFor(2); @@ -13326,7 +12914,7 @@ Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context, StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, array); StoreObjectFieldRoot(result, JSIteratorResult::kDoneOffset, RootIndex::kFalseValue); - return result; + return CAST(result); } TNode<JSReceiver> CodeStubAssembler::ArraySpeciesCreate(TNode<Context> context, @@ -13393,21 +12981,19 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSTypedArrayLength( return LoadObjectField<UintPtrT>(typed_array, JSTypedArray::kLengthOffset); } -CodeStubArguments::CodeStubArguments( - CodeStubAssembler* assembler, Node* argc, Node* fp, - CodeStubAssembler::ParameterMode param_mode, ReceiverMode receiver_mode) +CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler, + TNode<IntPtrT> argc, TNode<RawPtrT> fp, + ReceiverMode receiver_mode) : assembler_(assembler), - argc_mode_(param_mode), receiver_mode_(receiver_mode), argc_(argc), base_(), fp_(fp != nullptr ? fp : assembler_->LoadFramePointer()) { TNode<IntPtrT> offset = assembler_->ElementOffsetFromIndex( - argc_, SYSTEM_POINTER_ELEMENTS, param_mode, + argc_, SYSTEM_POINTER_ELEMENTS, (StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kSystemPointerSize); - base_ = - assembler_->UncheckedCast<RawPtrT>(assembler_->IntPtrAdd(fp_, offset)); + base_ = assembler_->RawPtrAdd(fp_, offset); } TNode<Object> CodeStubArguments::GetReceiver() const { @@ -13422,24 +13008,18 @@ void CodeStubArguments::SetReceiver(TNode<Object> object) const { base_, assembler_->IntPtrConstant(kSystemPointerSize), object); } -TNode<WordT> CodeStubArguments::AtIndexPtr( - Node* index, CodeStubAssembler::ParameterMode mode) const { - using Node = compiler::Node; - Node* negated_index = assembler_->IntPtrOrSmiSub( - assembler_->IntPtrOrSmiConstant(0, mode), index, mode); +TNode<RawPtrT> CodeStubArguments::AtIndexPtr(TNode<IntPtrT> index) const { + TNode<IntPtrT> negated_index = + assembler_->IntPtrOrSmiSub(assembler_->IntPtrConstant(0), index); TNode<IntPtrT> offset = assembler_->ElementOffsetFromIndex( - negated_index, SYSTEM_POINTER_ELEMENTS, mode, 0); - return assembler_->IntPtrAdd(assembler_->UncheckedCast<IntPtrT>(base_), - offset); + negated_index, SYSTEM_POINTER_ELEMENTS, 0); + return assembler_->RawPtrAdd(base_, offset); } -TNode<Object> CodeStubArguments::AtIndex( - Node* index, CodeStubAssembler::ParameterMode mode) const { - DCHECK_EQ(argc_mode_, mode); - CSA_ASSERT(assembler_, - assembler_->UintPtrOrSmiLessThan(index, GetLength(mode), mode)); +TNode<Object> CodeStubArguments::AtIndex(TNode<IntPtrT> index) const { + CSA_ASSERT(assembler_, assembler_->UintPtrOrSmiLessThan(index, GetLength())); return assembler_->UncheckedCast<Object>( - assembler_->LoadFullTagged(AtIndexPtr(index, mode))); + assembler_->LoadFullTagged(AtIndexPtr(index))); } TNode<Object> CodeStubArguments::AtIndex(int index) const { @@ -13452,9 +13032,8 @@ TNode<Object> CodeStubArguments::GetOptionalArgumentValue( CodeStubAssembler::Label argument_missing(assembler_), argument_done(assembler_, &result); - assembler_->GotoIf(assembler_->UintPtrOrSmiGreaterThanOrEqual( - assembler_->IntPtrOrSmiConstant(index, argc_mode_), - argc_, argc_mode_), + assembler_->GotoIf(assembler_->UintPtrGreaterThanOrEqual( + assembler_->IntPtrConstant(index), argc_), &argument_missing); result = AtIndex(index); assembler_->Goto(&argument_done); @@ -13473,10 +13052,8 @@ TNode<Object> CodeStubArguments::GetOptionalArgumentValue( CodeStubAssembler::Label argument_missing(assembler_), argument_done(assembler_, &result); - assembler_->GotoIf( - assembler_->UintPtrOrSmiGreaterThanOrEqual( - assembler_->IntPtrToParameter(index, argc_mode_), argc_, argc_mode_), - &argument_missing); + assembler_->GotoIf(assembler_->UintPtrGreaterThanOrEqual(index, argc_), + &argument_missing); result = AtIndex(index); assembler_->Goto(&argument_done); @@ -13490,43 +13067,38 @@ TNode<Object> CodeStubArguments::GetOptionalArgumentValue( void CodeStubArguments::ForEach( const CodeStubAssembler::VariableList& vars, - const CodeStubArguments::ForEachBodyFunction& body, Node* first, Node* last, - CodeStubAssembler::ParameterMode mode) { + const CodeStubArguments::ForEachBodyFunction& body, TNode<IntPtrT> first, + TNode<IntPtrT> last) const { assembler_->Comment("CodeStubArguments::ForEach"); if (first == nullptr) { - first = assembler_->IntPtrOrSmiConstant(0, mode); + first = assembler_->IntPtrConstant(0); } if (last == nullptr) { - DCHECK_EQ(mode, argc_mode_); last = argc_; } - TNode<IntPtrT> start = assembler_->IntPtrSub( - assembler_->UncheckedCast<IntPtrT>(base_), - assembler_->ElementOffsetFromIndex(first, SYSTEM_POINTER_ELEMENTS, mode)); - TNode<IntPtrT> end = assembler_->IntPtrSub( - assembler_->UncheckedCast<IntPtrT>(base_), - assembler_->ElementOffsetFromIndex(last, SYSTEM_POINTER_ELEMENTS, mode)); - assembler_->BuildFastLoop( + TNode<RawPtrT> start = assembler_->RawPtrSub( + base_, + assembler_->ElementOffsetFromIndex(first, SYSTEM_POINTER_ELEMENTS)); + TNode<RawPtrT> end = assembler_->RawPtrSub( + base_, assembler_->ElementOffsetFromIndex(last, SYSTEM_POINTER_ELEMENTS)); + assembler_->BuildFastLoop<RawPtrT>( vars, start, end, - [this, &body](Node* current) { - Node* arg = assembler_->Load(MachineType::AnyTagged(), current); + [&](TNode<RawPtrT> current) { + TNode<Object> arg = assembler_->Load<Object>(current); body(arg); }, - -kSystemPointerSize, CodeStubAssembler::INTPTR_PARAMETERS, - CodeStubAssembler::IndexAdvanceMode::kPost); + -kSystemPointerSize, CodeStubAssembler::IndexAdvanceMode::kPost); } void CodeStubArguments::PopAndReturn(Node* value) { - Node* pop_count; + TNode<IntPtrT> pop_count; if (receiver_mode_ == ReceiverMode::kHasReceiver) { - pop_count = assembler_->IntPtrOrSmiAdd( - argc_, assembler_->IntPtrOrSmiConstant(1, argc_mode_), argc_mode_); + pop_count = assembler_->IntPtrAdd(argc_, assembler_->IntPtrConstant(1)); } else { pop_count = argc_; } - assembler_->PopAndReturn(assembler_->ParameterToIntPtr(pop_count, argc_mode_), - value); + assembler_->PopAndReturn(pop_count, value); } TNode<BoolT> CodeStubAssembler::IsFastElementsKind( @@ -13642,21 +13214,15 @@ Node* CodeStubAssembler:: } TNode<Code> CodeStubAssembler::LoadBuiltin(TNode<Smi> builtin_id) { - CSA_ASSERT(this, SmiGreaterThanOrEqual(builtin_id, SmiConstant(0))); - CSA_ASSERT(this, - SmiLessThan(builtin_id, SmiConstant(Builtins::builtin_count))); + CSA_ASSERT(this, SmiBelow(builtin_id, SmiConstant(Builtins::builtin_count))); - int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; - int index_shift = kSystemPointerSizeLog2 - kSmiShiftBits; - TNode<WordT> table_index = - index_shift >= 0 - ? WordShl(BitcastTaggedSignedToWord(builtin_id), index_shift) - : WordSar(BitcastTaggedSignedToWord(builtin_id), -index_shift); - - return CAST( - Load(MachineType::TaggedPointer(), + TNode<IntPtrT> offset = + ElementOffsetFromIndex(SmiToBInt(builtin_id), SYSTEM_POINTER_ELEMENTS); + + return CAST(BitcastWordToTagged( + Load(MachineType::Pointer(), ExternalConstant(ExternalReference::builtins_address(isolate())), - table_index)); + offset))); } TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode( @@ -13765,11 +13331,9 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode( return sfi_code.value(); } -Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map, - Node* shared_info, - Node* context) { - CSA_SLOW_ASSERT(this, IsMap(map)); - +TNode<JSFunction> CodeStubAssembler::AllocateFunctionWithMapAndContext( + TNode<Map> map, TNode<SharedFunctionInfo> shared_info, + TNode<Context> context) { TNode<Code> const code = GetSharedFunctionInfoCode(shared_info); // TODO(ishell): All the callers of this function pass map loaded from @@ -13790,7 +13354,7 @@ Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map, shared_info); StoreObjectFieldNoWriteBarrier(fun, JSFunction::kContextOffset, context); StoreObjectFieldNoWriteBarrier(fun, JSFunction::kCodeOffset, code); - return fun; + return CAST(fun); } void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver, @@ -13839,8 +13403,9 @@ void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver, } } -Node* CodeStubAssembler::CheckEnumCache(Node* receiver, Label* if_empty, - Label* if_runtime) { +TNode<Map> CodeStubAssembler::CheckEnumCache(TNode<HeapObject> receiver, + Label* if_empty, + Label* if_runtime) { Label if_fast(this), if_cache(this), if_no_cache(this, Label::kDeferred); TNode<Map> receiver_map = LoadMap(receiver); @@ -13855,7 +13420,7 @@ Node* CodeStubAssembler::CheckEnumCache(Node* receiver, Label* if_empty, { // Avoid runtime-call for empty dictionary receivers. GotoIfNot(IsDictionaryMap(receiver_map), if_runtime); - TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver)); + TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver))); TNode<Smi> length = GetNumberOfElements(properties); GotoIfNot(TaggedEqual(length, SmiConstant(0)), if_runtime); // Check that there are no elements on the {receiver} and its prototype @@ -13881,8 +13446,7 @@ TNode<Object> CodeStubAssembler::GetArgumentValue(TorqueStructArguments args, TorqueStructArguments CodeStubAssembler::GetFrameArguments( TNode<RawPtrT> frame, TNode<IntPtrT> argc) { - return CodeStubArguments(this, argc, frame, INTPTR_PARAMETERS) - .GetTorqueArguments(); + return CodeStubArguments(this, argc, frame).GetTorqueArguments(); } void CodeStubAssembler::Print(const char* s) { @@ -13976,9 +13540,8 @@ TNode<JSArray> CodeStubAssembler::ArrayCreate(TNode<Context> context, // TODO(delphick): Consider using // AllocateUninitializedJSArrayWithElements to avoid initializing an // array and then writing over it. - array = - AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, length, SmiConstant(0), - nullptr, ParameterMode::SMI_PARAMETERS); + array = AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, length, + SmiConstant(0), {}, ParameterMode::SMI_PARAMETERS); Goto(&done); BIND(&done); |