diff options
Diffstat (limited to 'deps/v8/src/code-stub-assembler.h')
-rw-r--r-- | deps/v8/src/code-stub-assembler.h | 445 |
1 files changed, 328 insertions, 117 deletions
diff --git a/deps/v8/src/code-stub-assembler.h b/deps/v8/src/code-stub-assembler.h index a2d5e80015..44becb3981 100644 --- a/deps/v8/src/code-stub-assembler.h +++ b/deps/v8/src/code-stub-assembler.h @@ -73,10 +73,10 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { public: using Node = compiler::Node; - template <class A> - using TNode = compiler::TNode<A>; - template <class A> - using SloppyTNode = compiler::SloppyTNode<A>; + template <class T> + using TNode = compiler::TNode<T>; + template <class T> + using SloppyTNode = compiler::SloppyTNode<T>; CodeStubAssembler(compiler::CodeAssemblerState* state); @@ -87,6 +87,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { kAllowLargeObjectAllocation = 1 << 2, }; + enum SlackTrackingMode { kWithSlackTracking, kNoSlackTracking }; + typedef base::Flags<AllocationFlag> AllocationFlags; enum ParameterMode { SMI_PARAMETERS, INTPTR_PARAMETERS }; @@ -177,8 +179,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* IntPtrOrSmiConstant(int value, ParameterMode mode); - bool IsIntPtrOrSmiConstantZero(Node* test); - bool TryGetIntPtrOrSmiConstantValue(Node* maybe_constant, int* value); + bool IsIntPtrOrSmiConstantZero(Node* test, ParameterMode mode); + bool TryGetIntPtrOrSmiConstantValue(Node* maybe_constant, int* value, + ParameterMode mode); // Round the 32bits payload of the provided word up to the next power of two. Node* IntPtrRoundUpToPowerOfTwo32(Node* value); @@ -284,6 +287,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { void GotoIfNotNumber(Node* value, Label* is_not_number); void GotoIfNumber(Node* value, Label* is_number); + Node* BitwiseOp(Node* left32, Node* right32, Operation bitwise_op); + // Allocate an object of the given size. Node* AllocateInNewSpace(Node* size, AllocationFlags flags = kNone); Node* AllocateInNewSpace(int size, AllocationFlags flags = kNone); @@ -408,6 +413,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { void BranchIfFastJSArrayForCopy(Node* object, Node* context, Label* if_true, Label* if_false); + // Branches to {if_true} when --force-slow-path flag has been passed. + // It's used for testing to ensure that slow path implementation behave + // equivalent to corresponding fast paths (where applicable). + // + // Works only in DEBUG mode or with ENABLE_FASTSLOW_SWITCH compile time flag. + // Nop otherwise. + void GotoIfForceSlowPath(Label* if_true); + // Load value from current frame by given offset in bytes. Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged()); // Load value from current parent frame by given offset in bytes. @@ -420,6 +433,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // Load a field from an object on the heap. Node* LoadObjectField(SloppyTNode<HeapObject> object, int offset, MachineType rep); + template <class T, typename std::enable_if< + std::is_convertible<TNode<T>, TNode<Object>>::value, + int>::type = 0> + TNode<T> LoadObjectField(TNode<HeapObject> object, int offset) { + return CAST(LoadObjectField(object, offset, MachineTypeOf<T>::value)); + } + template <class T, typename std::enable_if< + std::is_convertible<TNode<T>, TNode<UntaggedT>>::value, + int>::type = 0> + TNode<T> LoadObjectField(TNode<HeapObject> object, int offset) { + return UncheckedCast<T>( + LoadObjectField(object, offset, MachineTypeOf<T>::value)); + } TNode<Object> LoadObjectField(SloppyTNode<HeapObject> object, int offset) { return UncheckedCast<Object>( LoadObjectField(object, offset, MachineType::AnyTagged())); @@ -457,9 +483,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // Load the properties backing store of a JSObject. TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object); TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object); - // Load the hash from the backing store of a JSObject. - TNode<Int32T> LoadHashForJSObject(SloppyTNode<JSObject> jsobject, - SloppyTNode<Int32T> instance_type); // Load the elements backing store of a JSObject. TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object); // Load the length of a JSArray instance. @@ -490,15 +513,20 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { TNode<PrototypeInfo> LoadMapPrototypeInfo(SloppyTNode<Map> map, Label* if_has_no_proto_info); // Load the instance size of a Map. - TNode<IntPtrT> LoadMapInstanceSize(SloppyTNode<Map> map); - // Load the inobject properties count of a Map (valid only for JSObjects). - TNode<IntPtrT> LoadMapInobjectProperties(SloppyTNode<Map> map); + TNode<IntPtrT> LoadMapInstanceSizeInWords(SloppyTNode<Map> map); + // Load the inobject properties start of a Map (valid only for JSObjects). + TNode<IntPtrT> LoadMapInobjectPropertiesStartInWords(SloppyTNode<Map> map); // Load the constructor function index of a Map (only for primitive maps). TNode<IntPtrT> LoadMapConstructorFunctionIndex(SloppyTNode<Map> map); // Load the constructor of a Map (equivalent to Map::GetConstructor()). TNode<Object> LoadMapConstructor(SloppyTNode<Map> map); // Load the EnumLength of a Map. Node* LoadMapEnumLength(SloppyTNode<Map> map); + // Load the back-pointer of a Map. + Node* LoadMapBackPointer(SloppyTNode<Map> map); + // Load the identity hash of a JSRececiver. + TNode<IntPtrT> LoadJSReceiverIdentityHash(SloppyTNode<Object> receiver, + Label* if_no_hash = nullptr); // This is only used on a newly allocated PropertyArray which // doesn't have an existing hash. @@ -509,14 +537,17 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { TNode<BoolT> IsDictionaryMap(SloppyTNode<Map> map); // Load the hash field of a name as an uint32 value. - Node* LoadNameHashField(Node* name); + TNode<Uint32T> LoadNameHashField(SloppyTNode<Name> name); // Load the hash value of a name as an uint32 value. // If {if_hash_not_computed} label is specified then it also checks if // hash is actually computed. - Node* LoadNameHash(Node* name, Label* if_hash_not_computed = nullptr); + TNode<Uint32T> LoadNameHash(SloppyTNode<Name> name, + Label* if_hash_not_computed = nullptr); - // Load length field of a String object. - Node* LoadStringLength(Node* object); + // Load length field of a String object as intptr_t value. + TNode<IntPtrT> LoadStringLengthAsWord(SloppyTNode<String> object); + // Load length field of a String object as Smi value. + TNode<Smi> LoadStringLengthAsSmi(SloppyTNode<String> object); // Loads a pointer to the sequential String char array. Node* PointerToSeqStringData(Node* seq_string); // Load value field of a JSValue object. @@ -564,22 +595,39 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ParameterMode parameter_mode = INTPTR_PARAMETERS); // Context manipulation - Node* LoadContextElement(Node* context, int slot_index); - Node* LoadContextElement(Node* context, Node* slot_index); - Node* StoreContextElement(Node* context, int slot_index, Node* value); - Node* StoreContextElement(Node* context, Node* slot_index, Node* value); - Node* StoreContextElementNoWriteBarrier(Node* context, int slot_index, - Node* value); - Node* LoadNativeContext(Node* context); - - Node* LoadJSArrayElementsMap(ElementsKind kind, Node* native_context); - Node* LoadJSArrayElementsMap(Node* kind, Node* native_context); + TNode<Object> LoadContextElement(SloppyTNode<Context> context, + int slot_index); + TNode<Object> LoadContextElement(SloppyTNode<Context> context, + SloppyTNode<IntPtrT> slot_index); + void StoreContextElement(SloppyTNode<Context> context, int slot_index, + SloppyTNode<Object> value); + void StoreContextElement(SloppyTNode<Context> context, + SloppyTNode<IntPtrT> slot_index, + SloppyTNode<Object> value); + void StoreContextElementNoWriteBarrier(SloppyTNode<Context> context, + int slot_index, + SloppyTNode<Object> value); + TNode<Context> LoadNativeContext(SloppyTNode<Context> context); + // Calling this is only valid if there's a module context in the chain. + TNode<Context> LoadModuleContext(SloppyTNode<Context> context); + + void GotoIfContextElementEqual(Node* value, Node* native_context, + int slot_index, Label* if_equal) { + GotoIf(WordEqual(value, LoadContextElement(native_context, slot_index)), + if_equal); + } + + TNode<Map> LoadJSArrayElementsMap(ElementsKind kind, + SloppyTNode<Context> native_context); + TNode<Map> LoadJSArrayElementsMap(SloppyTNode<Int32T> kind, + SloppyTNode<Context> native_context); // Load the "prototype" property of a JSFunction. Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout); // Store the floating point value of a HeapNumber. - Node* StoreHeapNumberValue(Node* object, Node* value); + void StoreHeapNumberValue(SloppyTNode<HeapNumber> object, + SloppyTNode<Float64T> value); // Store a field to an object on the heap. Node* StoreObjectField(Node* object, int offset, Node* value); Node* StoreObjectField(Node* object, Node* offset, Node* value); @@ -655,41 +703,42 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Allocate a HeapNumber without initializing its value. - Node* AllocateHeapNumber(MutableMode mode = IMMUTABLE); + TNode<HeapNumber> AllocateHeapNumber(MutableMode mode = IMMUTABLE); // Allocate a HeapNumber with a specific value. - Node* AllocateHeapNumberWithValue(Node* value, MutableMode mode = IMMUTABLE); + TNode<HeapNumber> AllocateHeapNumberWithValue(SloppyTNode<Float64T> value, + MutableMode mode = IMMUTABLE); // Allocate a SeqOneByteString with the given length. Node* AllocateSeqOneByteString(int length, AllocationFlags flags = kNone); - Node* AllocateSeqOneByteString(Node* context, Node* length, - ParameterMode mode = INTPTR_PARAMETERS, + Node* AllocateSeqOneByteString(Node* context, TNode<Smi> length, AllocationFlags flags = kNone); // Allocate a SeqTwoByteString with the given length. Node* AllocateSeqTwoByteString(int length, AllocationFlags flags = kNone); - Node* AllocateSeqTwoByteString(Node* context, Node* length, - ParameterMode mode = INTPTR_PARAMETERS, + Node* AllocateSeqTwoByteString(Node* context, TNode<Smi> length, AllocationFlags flags = kNone); // Allocate a SlicedOneByteString with the given length, parent and offset. // |length| and |offset| are expected to be tagged. - Node* AllocateSlicedOneByteString(Node* length, Node* parent, Node* offset); + Node* AllocateSlicedOneByteString(TNode<Smi> length, Node* parent, + Node* offset); // Allocate a SlicedTwoByteString with the given length, parent and offset. // |length| and |offset| are expected to be tagged. - Node* AllocateSlicedTwoByteString(Node* length, Node* parent, Node* offset); + Node* AllocateSlicedTwoByteString(TNode<Smi> length, Node* parent, + Node* offset); // Allocate a one-byte ConsString with the given length, first and second // parts. |length| is expected to be tagged, and |first| and |second| are // expected to be one-byte strings. - Node* AllocateOneByteConsString(Node* length, Node* first, Node* second, + Node* AllocateOneByteConsString(TNode<Smi> length, Node* first, Node* second, AllocationFlags flags = kNone); // Allocate a two-byte ConsString with the given length, first and second // parts. |length| is expected to be tagged, and |first| and |second| are // expected to be two-byte strings. - Node* AllocateTwoByteConsString(Node* length, Node* first, Node* second, + Node* AllocateTwoByteConsString(TNode<Smi> length, Node* first, Node* second, AllocationFlags flags = kNone); // Allocate an appropriate one- or two-byte ConsString with the first and - // second parts specified by |first| and |second|. - Node* NewConsString(Node* context, Node* length, Node* left, Node* right, + // second parts specified by |left| and |right|. + Node* NewConsString(Node* context, TNode<Smi> length, Node* left, Node* right, AllocationFlags flags = kNone); Node* AllocateNameDictionary(int at_least_space_for); @@ -700,16 +749,22 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* AllocateStruct(Node* map, AllocationFlags flags = kNone); void InitializeStructBody(Node* object, Node* map, Node* size, int start_offset = Struct::kHeaderSize); - Node* AllocateJSObjectFromMap(Node* map, Node* properties = nullptr, - Node* elements = nullptr, - AllocationFlags flags = kNone); - void InitializeJSObjectFromMap(Node* object, Node* map, Node* size, - Node* properties = nullptr, - Node* elements = nullptr); + Node* AllocateJSObjectFromMap( + Node* map, Node* properties = nullptr, Node* elements = nullptr, + AllocationFlags flags = kNone, + SlackTrackingMode slack_tracking_mode = kNoSlackTracking); + + void InitializeJSObjectFromMap( + Node* object, Node* map, Node* instance_size, Node* properties = nullptr, + Node* elements = nullptr, + SlackTrackingMode slack_tracking_mode = kNoSlackTracking); - void InitializeJSObjectBody(Node* object, Node* map, Node* size, - int start_offset = JSObject::kHeaderSize); + void InitializeJSObjectBodyWithSlackTracking(Node* object, Node* map, + Node* instance_size); + void InitializeJSObjectBodyNoSlackTracking( + Node* object, Node* map, Node* instance_size, + int start_offset = JSObject::kHeaderSize); // Allocate a JSArray without elements and initialize the header fields. Node* AllocateUninitializedJSArrayWithoutElements(Node* array_map, @@ -727,9 +782,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* length, Node* allocation_site = nullptr, ParameterMode capacity_mode = INTPTR_PARAMETERS); + Node* CloneFastJSArray(Node* context, Node* array, + ParameterMode mode = INTPTR_PARAMETERS, + Node* allocation_site = nullptr); + + Node* ExtractFastJSArray(Node* context, Node* array, Node* begin, Node* count, + ParameterMode mode = INTPTR_PARAMETERS, + Node* capacity = nullptr, + Node* allocation_site = nullptr); + Node* AllocateFixedArray(ElementsKind kind, Node* capacity, ParameterMode mode = INTPTR_PARAMETERS, - AllocationFlags flags = kNone); + AllocationFlags flags = kNone, + Node* fixed_array_map = nullptr); Node* AllocatePropertyArray(Node* capacity, ParameterMode mode = INTPTR_PARAMETERS, @@ -765,31 +830,103 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ElementsKind kind, Node* from_array, Node* to_array, Node* length, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, ParameterMode mode = INTPTR_PARAMETERS) { - CopyFixedArrayElements(kind, from_array, kind, to_array, length, length, + CopyFixedArrayElements(kind, from_array, kind, to_array, + IntPtrOrSmiConstant(0, mode), length, length, barrier_mode, mode); } - // Copies |element_count| elements from |from_array| to |to_array| of - // |capacity| size respecting both array's elements kinds. + // Copies |element_count| elements from |from_array| starting from element + // zero to |to_array| of |capacity| size respecting both array's elements + // kinds. void CopyFixedArrayElements( ElementsKind from_kind, Node* from_array, ElementsKind to_kind, Node* to_array, Node* element_count, Node* capacity, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, + ParameterMode mode = INTPTR_PARAMETERS) { + CopyFixedArrayElements(from_kind, from_array, to_kind, to_array, + IntPtrOrSmiConstant(0, mode), element_count, + capacity, barrier_mode, mode); + } + + // Copies |element_count| elements from |from_array| starting from element + // |first_element| to |to_array| of |capacity| size respecting both array's + // elements kinds. + void CopyFixedArrayElements( + ElementsKind from_kind, Node* from_array, ElementsKind to_kind, + Node* to_array, Node* first_element, Node* element_count, Node* capacity, + WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, ParameterMode mode = INTPTR_PARAMETERS); + enum class ExtractFixedArrayFlag { + kFixedArrays = 1, + kFixedDoubleArrays = 2, + kDontCopyCOW = 4, + kNewSpaceAllocationOnly = 8, + kAllFixedArrays = kFixedArrays | kFixedDoubleArrays, + kAllFixedArraysDontCopyCOW = kAllFixedArrays | kDontCopyCOW + }; + + typedef base::Flags<ExtractFixedArrayFlag> ExtractFixedArrayFlags; + + // Copy a portion of an existing FixedArray or FixedDoubleArray into a new + // FixedArray, including special appropriate handling for empty arrays and COW + // arrays. + // + // * |source| is either a FixedArray or FixedDoubleArray from which to copy + // elements. + // * |first| is the starting element index to copy from, if nullptr is passed + // then index zero is used by default. + // * |count| is the number of elements to copy out of the source array + // starting from and including the element indexed by |start|. If |count| is + // nullptr, then all of the elements from |start| to the end of |source| are + // copied. + // * |capacity| determines the size of the allocated result array, with + // |capacity| >= |count|. If |capacity| is nullptr, then |count| is used as + // the destination array's capacity. + // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both + // are detected and copied. Although it's always correct to pass + // kAllFixedArrays, the generated code is more compact and efficient if the + // caller can specify whether only FixedArrays or FixedDoubleArrays will be + // passed as the |source| parameter. + // * |parameter_mode| determines the parameter mode of |first|, |count| and + // |capacity|. + Node* ExtractFixedArray(Node* source, Node* first, Node* count = nullptr, + Node* capacity = nullptr, + ExtractFixedArrayFlags extract_flags = + ExtractFixedArrayFlag::kAllFixedArrays, + ParameterMode parameter_mode = INTPTR_PARAMETERS); + + // Copy the entire contents of a FixedArray or FixedDoubleArray to a new + // array, including special appropriate handling for empty arrays and COW + // arrays. + // + // * |source| is either a FixedArray or FixedDoubleArray from which to copy + // elements. + // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both + // are detected and copied. Although it's always correct to pass + // kAllFixedArrays, the generated code is more compact and efficient if the + // caller can specify whether only FixedArrays or FixedDoubleArrays will be + // passed as the |source| parameter. + Node* CloneFixedArray(Node* source, + ExtractFixedArrayFlags flags = + ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW) { + ParameterMode mode = OptimalParameterMode(); + return ExtractFixedArray(source, IntPtrOrSmiConstant(0, mode), nullptr, + nullptr, flags, mode); + } + // Copies |character_count| elements from |from_string| to |to_string| // starting at the |from_index|'th character. |from_string| and |to_string| // can either be one-byte strings or two-byte strings, although if // |from_string| is two-byte, then |to_string| must be two-byte. - // |from_index|, |to_index| and |character_count| must be either Smis or - // intptr_ts depending on |mode| s.t. 0 <= |from_index| <= |from_index| + - // |character_count| <= from_string.length and 0 <= |to_index| <= |to_index| + - // |character_count| <= to_string.length. + // |from_index|, |to_index| and |character_count| must be intptr_ts s.t. 0 <= + // |from_index| <= |from_index| + |character_count| <= from_string.length and + // 0 <= |to_index| <= |to_index| + |character_count| <= to_string.length. void CopyStringCharacters(Node* from_string, Node* to_string, - Node* from_index, Node* to_index, - Node* character_count, + TNode<IntPtrT> from_index, TNode<IntPtrT> to_index, + TNode<IntPtrT> character_count, String::Encoding from_encoding, - String::Encoding to_encoding, ParameterMode mode); + String::Encoding to_encoding); // Loads an element from |array| of |from_kind| elements by given |offset| // (NOTE: not index!), does a hole check if |if_hole| is provided and @@ -836,22 +973,36 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* TryTaggedToFloat64(Node* value, Label* if_valueisnotnumber); Node* TruncateTaggedToFloat64(Node* context, Node* value); Node* TruncateTaggedToWord32(Node* context, Node* value); + void TaggedToWord32OrBigInt(Node* context, Node* value, Label* if_number, + Variable* var_word32, Label* if_bigint, + Variable* var_bigint); + void TaggedToWord32OrBigIntWithFeedback( + Node* context, Node* value, Label* if_number, Variable* var_word32, + Label* if_bigint, Variable* var_bigint, Variable* var_feedback); + // Truncate the floating point value of a HeapNumber to an Int32. Node* TruncateHeapNumberValueToWord32(Node* object); // Conversions. - Node* ChangeFloat64ToTagged(Node* value); - Node* ChangeInt32ToTagged(Node* value); - Node* ChangeUint32ToTagged(Node* value); - Node* ChangeNumberToFloat64(Node* value); - Node* ChangeNumberToIntPtr(Node* value); + TNode<Number> ChangeFloat64ToTagged(SloppyTNode<Float64T> value); + TNode<Number> ChangeInt32ToTagged(SloppyTNode<Int32T> value); + TNode<Number> ChangeUint32ToTagged(SloppyTNode<Uint32T> value); + TNode<Float64T> ChangeNumberToFloat64(SloppyTNode<Number> value); + TNode<UintPtrT> ChangeNonnegativeNumberToUintPtr(SloppyTNode<Number> value); + + void TaggedToNumeric(Node* context, Node* value, Label* done, + Variable* var_numeric); + void TaggedToNumericWithFeedback(Node* context, Node* value, Label* done, + Variable* var_numeric, + Variable* var_feedback); Node* TimesPointerSize(Node* value); // Type conversions. // Throws a TypeError for {method_name} if {value} is not coercible to Object, // or returns the {value} converted to a String otherwise. - Node* ToThisString(Node* context, Node* value, char const* method_name); + TNode<String> ToThisString(Node* context, Node* value, + char const* method_name); // Throws a TypeError for {method_name} if {value} is neither of the given // {primitive_type} nor a JSValue wrapping a value of {primitive_type}, or // returns the {value} (or wrapped value) otherwise. @@ -867,6 +1018,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* ThrowIfNotInstanceType(Node* context, Node* value, InstanceType instance_type, char const* method_name); + // Throws a TypeError for {method_name} if {value} is not a JSReceiver. + // Returns the {value}'s map. + Node* ThrowIfNotJSReceiver(Node* context, Node* value, + MessageTemplate::Template msg_template, + const char* method_name = nullptr); void ThrowRangeError(Node* context, MessageTemplate::Template message, Node* arg0 = nullptr, Node* arg1 = nullptr, @@ -884,8 +1040,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* IsAccessorPair(Node* object); Node* IsAllocationSite(Node* object); Node* IsAnyHeapNumber(Node* object); + Node* IsArrayIteratorInstanceType(Node* instance_type); + Node* IsNoElementsProtectorCellInvalid(); + Node* IsBigIntInstanceType(Node* instance_type); + Node* IsBigInt(Node* object); Node* IsBoolean(Node* object); - Node* IsExtensibleMap(Node* map); Node* IsCallableMap(Node* map); Node* IsCallable(Node* object); Node* IsCell(Node* object); @@ -894,14 +1053,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* IsConstructor(Node* object); Node* IsDeprecatedMap(Node* map); Node* IsDictionary(Node* object); + Node* IsExtensibleMap(Node* map); Node* IsExternalStringInstanceType(Node* instance_type); + TNode<BoolT> IsFastJSArray(SloppyTNode<Object> object, + SloppyTNode<Context> context); Node* IsFeedbackVector(Node* object); Node* IsFixedArray(Node* object); + Node* IsFixedArraySubclass(Node* object); Node* IsFixedArrayWithKind(Node* object, ElementsKind kind); Node* IsFixedArrayWithKindOrEmpty(Node* object, ElementsKind kind); Node* IsFixedDoubleArray(Node* object); Node* IsFixedTypedArray(Node* object); - Node* IsZeroOrFixedArray(Node* object); + Node* IsFunctionWithPrototypeSlotMap(Node* map); Node* IsHashTable(Node* object); Node* IsHeapNumber(Node* object); Node* IsIndirectStringInstanceType(Node* instance_type); @@ -912,16 +1075,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* IsJSFunctionInstanceType(Node* instance_type); Node* IsJSFunctionMap(Node* object); Node* IsJSFunction(Node* object); + Node* IsJSGlobalProxyInstanceType(Node* instance_type); Node* IsJSGlobalProxy(Node* object); Node* IsJSObjectInstanceType(Node* instance_type); Node* IsJSObjectMap(Node* map); Node* IsJSObject(Node* object); - Node* IsJSGlobalProxyInstanceType(Node* instance_type); Node* IsJSProxy(Node* object); Node* IsJSReceiverInstanceType(Node* instance_type); Node* IsJSReceiverMap(Node* map); Node* IsJSReceiver(Node* object); - Node* IsNullOrJSReceiver(Node* object); Node* IsJSRegExp(Node* object); Node* IsJSTypedArray(Node* object); Node* IsJSValueInstanceType(Node* instance_type); @@ -931,33 +1093,36 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* IsMutableHeapNumber(Node* object); Node* IsName(Node* object); Node* IsNativeContext(Node* object); + Node* IsNullOrJSReceiver(Node* object); + Node* IsNullOrUndefined(Node* object); + Node* IsNumberDictionary(Node* object); Node* IsOneByteStringInstanceType(Node* instance_type); Node* IsPrimitiveInstanceType(Node* instance_type); Node* IsPrivateSymbol(Node* object); Node* IsPropertyArray(Node* object); Node* IsPropertyCell(Node* object); + Node* IsPrototypeInitialArrayPrototype(Node* context, Node* map); Node* IsSequentialStringInstanceType(Node* instance_type); - inline Node* IsSharedFunctionInfo(Node* object) { - return IsSharedFunctionInfoMap(LoadMap(object)); - } Node* IsShortExternalStringInstanceType(Node* instance_type); Node* IsSpecialReceiverInstanceType(Node* instance_type); Node* IsSpecialReceiverMap(Node* map); + Node* IsSpeciesProtectorCellInvalid(); Node* IsStringInstanceType(Node* instance_type); Node* IsString(Node* object); Node* IsSymbolInstanceType(Node* instance_type); Node* IsSymbol(Node* object); - Node* IsBigIntInstanceType(Node* instance_type); - Node* IsBigInt(Node* object); - Node* IsUnseededNumberDictionary(Node* object); - Node* IsWeakCell(Node* object); Node* IsUndetectableMap(Node* map); - Node* IsArrayProtectorCellInvalid(); - Node* IsSpeciesProtectorCellInvalid(); - Node* IsPrototypeInitialArrayPrototype(Node* context, Node* map); + Node* IsWeakCell(Node* object); + Node* IsZeroOrFixedArray(Node* object); + + inline Node* IsSharedFunctionInfo(Node* object) { + return IsSharedFunctionInfoMap(LoadMap(object)); + } // True iff |object| is a Smi or a HeapNumber. Node* IsNumber(Node* object); + // True iff |object| is a Smi or a HeapNumber or a BigInt. + Node* IsNumeric(Node* object); // True iff |number| is either a Smi, or a HeapNumber whose value is not // within Smi range. @@ -969,15 +1134,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // ElementsKind helpers: Node* IsFastElementsKind(Node* elements_kind); + Node* IsFastSmiOrTaggedElementsKind(Node* elements_kind); Node* IsHoleyFastElementsKind(Node* elements_kind); Node* IsElementsKindGreaterThan(Node* target_kind, ElementsKind reference_kind); + Node* FixedArraySizeDoesntFitInNewSpace( + Node* element_count, int base_size = FixedArray::kHeaderSize, + ParameterMode mode = INTPTR_PARAMETERS); + // String helpers. // Load a character from a String (might flatten a ConsString). - TNode<Uint32T> StringCharCodeAt( - SloppyTNode<String> string, Node* index, - ParameterMode parameter_mode = SMI_PARAMETERS); + TNode<Uint32T> StringCharCodeAt(SloppyTNode<String> string, + SloppyTNode<IntPtrT> index); // Return the single character string with only {code}. Node* StringFromCharCode(Node* code); @@ -1013,26 +1182,39 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* StringFromCodePoint(Node* codepoint, UnicodeEncoding encoding); // Type conversion helpers. + enum class BigIntHandling { kConvertToNumber, kThrow }; // Convert a String to a Number. - Node* StringToNumber(Node* context, Node* input); + TNode<Number> StringToNumber(SloppyTNode<Context> context, + SloppyTNode<String> input); Node* NumberToString(Node* context, Node* input); // Convert an object to a name. Node* ToName(Node* context, Node* input); // Convert a Non-Number object to a Number. - Node* NonNumberToNumber(Node* context, Node* input); + TNode<Number> NonNumberToNumber( + SloppyTNode<Context> context, SloppyTNode<HeapObject> input, + BigIntHandling bigint_handling = BigIntHandling::kThrow); + // Convert a Non-Number object to a Numeric. + TNode<Numeric> NonNumberToNumeric(SloppyTNode<Context> context, + SloppyTNode<HeapObject> input); // Convert any object to a Number. - Node* ToNumber(Node* context, Node* input); + // Conforms to ES#sec-tonumber if {bigint_handling} == kThrow. + // With {bigint_handling} == kConvertToNumber, matches behavior of + // tc39.github.io/proposal-bigint/#sec-number-constructor-number-value. + TNode<Number> ToNumber( + SloppyTNode<Context> context, SloppyTNode<Object> input, + BigIntHandling bigint_handling = BigIntHandling::kThrow); // Converts |input| to one of 2^32 integer values in the range 0 through // 2^32-1, inclusive. // ES#sec-touint32 - TNode<Object> ToUint32(SloppyTNode<Context> context, + TNode<Number> ToUint32(SloppyTNode<Context> context, SloppyTNode<Object> input); // Convert any object to a String. TNode<String> ToString(SloppyTNode<Context> context, SloppyTNode<Object> input); - Node* ToString_Inline(Node* const context, Node* const input); + TNode<String> ToString_Inline(SloppyTNode<Context> context, + SloppyTNode<Object> input); // Convert any object to a Primitive. Node* JSReceiverToPrimitive(Node* context, Node* input); @@ -1052,7 +1234,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* ToLength_Inline(Node* const context, Node* const input); // Convert any object to an Integer. - TNode<Object> ToInteger(SloppyTNode<Context> context, + TNode<Number> ToInteger(SloppyTNode<Context> context, SloppyTNode<Object> input, ToIntegerTruncationMode mode = kNoTruncation); @@ -1113,6 +1295,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Int32Constant(0)); } + // Returns true if none of the mask's bits in given |word32| are set. + TNode<BoolT> IsNotSetWord32(SloppyTNode<Word32T> word32, uint32_t mask) { + return Word32Equal(Word32And(word32, Int32Constant(mask)), + Int32Constant(0)); + } + // Returns true if any of the |T|'s bits in given |word| are set. template <typename T> Node* IsSetWord(Node* word) { @@ -1305,7 +1493,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* ComputeIntegerHash(Node* key); Node* ComputeIntegerHash(Node* key, Node* seed); - template <typename Dictionary> void NumberDictionaryLookup(Node* dictionary, Node* intptr_index, Label* if_found, Variable* var_entry, Label* if_not_found); @@ -1356,11 +1543,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { template <class... TArgs> Node* CallBuiltin(Builtins::Name id, Node* context, TArgs... args) { + DCHECK_IMPLIES(Builtins::KindOf(id) == Builtins::TFJ, + !Builtins::IsLazy(id)); return CallStub(Builtins::CallableFor(isolate(), id), context, args...); } template <class... TArgs> Node* TailCallBuiltin(Builtins::Name id, Node* context, TArgs... args) { + DCHECK_IMPLIES(Builtins::KindOf(id) == Builtins::TFJ, + !Builtins::IsLazy(id)); return TailCallStub(Builtins::CallableFor(isolate(), id), context, args...); } @@ -1439,6 +1630,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // Update the type feedback vector. void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id); + // Report that there was a feedback update, performing any tasks that should + // be done after a feedback update. + void ReportFeedbackUpdate(SloppyTNode<FeedbackVector> feedback_vector, + SloppyTNode<IntPtrT> slot_id, const char* reason); + // Combine the new feedback with the existing_feedback. void CombineFeedback(Variable* existing_feedback, Node* feedback); @@ -1500,11 +1696,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // Create a new AllocationSite and install it into a feedback vector. Node* CreateAllocationSiteInFeedbackVector(Node* feedback_vector, Node* slot); - // Given a recently allocated object {object}, with map {initial_map}, - // initialize remaining fields appropriately to comply with slack tracking. - void HandleSlackTracking(Node* context, Node* object, Node* initial_map, - int start_offset); - enum class IndexAdvanceMode { kPre, kPost }; typedef std::function<void(Node* index)> FastLoopBody; @@ -1568,22 +1759,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { void InitializeFieldsWithRoot(Node* object, Node* start_offset, Node* end_offset, Heap::RootListIndex root); - enum RelationalComparisonMode { - kLessThan, - kLessThanOrEqual, - kGreaterThan, - kGreaterThanOrEqual - }; - - Node* RelationalComparison(RelationalComparisonMode mode, Node* lhs, - Node* rhs, Node* context, + Node* RelationalComparison(Operation op, Node* lhs, Node* rhs, Node* context, Variable* var_type_feedback = nullptr); - void BranchIfNumericRelationalComparison(RelationalComparisonMode mode, - Node* lhs, Node* rhs, Label* if_true, - Label* if_false); + void BranchIfNumericRelationalComparison(Operation op, Node* lhs, Node* rhs, + Label* if_true, Label* if_false); + + void BranchIfAccessorPair(Node* value, Label* if_accessor_pair, + Label* if_not_accessor_pair) { + GotoIf(TaggedIsSmi(value), if_not_accessor_pair); + Branch(IsAccessorPair(value), if_accessor_pair, if_not_accessor_pair); + } - void GotoIfNumberGreaterThanOrEqual(Node* lhs, Node* rhs, Label* if_false); + void GotoIfNumericGreaterThanOrEqual(Node* lhs, Node* rhs, Label* if_false); Node* Equal(Node* lhs, Node* rhs, Node* context, Variable* var_type_feedback = nullptr); @@ -1643,7 +1831,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // Support for printf-style debugging void Print(const char* s); void Print(const char* prefix, Node* tagged_value); - inline void Print(Node* tagged_value) { return Print(nullptr, tagged_value); } + inline void Print(SloppyTNode<Object> tagged_value) { + return Print(nullptr, tagged_value); + } template <class... TArgs> Node* MakeTypeError(MessageTemplate::Template message, Node* context, @@ -1660,6 +1850,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Unreachable(); } + void PerformStackCheck(Node* context); + protected: void DescriptorLookup(Node* unique_name, Node* descriptors, Node* bitfield3, Label* if_found, Variable* var_name_index, @@ -1710,11 +1902,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* EmitKeyedSloppyArguments(Node* receiver, Node* key, Node* value, Label* bailout); - Node* AllocateSlicedString(Heap::RootListIndex map_root_index, Node* length, - Node* parent, Node* offset); + Node* AllocateSlicedString(Heap::RootListIndex map_root_index, + TNode<Smi> length, Node* parent, Node* offset); - Node* AllocateConsString(Heap::RootListIndex map_root_index, Node* length, - Node* first, Node* second, AllocationFlags flags); + Node* AllocateConsString(Heap::RootListIndex map_root_index, + TNode<Smi> length, Node* first, Node* second, + AllocationFlags flags); // Implements DescriptorArray::number_of_entries. // Returns an untagged int32. @@ -1728,19 +1921,37 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { void GenerateEqual_Same(Node* value, Label* if_equal, Label* if_notequal, Variable* var_type_feedback = nullptr); Node* AllocAndCopyStringCharacters(Node* context, Node* from, - Node* from_instance_type, Node* from_index, - Node* character_count); + Node* from_instance_type, + TNode<IntPtrT> from_index, + TNode<Smi> character_count); static const int kElementLoopUnrollThreshold = 8; + + // {convert_bigint} is only meaningful when {mode} == kToNumber. + Node* NonNumberToNumberOrNumeric( + Node* context, Node* input, Object::Conversion mode, + BigIntHandling bigint_handling = BigIntHandling::kThrow); + + enum class Feedback { kCollect, kNone }; + template <Feedback feedback> + void TaggedToNumeric(Node* context, Node* value, Label* done, + Variable* var_numeric, Variable* var_feedback = nullptr); + + template <Feedback feedback, Object::Conversion conversion> + void TaggedToWord32OrBigIntImpl(Node* context, Node* value, Label* if_number, + Variable* var_word32, + Label* if_bigint = nullptr, + Variable* var_bigint = nullptr, + Variable* var_feedback = nullptr); }; class CodeStubArguments { public: typedef compiler::Node Node; - template <class A> - using TNode = compiler::TNode<A>; - template <class A> - using SloppyTNode = compiler::SloppyTNode<A>; + template <class T> + using TNode = compiler::TNode<T>; + template <class T> + using SloppyTNode = compiler::SloppyTNode<T>; enum ReceiverMode { kHasReceiver, kNoReceiver }; // |argc| is an intptr value which specifies the number of arguments passed |