diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-09-18 14:34:04 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-10-04 11:15:27 +0000 |
commit | e6430e577f105ad8813c92e75c54660c4985026e (patch) | |
tree | 88115e5d1fb471fea807111924dcccbeadbf9e4f /chromium/v8/src/code-stub-assembler.cc | |
parent | 53d399fe6415a96ea6986ec0d402a9c07da72453 (diff) | |
download | qtwebengine-chromium-e6430e577f105ad8813c92e75c54660c4985026e.tar.gz |
BASELINE: Update Chromium to 61.0.3163.99
Change-Id: I8452f34574d88ca2b27af9bd56fc9ff3f16b1367
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/src/code-stub-assembler.cc')
-rw-r--r-- | chromium/v8/src/code-stub-assembler.cc | 1312 |
1 files changed, 837 insertions, 475 deletions
diff --git a/chromium/v8/src/code-stub-assembler.cc b/chromium/v8/src/code-stub-assembler.cc index edfe2de86c1..465643dd127 100644 --- a/chromium/v8/src/code-stub-assembler.cc +++ b/chromium/v8/src/code-stub-assembler.cc @@ -74,9 +74,8 @@ void CodeStubAssembler::Check(const NodeGenerator& condition_body, } else { SNPrintF(buffer, "CSA_ASSERT failed: %s\n", message); } - CallRuntime( - Runtime::kGlobalPrint, SmiConstant(Smi::kZero), - HeapConstant(factory()->NewStringFromAsciiChecked(&(buffer[0])))); + CallRuntime(Runtime::kGlobalPrint, SmiConstant(0), + HeapConstant(factory()->InternalizeUtf8String(&(buffer[0])))); } DebugBreak(); Goto(&ok); @@ -154,9 +153,12 @@ Node* CodeStubAssembler::NoContextConstant() { return NumberConstant(0); } HEAP_CONSTANT_LIST(HEAP_CONSTANT_ACCESSOR); #undef HEAP_CONSTANT_ACCESSOR -#define HEAP_CONSTANT_TEST(rootName, name) \ - Node* CodeStubAssembler::Is##name(Node* value) { \ - return WordEqual(value, name##Constant()); \ +#define HEAP_CONSTANT_TEST(rootName, name) \ + Node* CodeStubAssembler::Is##name(Node* value) { \ + return WordEqual(value, name##Constant()); \ + } \ + Node* CodeStubAssembler::IsNot##name(Node* value) { \ + return WordNotEqual(value, name##Constant()); \ } HEAP_CONSTANT_LIST(HEAP_CONSTANT_TEST); #undef HEAP_CONSTANT_TEST @@ -171,7 +173,7 @@ Node* CodeStubAssembler::StaleRegisterConstant() { Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) { if (mode == SMI_PARAMETERS) { - return SmiConstant(Smi::FromInt(value)); + return SmiConstant(value); } else { DCHECK_EQ(INTPTR_PARAMETERS, mode); return IntPtrConstant(value); @@ -198,6 +200,10 @@ Node* CodeStubAssembler::IntPtrRoundUpToPowerOfTwo32(Node* value) { return IntPtrAdd(value, IntPtrConstant(1)); } +Node* CodeStubAssembler::MatchesParameterMode(Node* value, ParameterMode mode) { + return (mode == SMI_PARAMETERS) ? TaggedIsSmi(value) : Int32Constant(1); +} + Node* CodeStubAssembler::WordIsPowerOfTwo(Node* value) { // value && !(value & (value - 1)) return WordEqual( @@ -435,7 +441,7 @@ Node* CodeStubAssembler::SmiFromWord32(Node* value) { Node* CodeStubAssembler::SmiTag(Node* value) { int32_t constant_value; if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) { - return SmiConstant(Smi::FromInt(constant_value)); + return SmiConstant(constant_value); } return BitcastWordToTaggedSigned(WordShl(value, SmiShiftBitsConstant())); } @@ -672,6 +678,7 @@ void CodeStubAssembler::Bind(Label* label) { CodeAssembler::Bind(label); } 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); Node* empty_elements = LoadRoot(Heap::kEmptyFixedArrayRootIndex); @@ -948,12 +955,7 @@ void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true, // Only null, undefined and document.all have the undetectable bit set, // so we can return false immediately when that bit is set. - Node* value_map_bitfield = LoadMapBitField(value_map); - Node* value_map_undetectable = - Word32And(value_map_bitfield, Int32Constant(1 << Map::kIsUndetectable)); - - // Check if the {value} is undetectable. - GotoIfNot(Word32Equal(value_map_undetectable, Int32Constant(0)), if_false); + GotoIf(IsUndetectableMap(value_map), if_false); // We still need to handle numbers specially, but all other {value}s // that make it here yield true. @@ -1093,7 +1095,7 @@ Node* CodeStubAssembler::DoesntHaveInstanceType(Node* object, } Node* CodeStubAssembler::LoadProperties(Node* object) { - return LoadObjectField(object, JSObject::kPropertiesOffset); + return LoadObjectField(object, JSObject::kPropertiesOrHashOffset); } Node* CodeStubAssembler::LoadElements(Node* object) { @@ -1210,25 +1212,6 @@ Node* CodeStubAssembler::LoadMapConstructor(Node* map) { return result.value(); } -Node* CodeStubAssembler::LoadSharedFunctionInfoSpecialField( - Node* shared, int offset, ParameterMode mode) { - if (Is64()) { - Node* result = LoadObjectField(shared, offset, MachineType::Int32()); - if (mode == SMI_PARAMETERS) { - result = SmiTag(result); - } else { - result = ChangeUint32ToWord(result); - } - return result; - } else { - Node* result = LoadObjectField(shared, offset); - if (mode != SMI_PARAMETERS) { - result = SmiUntag(result); - } - return result; - } -} - Node* CodeStubAssembler::LoadNameHashField(Node* name) { CSA_ASSERT(this, IsName(name)); return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32()); @@ -1237,9 +1220,7 @@ Node* CodeStubAssembler::LoadNameHashField(Node* name) { Node* CodeStubAssembler::LoadNameHash(Node* name, Label* if_hash_not_computed) { Node* hash_field = LoadNameHashField(name); if (if_hash_not_computed != nullptr) { - GotoIf(Word32Equal( - Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), - Int32Constant(0)), + GotoIf(IsSetWord32(hash_field, Name::kHashNotComputedMask), if_hash_not_computed); } return Word32Shr(hash_field, Int32Constant(Name::kHashShift)); @@ -1284,7 +1265,7 @@ Node* CodeStubAssembler::LoadFixedArrayElement(Node* object, Node* index_node, ParameterMode parameter_mode) { int32_t header_size = FixedArray::kHeaderSize + additional_offset - kHeapObjectTag; - Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, + Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS, parameter_mode, header_size); return Load(MachineType::AnyTagged(), object, offset); } @@ -1349,13 +1330,14 @@ Node* CodeStubAssembler::LoadFixedTypedArrayElementAsTagged( return AllocateHeapNumberWithValue(value); default: UNREACHABLE(); - return nullptr; } } Node* CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement( Node* object, Node* index_node, int additional_offset, ParameterMode parameter_mode) { + CSA_SLOW_ASSERT(this, IsFixedArray(object)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, parameter_mode)); int32_t header_size = FixedArray::kHeaderSize + additional_offset - kHeapObjectTag; #if V8_TARGET_LITTLE_ENDIAN @@ -1363,7 +1345,7 @@ Node* CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement( header_size += kPointerSize / 2; } #endif - Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, + Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS, parameter_mode, header_size); if (Is64()) { return Load(MachineType::Int32(), object, offset); @@ -1375,10 +1357,12 @@ Node* CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement( Node* CodeStubAssembler::LoadFixedDoubleArrayElement( Node* object, Node* index_node, MachineType machine_type, int additional_offset, ParameterMode parameter_mode, Label* if_hole) { + CSA_SLOW_ASSERT(this, IsFixedDoubleArray(object)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, parameter_mode)); CSA_ASSERT(this, IsFixedDoubleArray(object)); int32_t header_size = FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag; - Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_DOUBLE_ELEMENTS, + Node* offset = ElementOffsetFromIndex(index_node, HOLEY_DOUBLE_ELEMENTS, parameter_mode, header_size); return LoadDoubleWithHoleCheck(object, offset, if_hole, machine_type); } @@ -1542,11 +1526,15 @@ Node* CodeStubAssembler::StoreFixedArrayElement(Node* object, Node* index_node, WriteBarrierMode barrier_mode, int additional_offset, ParameterMode parameter_mode) { + CSA_SLOW_ASSERT(this, + Word32Or(IsFixedArray(object), IsPropertyArray(object))); + CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, parameter_mode)); DCHECK(barrier_mode == SKIP_WRITE_BARRIER || barrier_mode == UPDATE_WRITE_BARRIER); + STATIC_ASSERT(FixedArray::kHeaderSize == PropertyArray::kHeaderSize); int header_size = FixedArray::kHeaderSize + additional_offset - kHeapObjectTag; - Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, + Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS, parameter_mode, header_size); if (barrier_mode == SKIP_WRITE_BARRIER) { return StoreNoWriteBarrier(MachineRepresentation::kTagged, object, offset, @@ -1559,8 +1547,9 @@ Node* CodeStubAssembler::StoreFixedArrayElement(Node* object, Node* index_node, Node* CodeStubAssembler::StoreFixedDoubleArrayElement( Node* object, Node* index_node, Node* value, ParameterMode parameter_mode) { CSA_ASSERT(this, IsFixedDoubleArray(object)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, parameter_mode)); Node* offset = - ElementOffsetFromIndex(index_node, FAST_DOUBLE_ELEMENTS, parameter_mode, + ElementOffsetFromIndex(index_node, PACKED_DOUBLE_ELEMENTS, parameter_mode, FixedArray::kHeaderSize - kHeapObjectTag); MachineRepresentation rep = MachineRepresentation::kFloat64; return StoreNoWriteBarrier(rep, object, offset, value); @@ -1620,6 +1609,7 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, CodeStubArguments& args, Variable& arg_index, Label* bailout) { + CSA_SLOW_ASSERT(this, IsJSArray(array)); Comment("BuildAppendJSArray: %s", ElementsKindToString(kind)); Label pre_bailout(this); Label success(this); @@ -1672,24 +1662,25 @@ void CodeStubAssembler::TryStoreArrayElement(ElementsKind kind, ParameterMode mode, Label* bailout, Node* elements, Node* index, Node* value) { - if (IsFastSmiElementsKind(kind)) { + if (IsSmiElementsKind(kind)) { GotoIf(TaggedIsNotSmi(value), bailout); - } else if (IsFastDoubleElementsKind(kind)) { + } else if (IsDoubleElementsKind(kind)) { GotoIfNotNumber(value, bailout); } - if (IsFastDoubleElementsKind(kind)) { + if (IsDoubleElementsKind(kind)) { Node* double_value = ChangeNumberToFloat64(value); StoreFixedDoubleArrayElement(elements, index, Float64SilenceNaN(double_value), mode); } else { WriteBarrierMode barrier_mode = - IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; + IsSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; StoreFixedArrayElement(elements, index, value, barrier_mode, 0, mode); } } void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, Node* value, Label* bailout) { + CSA_SLOW_ASSERT(this, IsJSArray(array)); Comment("BuildAppendJSArray: %s", ElementsKindToString(kind)); ParameterMode mode = OptimalParameterMode(); VARIABLE(var_length, OptimalParameterRepresentation(), @@ -1711,6 +1702,31 @@ void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); } +Node* CodeStubAssembler::AllocateCellWithValue(Node* value, + WriteBarrierMode mode) { + Node* result = Allocate(Cell::kSize, kNone); + StoreMapNoWriteBarrier(result, Heap::kCellMapRootIndex); + StoreCellValue(result, value, mode); + return result; +} + +Node* CodeStubAssembler::LoadCellValue(Node* cell) { + CSA_SLOW_ASSERT(this, HasInstanceType(cell, CELL_TYPE)); + return LoadObjectField(cell, Cell::kValueOffset); +} + +Node* CodeStubAssembler::StoreCellValue(Node* cell, Node* value, + WriteBarrierMode mode) { + CSA_SLOW_ASSERT(this, HasInstanceType(cell, CELL_TYPE)); + DCHECK(mode == SKIP_WRITE_BARRIER || mode == UPDATE_WRITE_BARRIER); + + if (mode == UPDATE_WRITE_BARRIER) { + return StoreObjectField(cell, Cell::kValueOffset, value); + } else { + return StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, value); + } +} + Node* CodeStubAssembler::AllocateHeapNumber(MutableMode mode) { Node* result = Allocate(HeapNumber::kSize, kNone); Heap::RootListIndex heap_map_index = @@ -1737,7 +1753,7 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length, DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, - SmiConstant(Smi::FromInt(length))); + SmiConstant(length)); // Initialize both used and unused parts of hash field slot at once. StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, IntPtrConstant(String::kEmptyHashField), @@ -1745,10 +1761,26 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length, return result; } +Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) { + Label out(this); + VARIABLE(var_result, MachineRepresentation::kWord32, Int32Constant(1)); + + GotoIf(WordEqual(object, SmiConstant(0)), &out); + GotoIf(IsFixedArray(object), &out); + + var_result.Bind(Int32Constant(0)); + Goto(&out); + + BIND(&out); + return var_result.value(); +} + Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, ParameterMode mode, AllocationFlags flags) { Comment("AllocateSeqOneByteString"); + CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(length, mode)); VARIABLE(var_result, MachineRepresentation::kTagged); // Compute the SeqOneByteString size and check if it fits into new space. @@ -1808,7 +1840,7 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, - SmiConstant(Smi::FromInt(length))); + SmiConstant(length)); // Initialize both used and unused parts of hash field slot at once. StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, IntPtrConstant(String::kEmptyHashField), @@ -1819,6 +1851,8 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, ParameterMode mode, AllocationFlags flags) { + CSA_SLOW_ASSERT(this, IsFixedArray(context)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(length, mode)); Comment("AllocateSeqTwoByteString"); VARIABLE(var_result, MachineRepresentation::kTagged); @@ -1874,7 +1908,9 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, Node* CodeStubAssembler::AllocateSlicedString( Heap::RootListIndex map_root_index, Node* length, Node* parent, Node* offset) { + CSA_ASSERT(this, IsString(parent)); CSA_ASSERT(this, TaggedIsSmi(length)); + CSA_ASSERT(this, TaggedIsSmi(offset)); Node* result = Allocate(SlicedString::kSize); DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); StoreMapNoWriteBarrier(result, map_root_index); @@ -1907,6 +1943,8 @@ Node* CodeStubAssembler::AllocateConsString(Heap::RootListIndex map_root_index, Node* length, Node* first, Node* second, AllocationFlags flags) { + CSA_ASSERT(this, IsString(first)); + CSA_ASSERT(this, IsString(second)); CSA_ASSERT(this, TaggedIsSmi(length)); Node* result = Allocate(ConsString::kSize, flags); DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); @@ -1946,6 +1984,9 @@ Node* CodeStubAssembler::AllocateTwoByteConsString(Node* length, Node* first, Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left, Node* right, AllocationFlags flags) { + CSA_ASSERT(this, IsFixedArray(context)); + CSA_ASSERT(this, IsString(left)); + CSA_ASSERT(this, IsString(right)); CSA_ASSERT(this, TaggedIsSmi(length)); // Added string can be a cons string. Comment("Allocating ConsString"); @@ -1973,10 +2014,8 @@ Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left, Label two_byte_map(this); VARIABLE(result, MachineRepresentation::kTagged); Label done(this, &result); - GotoIf(Word32NotEqual(Word32And(anded_instance_types, - Int32Constant(kStringEncodingMask | - kOneByteDataHintTag)), - Int32Constant(0)), + GotoIf(IsSetWord32(anded_instance_types, + kStringEncodingMask | kOneByteDataHintTag), &one_byte_map); Branch(Word32NotEqual(Word32And(xored_instance_types, Int32Constant(kStringEncodingMask | @@ -2001,10 +2040,15 @@ Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left, Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, Node* index, Node* input) { - Node* const max_length = - SmiConstant(Smi::FromInt(JSArray::kInitialMaxFastElementArray)); + CSA_ASSERT(this, IsFixedArray(context)); + CSA_ASSERT(this, TaggedIsSmi(index)); + CSA_ASSERT(this, TaggedIsSmi(length)); + CSA_ASSERT(this, IsString(input)); + +#ifdef DEBUG + Node* const max_length = SmiConstant(JSArray::kInitialMaxFastElementArray); CSA_ASSERT(this, SmiLessThanOrEqual(length, max_length)); - USE(max_length); +#endif // DEBUG // Allocate the JSRegExpResult. // TODO(jgruber): Fold JSArray and FixedArray allocations, then remove @@ -2020,7 +2064,7 @@ Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, // Initialize the header before allocating the elements. Node* const empty_array = EmptyFixedArrayConstant(); DCHECK(Heap::RootIsImmortalImmovable(Heap::kEmptyFixedArrayRootIndex)); - StoreObjectFieldNoWriteBarrier(result, JSArray::kPropertiesOffset, + StoreObjectFieldNoWriteBarrier(result, JSArray::kPropertiesOrHashOffset, empty_array); StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset, empty_array); StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset, length); @@ -2030,7 +2074,7 @@ Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, Node* const zero = IntPtrConstant(0); Node* const length_intptr = SmiUntag(length); - const ElementsKind elements_kind = FAST_ELEMENTS; + const ElementsKind elements_kind = PACKED_ELEMENTS; Node* const elements = AllocateFixedArray(elements_kind, length_intptr); StoreObjectField(result, JSArray::kElementsOffset, elements); @@ -2077,8 +2121,6 @@ Node* CodeStubAssembler::AllocateNameDictionaryWithCapacity(Node* capacity) { SmiTag(capacity), SKIP_WRITE_BARRIER); // Initialize Dictionary fields. Node* filler = LoadRoot(Heap::kUndefinedValueRootIndex); - StoreFixedArrayElement(result, NameDictionary::kMaxNumberKeyIndex, filler, - SKIP_WRITE_BARRIER); StoreFixedArrayElement(result, NameDictionary::kNextEnumerationIndexIndex, SmiConstant(PropertyDetails::kInitialIndex), SKIP_WRITE_BARRIER); @@ -2106,7 +2148,7 @@ Node* CodeStubAssembler::CopyNameDictionary(Node* dictionary, large_object_fallback); Node* properties = AllocateNameDictionaryWithCapacity(capacity); Node* length = SmiUntag(LoadFixedArrayBaseLength(dictionary)); - CopyFixedArrayElements(FAST_ELEMENTS, dictionary, properties, length, + CopyFixedArrayElements(PACKED_ELEMENTS, dictionary, properties, length, SKIP_WRITE_BARRIER, INTPTR_PARAMETERS); return properties; } @@ -2125,20 +2167,25 @@ Node* CodeStubAssembler::AllocateJSObjectFromMap(Node* map, Node* properties, void CodeStubAssembler::InitializeJSObjectFromMap(Node* object, Node* map, Node* size, Node* properties, Node* elements) { + CSA_SLOW_ASSERT(this, IsMap(map)); // This helper assumes that the object is in new-space, as guarded by the // check in AllocatedJSObjectFromMap. if (properties == nullptr) { CSA_ASSERT(this, Word32BinaryNot(IsDictionaryMap((map)))); - StoreObjectFieldRoot(object, JSObject::kPropertiesOffset, + StoreObjectFieldRoot(object, JSObject::kPropertiesOrHashOffset, Heap::kEmptyFixedArrayRootIndex); } else { - StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOffset, + CSA_ASSERT(this, Word32Or(Word32Or(IsPropertyArray(properties), + IsDictionary(properties)), + IsEmptyFixedArray(properties))); + StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOrHashOffset, properties); } if (elements == nullptr) { StoreObjectFieldRoot(object, JSObject::kElementsOffset, Heap::kEmptyFixedArrayRootIndex); } else { + CSA_ASSERT(this, IsFixedArray(elements)); StoreObjectFieldNoWriteBarrier(object, JSObject::kElementsOffset, elements); } InitializeJSObjectBody(object, map, size, JSObject::kHeaderSize); @@ -2146,6 +2193,7 @@ void CodeStubAssembler::InitializeJSObjectFromMap(Node* object, Node* map, void CodeStubAssembler::InitializeJSObjectBody(Node* object, Node* map, Node* size, int start_offset) { + CSA_SLOW_ASSERT(this, IsMap(map)); // TODO(cbruni): activate in-object slack tracking machinery. Comment("InitializeJSObjectBody"); Node* filler = LoadRoot(Heap::kUndefinedValueRootIndex); @@ -2175,6 +2223,8 @@ void CodeStubAssembler::StoreFieldsNoWriteBarrier(Node* start_address, Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { Comment("begin allocation of JSArray without elements"); + CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); + CSA_SLOW_ASSERT(this, IsMap(array_map)); int base_size = JSArray::kSize; if (allocation_site != nullptr) { base_size += AllocationMemento::kSize; @@ -2191,6 +2241,8 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ElementsKind kind, Node* array_map, Node* length, Node* allocation_site, Node* capacity, ParameterMode capacity_mode) { Comment("begin allocation of JSArray with elements"); + CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); + CSA_SLOW_ASSERT(this, IsMap(array_map)); int base_size = JSArray::kSize; if (allocation_site != nullptr) { @@ -2217,20 +2269,23 @@ Node* CodeStubAssembler::AllocateUninitializedJSArray(ElementsKind kind, Node* length, Node* allocation_site, Node* size_in_bytes) { + CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); + CSA_SLOW_ASSERT(this, IsMap(array_map)); + // Allocate space for the JSArray and the elements FixedArray in one go. Node* array = AllocateInNewSpace(size_in_bytes); Comment("write JSArray headers"); StoreMapNoWriteBarrier(array, array_map); - CSA_ASSERT(this, TaggedIsSmi(length)); StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); - StoreObjectFieldRoot(array, JSArray::kPropertiesOffset, + StoreObjectFieldRoot(array, JSArray::kPropertiesOrHashOffset, Heap::kEmptyFixedArrayRootIndex); if (allocation_site != nullptr) { - InitializeAllocationMemento(array, JSArray::kSize, allocation_site); + InitializeAllocationMemento(array, IntPtrConstant(JSArray::kSize), + allocation_site); } return array; } @@ -2239,12 +2294,16 @@ Node* CodeStubAssembler::AllocateJSArray(ElementsKind kind, Node* array_map, Node* capacity, Node* length, Node* allocation_site, ParameterMode capacity_mode) { + CSA_SLOW_ASSERT(this, IsMap(array_map)); + CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, capacity_mode)); + Node *array = nullptr, *elements = nullptr; if (IsIntPtrOrSmiConstantZero(capacity)) { // Array is empty. Use the shared empty fixed array instead of allocating a // new one. array = AllocateUninitializedJSArrayWithoutElements(kind, array_map, length, - nullptr); + allocation_site); StoreObjectFieldRoot(array, JSArray::kElementsOffset, Heap::kEmptyFixedArrayRootIndex); } else { @@ -2253,8 +2312,8 @@ Node* CodeStubAssembler::AllocateJSArray(ElementsKind kind, Node* array_map, kind, array_map, length, allocation_site, capacity, capacity_mode); // Setup elements object. Heap::RootListIndex elements_map_index = - IsFastDoubleElementsKind(kind) ? Heap::kFixedDoubleArrayMapRootIndex - : Heap::kFixedArrayMapRootIndex; + IsDoubleElementsKind(kind) ? Heap::kFixedDoubleArrayMapRootIndex + : Heap::kFixedArrayMapRootIndex; DCHECK(Heap::RootIsImmortalImmovable(elements_map_index)); StoreMapNoWriteBarrier(elements, elements_map_index); StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, @@ -2272,13 +2331,15 @@ Node* CodeStubAssembler::AllocateFixedArray(ElementsKind kind, Node* capacity_node, ParameterMode mode, AllocationFlags flags) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity_node, mode)); CSA_ASSERT(this, IntPtrOrSmiGreaterThan(capacity_node, IntPtrOrSmiConstant(0, mode), mode)); Node* total_size = GetFixedArrayAllocationSize(capacity_node, kind, mode); + if (IsDoubleElementsKind(kind)) flags |= kDoubleAlignment; // Allocate both array and elements object, and initialize the JSArray. Node* array = Allocate(total_size, flags); - Heap::RootListIndex map_index = IsFastDoubleElementsKind(kind) + Heap::RootListIndex map_index = IsDoubleElementsKind(kind) ? Heap::kFixedDoubleArrayMapRootIndex : Heap::kFixedArrayMapRootIndex; DCHECK(Heap::RootIsImmortalImmovable(map_index)); @@ -2288,10 +2349,50 @@ Node* CodeStubAssembler::AllocateFixedArray(ElementsKind kind, return array; } +Node* CodeStubAssembler::AllocatePropertyArray(Node* capacity_node, + ParameterMode mode, + AllocationFlags flags) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity_node, mode)); + CSA_ASSERT(this, IntPtrOrSmiGreaterThan(capacity_node, + IntPtrOrSmiConstant(0, mode), mode)); + Node* total_size = GetPropertyArrayAllocationSize(capacity_node, mode); + + Node* array = Allocate(total_size, flags); + Heap::RootListIndex map_index = Heap::kPropertyArrayMapRootIndex; + DCHECK(Heap::RootIsImmortalImmovable(map_index)); + StoreMapNoWriteBarrier(array, map_index); + StoreObjectFieldNoWriteBarrier(array, FixedArray::kLengthOffset, + ParameterToTagged(capacity_node, mode)); + return array; +} + +void CodeStubAssembler::FillPropertyArrayWithUndefined(Node* array, + Node* from_node, + Node* to_node, + ParameterMode mode) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(from_node, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(to_node, mode)); + CSA_SLOW_ASSERT(this, IsPropertyArray(array)); + STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32); + ElementsKind kind = PACKED_ELEMENTS; + Node* value = LoadRoot(Heap::kUndefinedValueRootIndex); + + BuildFastFixedArrayForEach(array, kind, from_node, to_node, + [this, value](Node* array, Node* offset) { + StoreNoWriteBarrier( + MachineRepresentation::kTagged, array, + offset, value); + }, + mode); +} + void CodeStubAssembler::FillFixedArrayWithValue( ElementsKind kind, Node* array, Node* from_node, Node* to_node, Heap::RootListIndex value_root_index, ParameterMode mode) { - bool is_double = IsFastDoubleElementsKind(kind); + CSA_SLOW_ASSERT(this, MatchesParameterMode(from_node, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(to_node, mode)); + CSA_SLOW_ASSERT(this, IsFixedArrayWithKind(array, kind)); + bool is_double = IsDoubleElementsKind(kind); DCHECK(value_root_index == Heap::kTheHoleValueRootIndex || value_root_index == Heap::kUndefinedValueRootIndex); DCHECK_IMPLIES(is_double, value_root_index == Heap::kTheHoleValueRootIndex); @@ -2334,6 +2435,10 @@ void CodeStubAssembler::CopyFixedArrayElements( ElementsKind from_kind, Node* from_array, ElementsKind to_kind, Node* to_array, Node* element_count, Node* capacity, WriteBarrierMode barrier_mode, ParameterMode mode) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(element_count, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, mode)); + CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(from_array, from_kind)); + CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(to_array, to_kind)); STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize); const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag; Comment("[ CopyFixedArrayElements"); @@ -2343,16 +2448,15 @@ void CodeStubAssembler::CopyFixedArrayElements( DCHECK(!IsFixedTypedArrayElementsKind(to_kind)); Label done(this); - bool from_double_elements = IsFastDoubleElementsKind(from_kind); - bool to_double_elements = IsFastDoubleElementsKind(to_kind); - bool element_size_matches = - Is64() || - IsFastDoubleElementsKind(from_kind) == IsFastDoubleElementsKind(to_kind); + bool from_double_elements = IsDoubleElementsKind(from_kind); + bool to_double_elements = IsDoubleElementsKind(to_kind); + bool element_size_matches = Is64() || IsDoubleElementsKind(from_kind) == + IsDoubleElementsKind(to_kind); bool doubles_to_objects_conversion = - IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind); + IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind); bool needs_write_barrier = - doubles_to_objects_conversion || (barrier_mode == UPDATE_WRITE_BARRIER && - IsFastObjectElementsKind(to_kind)); + doubles_to_objects_conversion || + (barrier_mode == UPDATE_WRITE_BARRIER && IsObjectElementsKind(to_kind)); Node* double_hole = Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32); @@ -2410,7 +2514,7 @@ void CodeStubAssembler::CopyFixedArrayElements( // The target elements array is already preinitialized with holes, so we // can just proceed with the next iteration. if_hole = &next_iter; - } else if (IsFastDoubleElementsKind(to_kind)) { + } else if (IsDoubleElementsKind(to_kind)) { if_hole = &store_double_hole; } else { // In all the other cases don't check for holes and copy the data as is. @@ -2460,16 +2564,51 @@ void CodeStubAssembler::CopyFixedArrayElements( } BIND(&done); - IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); Comment("] CopyFixedArrayElements"); } +void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array, + Node* to_array, + Node* property_count, + WriteBarrierMode barrier_mode, + ParameterMode mode) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(property_count, mode)); + CSA_SLOW_ASSERT(this, Word32Or(IsPropertyArray(from_array), + IsEmptyFixedArray(from_array))); + CSA_SLOW_ASSERT(this, IsPropertyArray(to_array)); + Comment("[ CopyPropertyArrayValues"); + + bool needs_write_barrier = barrier_mode == UPDATE_WRITE_BARRIER; + Node* start = IntPtrOrSmiConstant(0, mode); + ElementsKind kind = PACKED_ELEMENTS; + BuildFastFixedArrayForEach( + from_array, kind, start, property_count, + [this, to_array, needs_write_barrier](Node* array, Node* offset) { + Node* value = Load(MachineType::AnyTagged(), array, offset); + + if (needs_write_barrier) { + Store(to_array, offset, value); + } else { + StoreNoWriteBarrier(MachineRepresentation::kTagged, to_array, offset, + value); + } + }, + mode); + Comment("] CopyPropertyArrayValues"); +} + void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string, Node* from_index, Node* to_index, Node* character_count, String::Encoding from_encoding, String::Encoding to_encoding, ParameterMode mode) { + // Cannot assert IsString(from_string) and IsString(to_string) here because + // CSA::SubString can pass in faked sequential strings when handling external + // subject strings. + CSA_SLOW_ASSERT(this, MatchesParameterMode(character_count, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(from_index, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(to_index, mode)); 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); @@ -2528,10 +2667,11 @@ Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, ElementsKind from_kind, ElementsKind to_kind, Label* if_hole) { - if (IsFastDoubleElementsKind(from_kind)) { + CSA_SLOW_ASSERT(this, IsFixedArrayWithKind(array, from_kind)); + if (IsDoubleElementsKind(from_kind)) { Node* value = LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); - if (!IsFastDoubleElementsKind(to_kind)) { + if (!IsDoubleElementsKind(to_kind)) { value = AllocateHeapNumberWithValue(value); } return value; @@ -2541,8 +2681,8 @@ Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, if (if_hole) { GotoIf(WordEqual(value, TheHoleConstant()), if_hole); } - if (IsFastDoubleElementsKind(to_kind)) { - if (IsFastSmiElementsKind(from_kind)) { + if (IsDoubleElementsKind(to_kind)) { + if (IsSmiElementsKind(from_kind)) { value = SmiToFloat64(value); } else { value = LoadHeapNumberValue(value); @@ -2554,6 +2694,7 @@ Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity, ParameterMode mode) { + CSA_SLOW_ASSERT(this, MatchesParameterMode(old_capacity, mode)); Node* half_old_capacity = WordOrSmiShr(old_capacity, 1, mode); Node* new_capacity = IntPtrOrSmiAdd(half_old_capacity, old_capacity, mode); Node* padding = IntPtrOrSmiConstant(16, mode); @@ -2563,6 +2704,9 @@ Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity, Node* 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)); Node* capacity = LoadFixedArrayBaseLength(elements); ParameterMode mode = OptimalParameterMode(); @@ -2579,6 +2723,10 @@ Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements, ParameterMode mode, Label* bailout) { Comment("TryGrowElementsCapacity"); + CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); + CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(elements, kind)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(key, mode)); // If the gap growth is too big, fall back to the runtime. Node* max_gap = IntPtrOrSmiConstant(JSObject::kMaxGap, mode); @@ -2596,6 +2744,11 @@ Node* CodeStubAssembler::GrowElementsCapacity( Node* object, Node* elements, ElementsKind from_kind, ElementsKind to_kind, Node* capacity, Node* new_capacity, ParameterMode mode, Label* bailout) { Comment("[ GrowElementsCapacity"); + CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); + CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(elements, from_kind)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(new_capacity, mode)); + // If size of the allocation for the new capacity doesn't fit in a page // that we can bump-pointer allocate from, fall back to the runtime. int max_size = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(to_kind); @@ -2617,24 +2770,23 @@ Node* CodeStubAssembler::GrowElementsCapacity( return new_elements; } -void CodeStubAssembler::InitializeAllocationMemento(Node* base_allocation, - int base_allocation_size, +void CodeStubAssembler::InitializeAllocationMemento(Node* base, + Node* base_allocation_size, Node* allocation_site) { + Comment("[Initialize AllocationMemento"); + Node* memento = InnerAllocate(base, base_allocation_size); + StoreMapNoWriteBarrier(memento, Heap::kAllocationMementoMapRootIndex); StoreObjectFieldNoWriteBarrier( - base_allocation, AllocationMemento::kMapOffset + base_allocation_size, - HeapConstant(Handle<Map>(isolate()->heap()->allocation_memento_map()))); - StoreObjectFieldNoWriteBarrier( - base_allocation, - AllocationMemento::kAllocationSiteOffset + base_allocation_size, - allocation_site); + memento, AllocationMemento::kAllocationSiteOffset, allocation_site); if (FLAG_allocation_site_pretenuring) { Node* count = LoadObjectField(allocation_site, AllocationSite::kPretenureCreateCountOffset); - Node* incremented_count = SmiAdd(count, SmiConstant(Smi::FromInt(1))); + Node* incremented_count = SmiAdd(count, SmiConstant(1)); StoreObjectFieldNoWriteBarrier(allocation_site, AllocationSite::kPretenureCreateCountOffset, incremented_count); } + Comment("]"); } Node* CodeStubAssembler::TryTaggedToFloat64(Node* value, @@ -2657,8 +2809,7 @@ Node* CodeStubAssembler::TryTaggedToFloat64(Node* value, { // Check if {value} is a HeapNumber. Label if_valueisheapnumber(this); - Branch(IsHeapNumberMap(LoadMap(value)), &if_valueisheapnumber, - if_valueisnotnumber); + Branch(IsHeapNumber(value), &if_valueisheapnumber, if_valueisnotnumber); BIND(&if_valueisheapnumber); { @@ -2694,8 +2845,7 @@ Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) { BIND(&if_valueisnotnumber); { // Convert the {value} to a Number first. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_value.Bind(CallStub(callable, context, value)); + var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value)); Goto(&loop); } } @@ -2730,7 +2880,7 @@ Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) { // Check if {value} is a HeapNumber. Label if_valueisheapnumber(this), if_valueisnotheapnumber(this, Label::kDeferred); - Branch(IsHeapNumberMap(LoadMap(value)), &if_valueisheapnumber, + Branch(IsHeapNumber(value), &if_valueisheapnumber, &if_valueisnotheapnumber); BIND(&if_valueisheapnumber); @@ -2743,8 +2893,8 @@ Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) { BIND(&if_valueisnotheapnumber); { // Convert the {value} to a Number first. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_value.Bind(CallStub(callable, context, value)); + var_value.Bind( + CallBuiltin(Builtins::kNonNumberToNumber, context, value)); Goto(&loop); } } @@ -2903,8 +3053,7 @@ Node* CodeStubAssembler::ToThisString(Node* context, Node* value, BIND(&if_valueisnotnullorundefined); { // Convert the {value} to a String. - Callable callable = CodeFactory::ToString(isolate()); - var_value.Bind(CallStub(callable, context, value)); + var_value.Bind(CallBuiltin(Builtins::kToString, context, value)); Goto(&if_valueisstring); } } @@ -2913,8 +3062,7 @@ Node* CodeStubAssembler::ToThisString(Node* context, Node* value, { // The {value} is either null or undefined. CallRuntime(Runtime::kThrowCalledOnNullOrUndefined, context, - HeapConstant(factory()->NewStringFromAsciiChecked( - method_name, TENURED))); + StringConstant(method_name)); Unreachable(); } } @@ -2931,6 +3079,7 @@ Node* CodeStubAssembler::ToThisString(Node* context, Node* value, } Node* CodeStubAssembler::ChangeNumberToFloat64(Node* value) { + CSA_SLOW_ASSERT(this, IsNumber(value)); VARIABLE(result, MachineRepresentation::kFloat64); Label smi(this); Label done(this, &result); @@ -2950,6 +3099,7 @@ Node* CodeStubAssembler::ChangeNumberToFloat64(Node* value) { } Node* CodeStubAssembler::ChangeNumberToIntPtr(Node* value) { + CSA_SLOW_ASSERT(this, IsNumber(value)); VARIABLE(result, MachineType::PointerRepresentation()); Label smi(this), done(this, &result); GotoIf(TaggedIsSmi(value), &smi); @@ -2988,7 +3138,7 @@ Node* CodeStubAssembler::ToThisValue(Node* context, Node* value, ? &done_loop : &done_throw); - // Load the mape of the {value}. + // Load the map of the {value}. Node* value_map = LoadMap(value); // Load the instance type of the {value}. @@ -3013,16 +3163,13 @@ Node* CodeStubAssembler::ToThisValue(Node* context, Node* value, GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop); break; case PrimitiveType::kNumber: - GotoIf( - Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), - &done_loop); + GotoIf(WordEqual(value_map, HeapNumberMapConstant()), &done_loop); break; case PrimitiveType::kString: GotoIf(IsStringInstanceType(value_instance_type), &done_loop); break; case PrimitiveType::kSymbol: - GotoIf(Word32Equal(value_instance_type, Int32Constant(SYMBOL_TYPE)), - &done_loop); + GotoIf(WordEqual(value_map, SymbolMapConstant()), &done_loop); break; } Goto(&done_throw); @@ -3049,16 +3196,22 @@ Node* CodeStubAssembler::ToThisValue(Node* context, Node* value, CHECK_NOT_NULL(primitive_name); // The {value} is not a compatible receiver for this method. - CallRuntime(Runtime::kThrowTypeError, context, - SmiConstant(MessageTemplate::kNotGeneric), - CStringConstant(method_name), CStringConstant(primitive_name)); - Unreachable(); + ThrowTypeError(context, MessageTemplate::kNotGeneric, method_name, + primitive_name); } BIND(&done_loop); return var_value.value(); } +void CodeStubAssembler::ThrowIncompatibleMethodReceiver(Node* context, + const char* method_name, + Node* receiver) { + CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, + StringConstant(method_name), receiver); + Unreachable(); +} + Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value, InstanceType instance_type, char const* method_name) { @@ -3076,21 +3229,45 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value, // The {value} is not a compatible receiver for this method. BIND(&throw_exception); - CallRuntime( - Runtime::kThrowIncompatibleMethodReceiver, context, - HeapConstant(factory()->NewStringFromAsciiChecked(method_name, TENURED)), - value); - Unreachable(); + ThrowIncompatibleMethodReceiver(context, method_name, value); BIND(&out); return var_value_map.value(); } +void CodeStubAssembler::ThrowTypeError(Node* context, + MessageTemplate::Template message, + char const* arg0, char const* arg1) { + Node* arg0_node = nullptr; + if (arg0) arg0_node = StringConstant(arg0); + Node* arg1_node = nullptr; + if (arg1) arg1_node = StringConstant(arg1); + ThrowTypeError(context, message, arg0_node, arg1_node); +} + +void CodeStubAssembler::ThrowTypeError(Node* context, + MessageTemplate::Template message, + Node* arg0, Node* arg1, Node* arg2) { + Node* template_index = SmiConstant(message); + if (arg0 == nullptr) { + CallRuntime(Runtime::kThrowTypeError, context, template_index); + } else if (arg1 == nullptr) { + CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0); + } else if (arg2 == nullptr) { + CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0, arg1); + } else { + CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0, arg1, + arg2); + } + Unreachable(); +} + Node* CodeStubAssembler::InstanceTypeEqual(Node* instance_type, int type) { return Word32Equal(instance_type, Int32Constant(type)); } Node* CodeStubAssembler::IsSpecialReceiverMap(Node* map) { + CSA_SLOW_ASSERT(this, IsMap(map)); Node* is_special = IsSpecialReceiverInstanceType(LoadMapInstanceType(map)); uint32_t mask = 1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded; @@ -3105,15 +3282,12 @@ Node* CodeStubAssembler::IsSpecialReceiverMap(Node* map) { Node* CodeStubAssembler::IsDictionaryMap(Node* map) { CSA_SLOW_ASSERT(this, IsMap(map)); Node* bit_field3 = LoadMapBitField3(map); - return Word32NotEqual(IsSetWord32<Map::DictionaryMap>(bit_field3), - Int32Constant(0)); + return IsSetWord32<Map::DictionaryMap>(bit_field3); } Node* CodeStubAssembler::IsCallableMap(Node* map) { CSA_ASSERT(this, IsMap(map)); - return Word32NotEqual( - Word32And(LoadMapBitField(map), Int32Constant(1 << Map::kIsCallable)), - Int32Constant(0)); + return IsSetWord32(LoadMapBitField(map), 1 << Map::kIsCallable); } Node* CodeStubAssembler::IsDeprecatedMap(Node* map) { @@ -3121,15 +3295,22 @@ Node* CodeStubAssembler::IsDeprecatedMap(Node* map) { return IsSetWord32<Map::Deprecated>(LoadMapBitField3(map)); } +Node* CodeStubAssembler::IsUndetectableMap(Node* map) { + CSA_ASSERT(this, IsMap(map)); + return IsSetWord32(LoadMapBitField(map), 1 << Map::kIsUndetectable); +} + Node* CodeStubAssembler::IsCallable(Node* object) { return IsCallableMap(LoadMap(object)); } Node* CodeStubAssembler::IsConstructorMap(Node* map) { CSA_ASSERT(this, IsMap(map)); - return Word32NotEqual( - Word32And(LoadMapBitField(map), Int32Constant(1 << Map::kIsConstructor)), - Int32Constant(0)); + return IsSetWord32(LoadMapBitField(map), 1 << Map::kIsConstructor); +} + +Node* CodeStubAssembler::IsConstructor(Node* object) { + return IsConstructorMap(LoadMap(object)); } Node* CodeStubAssembler::IsSpecialReceiverInstanceType(Node* instance_type) { @@ -3182,9 +3363,7 @@ Node* CodeStubAssembler::IsShortExternalStringInstanceType( Node* instance_type) { CSA_ASSERT(this, IsStringInstanceType(instance_type)); STATIC_ASSERT(kShortExternalStringTag != 0); - return Word32NotEqual( - Word32And(instance_type, Int32Constant(kShortExternalStringMask)), - Int32Constant(0)); + return IsSetWord32(instance_type, kShortExternalStringMask); } Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { @@ -3212,14 +3391,19 @@ Node* CodeStubAssembler::IsJSObject(Node* object) { return IsJSObjectMap(LoadMap(object)); } +Node* CodeStubAssembler::IsJSProxy(Node* object) { + Node* object_map = LoadMap(object); + Node* object_instance_type = LoadMapInstanceType(object_map); + + return InstanceTypeEqual(object_instance_type, JS_PROXY_TYPE); +} + Node* CodeStubAssembler::IsJSGlobalProxy(Node* object) { return Word32Equal(LoadInstanceType(object), Int32Constant(JS_GLOBAL_PROXY_TYPE)); } -Node* CodeStubAssembler::IsMap(Node* map) { - return HasInstanceType(map, MAP_TYPE); -} +Node* CodeStubAssembler::IsMap(Node* map) { return IsMetaMap(LoadMap(map)); } Node* CodeStubAssembler::IsJSValueInstanceType(Node* instance_type) { return Word32Equal(instance_type, Int32Constant(JS_VALUE_TYPE)); @@ -3245,6 +3429,49 @@ Node* CodeStubAssembler::IsJSArrayMap(Node* map) { return IsJSArrayInstanceType(LoadMapInstanceType(map)); } +Node* CodeStubAssembler::IsFixedArray(Node* object) { + return HasInstanceType(object, FIXED_ARRAY_TYPE); +} + +Node* CodeStubAssembler::IsPropertyArray(Node* object) { + return HasInstanceType(object, PROPERTY_ARRAY_TYPE); +} + +// This complicated check is due to elements oddities. If a smi array is empty +// after Array.p.shift, it is replaced by the empty array constant. If it is +// later filled with a double element, we try to grow it but pass in a double +// elements kind. Usually this would cause a size mismatch (since the source +// fixed array has HOLEY_ELEMENTS and destination has +// HOLEY_DOUBLE_ELEMENTS), but we don't have to worry about it when the +// source array is empty. +// TODO(jgruber): It might we worth creating an empty_double_array constant to +// simplify this case. +Node* CodeStubAssembler::IsFixedArrayWithKindOrEmpty(Node* object, + ElementsKind kind) { + Label out(this); + VARIABLE(var_result, MachineRepresentation::kWord32, Int32Constant(1)); + + GotoIf(IsFixedArrayWithKind(object, kind), &out); + + Node* const length = LoadFixedArrayBaseLength(object); + GotoIf(SmiEqual(length, SmiConstant(0)), &out); + + var_result.Bind(Int32Constant(0)); + Goto(&out); + + BIND(&out); + return var_result.value(); +} + +Node* CodeStubAssembler::IsFixedArrayWithKind(Node* object, ElementsKind kind) { + if (IsDoubleElementsKind(kind)) { + return IsFixedDoubleArray(object); + } else { + DCHECK(IsSmiOrObjectElementsKind(kind)); + return IsFixedArray(object); + } +} + Node* CodeStubAssembler::IsWeakCell(Node* object) { return IsWeakCellMap(LoadMap(object)); } @@ -3265,10 +3492,22 @@ Node* CodeStubAssembler::IsAccessorPair(Node* object) { return IsAccessorPairMap(LoadMap(object)); } +Node* CodeStubAssembler::IsAllocationSite(Node* object) { + return IsAllocationSiteMap(LoadMap(object)); +} + +Node* CodeStubAssembler::IsAnyHeapNumber(Node* object) { + return Word32Or(IsMutableHeapNumber(object), IsHeapNumber(object)); +} + Node* CodeStubAssembler::IsHeapNumber(Node* object) { return IsHeapNumberMap(LoadMap(object)); } +Node* CodeStubAssembler::IsMutableHeapNumber(Node* object) { + return IsMutableHeapNumberMap(LoadMap(object)); +} + Node* CodeStubAssembler::IsFeedbackVector(Node* object) { return IsFeedbackVectorMap(LoadMap(object)); } @@ -3283,6 +3522,10 @@ Node* CodeStubAssembler::IsString(Node* object) { Int32Constant(FIRST_NONSTRING_TYPE)); } +Node* CodeStubAssembler::IsSymbolInstanceType(Node* instance_type) { + return Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE)); +} + Node* CodeStubAssembler::IsSymbol(Node* object) { return IsSymbolMap(LoadMap(object)); } @@ -3396,7 +3639,7 @@ Node* CodeStubAssembler::IsNumberPositive(Node* number) { Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, ParameterMode parameter_mode) { - if (parameter_mode == SMI_PARAMETERS) CSA_ASSERT(this, TaggedIsSmi(index)); + CSA_ASSERT(this, MatchesParameterMode(index, parameter_mode)); CSA_ASSERT(this, IsString(string)); // Translate the {index} into a Word. @@ -3508,6 +3751,7 @@ Node* CodeStubAssembler::StringFromCharCode(Node* code) { } BIND(&if_done); + CSA_ASSERT(this, IsString(var_result.value())); return var_result.value(); } @@ -3524,7 +3768,7 @@ Node* CodeStubAssembler::AllocAndCopyStringCharacters(Node* context, Node* from, Label end(this), one_byte_sequential(this), two_byte_sequential(this); Variable var_result(this, MachineRepresentation::kTagged); - Node* const smi_zero = SmiConstant(Smi::kZero); + Node* const smi_zero = SmiConstant(0); Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential, &two_byte_sequential); @@ -3594,7 +3838,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, // A real substring (substr_length < string_length). Label single_char(this); - GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); + GotoIf(SmiEqual(substr_length, SmiConstant(1)), &single_char); // TODO(jgruber): Add an additional case for substring of length == 0? @@ -3613,8 +3857,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, Label next(this); // Short slice. Copy instead of slicing. - GotoIf(SmiLessThan(substr_length, - SmiConstant(Smi::FromInt(SlicedString::kMinLength))), + GotoIf(SmiLessThan(substr_length, SmiConstant(SlicedString::kMinLength)), &next); // Allocate new sliced string. @@ -3690,7 +3933,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, } // Equal length - check if {from, to} == {0, str.length}. - GotoIf(SmiAbove(from, SmiConstant(Smi::kZero)), &runtime); + GotoIf(SmiAbove(from, SmiConstant(0)), &runtime); // Return the original string (substr_length == string_length). @@ -3710,6 +3953,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, } BIND(&end); + CSA_ASSERT(this, IsString(var_result.value())); return var_result.value(); } @@ -3857,47 +4101,52 @@ Node* ToDirectStringAssembler::TryToSequential(StringPointerKind ptr_kind, return var_result.value(); } -Node* CodeStubAssembler::TryDerefExternalString(Node* const string, - Node* const instance_type, - Label* if_bailout) { - Label out(this); - - CSA_ASSERT(this, IsExternalStringInstanceType(instance_type)); - GotoIf(IsShortExternalStringInstanceType(instance_type), if_bailout); - - // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - - Node* resource_data = LoadObjectField( - string, ExternalString::kResourceDataOffset, MachineType::Pointer()); - Node* const fake_sequential_string = - IntPtrSub(resource_data, - IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - return fake_sequential_string; -} - -void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string, - Node* instance_type, - Variable* var_did_something) { - Label deref(this), done(this, var_did_something); +void CodeStubAssembler::BranchIfCanDerefIndirectString(Node* string, + Node* instance_type, + Label* can_deref, + Label* cannot_deref) { + CSA_ASSERT(this, IsString(string)); Node* representation = Word32And(instance_type, Int32Constant(kStringRepresentationMask)); - GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), &deref); - GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), &done); + GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), can_deref); + GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), + cannot_deref); // Cons string. - Node* rhs = LoadObjectField(var_string->value(), ConsString::kSecondOffset); - GotoIf(WordEqual(rhs, EmptyStringConstant()), &deref); - Goto(&done); + Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); + GotoIf(IsEmptyString(rhs), can_deref); + Goto(cannot_deref); +} + +void CodeStubAssembler::DerefIndirectString(Variable* var_string, + Node* 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 - BIND(&deref); STATIC_ASSERT(ThinString::kActualOffset == ConsString::kFirstOffset); var_string->Bind( LoadObjectField(var_string->value(), ThinString::kActualOffset)); - var_did_something->Bind(IntPtrConstant(1)); - Goto(&done); +} - BIND(&done); +void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string, + Node* 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(Variable* var_left, @@ -3905,13 +4154,24 @@ void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left, Variable* var_right, Node* right_instance_type, Label* did_something) { - VARIABLE(var_did_something, MachineType::PointerRepresentation(), - IntPtrConstant(0)); - MaybeDerefIndirectString(var_left, left_instance_type, &var_did_something); - MaybeDerefIndirectString(var_right, right_instance_type, &var_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); - GotoIf(WordNotEqual(var_did_something.value(), IntPtrConstant(0)), - did_something); + 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. } @@ -3938,6 +4198,10 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, CSA_ASSERT(this, TaggedIsSmi(left_length)); CSA_ASSERT(this, TaggedIsSmi(right_length)); Node* new_length = SmiAdd(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(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)), &runtime); @@ -3966,14 +4230,8 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, Word32Xor(left_instance_type, right_instance_type); // Check if both strings have the same encoding and both are sequential. - GotoIf(Word32NotEqual(Word32And(xored_instance_types, - Int32Constant(kStringEncodingMask)), - Int32Constant(0)), - &runtime); - GotoIf(Word32NotEqual(Word32And(ored_instance_types, - Int32Constant(kStringRepresentationMask)), - Int32Constant(0)), - &slow); + GotoIf(IsSetWord32(xored_instance_types, kStringEncodingMask), &runtime); + GotoIf(IsSetWord32(ored_instance_types, kStringRepresentationMask), &slow); Label two_byte(this); GotoIf(Word32Equal(Word32And(ored_instance_types, @@ -3983,11 +4241,10 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, // One-byte sequential string case Node* new_string = AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS); - CopyStringCharacters(var_left.value(), new_string, SmiConstant(Smi::kZero), - SmiConstant(Smi::kZero), left_length, - String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, - SMI_PARAMETERS); - CopyStringCharacters(var_right.value(), new_string, SmiConstant(Smi::kZero), + CopyStringCharacters(var_left.value(), new_string, SmiConstant(0), + SmiConstant(0), left_length, String::ONE_BYTE_ENCODING, + String::ONE_BYTE_ENCODING, SMI_PARAMETERS); + CopyStringCharacters(var_right.value(), new_string, SmiConstant(0), left_length, right_length, String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, SMI_PARAMETERS); result.Bind(new_string); @@ -3998,14 +4255,13 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, // Two-byte sequential string case new_string = AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS); - CopyStringCharacters(var_left.value(), new_string, - SmiConstant(Smi::kZero), SmiConstant(Smi::kZero), - left_length, String::TWO_BYTE_ENCODING, - String::TWO_BYTE_ENCODING, SMI_PARAMETERS); - CopyStringCharacters(var_right.value(), new_string, - SmiConstant(Smi::kZero), left_length, right_length, + CopyStringCharacters(var_left.value(), new_string, SmiConstant(0), + SmiConstant(0), left_length, String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, SMI_PARAMETERS); + CopyStringCharacters(var_right.value(), new_string, SmiConstant(0), + left_length, right_length, String::TWO_BYTE_ENCODING, + String::TWO_BYTE_ENCODING, SMI_PARAMETERS); result.Bind(new_string); Goto(&done_native); } @@ -4082,10 +4338,12 @@ Node* CodeStubAssembler::StringFromCodePoint(Node* codepoint, } BIND(&return_result); + CSA_ASSERT(this, IsString(var_result.value())); return var_result.value(); } Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { + CSA_SLOW_ASSERT(this, IsString(input)); Label runtime(this, Label::kDeferred); Label end(this); @@ -4093,9 +4351,8 @@ Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { // Check if string has a cached array index. Node* hash = LoadNameHashField(input); - Node* bit = - Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask)); - GotoIf(Word32NotEqual(bit, Int32Constant(0)), &runtime); + GotoIf(IsSetWord32(hash, Name::kDoesNotContainCachedArrayIndexMask), + &runtime); var_result.Bind( SmiTag(DecodeWordFromWord32<String::ArrayIndexValueBits>(hash))); @@ -4129,8 +4386,7 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) { GotoIf(TaggedIsSmi(argument), &smi); // Argument isn't smi, check to see if it's a heap-number. - Node* map = LoadMap(argument); - GotoIfNot(IsHeapNumberMap(map), &runtime); + GotoIfNot(IsHeapNumber(argument), &runtime); // Make a hash from the two 32-bit values of the double. Node* low = @@ -4140,13 +4396,12 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) { Node* hash = Word32Xor(low, high); hash = ChangeInt32ToIntPtr(hash); hash = WordShl(hash, one); - Node* index = WordAnd(hash, SmiUntag(BitcastWordToTagged(mask))); + Node* index = WordAnd(hash, WordSar(mask, SmiShiftBitsConstant())); // Cache entry's key must be a heap number Node* number_key = LoadFixedArrayElement(number_string_cache, index); GotoIf(TaggedIsSmi(number_key), &runtime); - map = LoadMap(number_key); - GotoIfNot(IsHeapNumberMap(map), &runtime); + GotoIfNot(IsHeapNumber(number_key), &runtime); // Cache entry's key must match the heap number value we're looking for. Node* low_compare = LoadObjectField(number_key, HeapNumber::kValueOffset, @@ -4185,6 +4440,7 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) { } BIND(&done); + CSA_ASSERT(this, IsString(result.value())); return result.value(); } @@ -4231,13 +4487,14 @@ Node* CodeStubAssembler::ToName(Node* context, Node* value) { } BIND(&end); + CSA_ASSERT(this, IsName(var_result.value())); return var_result.value(); } Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { // Assert input is a HeapObject (not smi or heap number) CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(input))); - CSA_ASSERT(this, Word32BinaryNot(IsHeapNumberMap(LoadMap(input)))); + CSA_ASSERT(this, Word32BinaryNot(IsHeapNumber(input))); // We might need to loop once here due to ToPrimitive conversions. VARIABLE(var_input, MachineRepresentation::kTagged, input); @@ -4286,9 +4543,7 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { // Check if the {result} is already a Number. Label if_resultisnumber(this), if_resultisnotnumber(this); GotoIf(TaggedIsSmi(result), &if_resultisnumber); - Node* result_map = LoadMap(result); - Branch(IsHeapNumberMap(result_map), &if_resultisnumber, - &if_resultisnotnumber); + Branch(IsHeapNumber(result), &if_resultisnumber, &if_resultisnotnumber); BIND(&if_resultisnumber); { @@ -4319,6 +4574,7 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { } BIND(&end); + CSA_ASSERT(this, IsNumber(var_result.value())); return var_result.value(); } @@ -4334,8 +4590,7 @@ Node* CodeStubAssembler::ToNumber(Node* context, Node* input) { BIND(¬_smi); { Label not_heap_number(this, Label::kDeferred); - Node* input_map = LoadMap(input); - GotoIfNot(IsHeapNumberMap(input_map), ¬_heap_number); + GotoIfNot(IsHeapNumber(input), ¬_heap_number); var_result.Bind(input); Goto(&end); @@ -4348,6 +4603,7 @@ Node* CodeStubAssembler::ToNumber(Node* context, Node* input) { } BIND(&end); + CSA_ASSERT(this, IsNumber(var_result.value())); return var_result.value(); } @@ -4444,21 +4700,20 @@ Node* CodeStubAssembler::ToUint32(Node* context, Node* input) { BIND(&return_zero); { - var_result.Bind(SmiConstant(Smi::kZero)); + var_result.Bind(SmiConstant(0)); Goto(&out); } } BIND(&out); + CSA_ASSERT(this, IsNumber(var_result.value())); return var_result.value(); } Node* CodeStubAssembler::ToString(Node* context, Node* input) { Label is_number(this); - Label runtime(this, Label::kDeferred); + Label runtime(this, Label::kDeferred), done(this); VARIABLE(result, MachineRepresentation::kTagged); - Label done(this, &result); - GotoIf(TaggedIsSmi(input), &is_number); Node* input_map = LoadMap(input); @@ -4558,6 +4813,7 @@ Node* CodeStubAssembler::ToSmiIndex(Node* const input, Node* const context, Goto(&done); BIND(&done); + CSA_SLOW_ASSERT(this, TaggedIsSmi(result.value())); return result.value(); } @@ -4570,9 +4826,11 @@ Node* CodeStubAssembler::ToSmiLength(Node* input, Node* const context, BIND(&to_integer); result.Bind(ToInteger(context, result.value(), CodeStubAssembler::kTruncateMinusZero)); - GotoIfNot(TaggedIsSmi(result.value()), range_error); - CSA_ASSERT(this, TaggedIsSmi(result.value())); - Goto(&negative_check); + GotoIf(TaggedIsSmi(result.value()), &negative_check); + // result.value() can still be a negative HeapNumber here. + Branch(IsTrue(CallBuiltin(Builtins::kLessThan, context, result.value(), + SmiConstant(0))), + &return_zero, range_error); BIND(&negative_check); Branch(SmiLessThan(result.value(), SmiConstant(0)), &return_zero, &done); @@ -4582,6 +4840,7 @@ Node* CodeStubAssembler::ToSmiLength(Node* input, Node* const context, Goto(&done); BIND(&done); + CSA_SLOW_ASSERT(this, TaggedIsSmi(result.value())); return result.value(); } @@ -4614,8 +4873,7 @@ Node* CodeStubAssembler::ToInteger(Node* context, Node* input, // Check if {arg} is a HeapNumber. Label if_argisheapnumber(this), if_argisnotheapnumber(this, Label::kDeferred); - Branch(IsHeapNumberMap(LoadMap(arg)), &if_argisheapnumber, - &if_argisnotheapnumber); + Branch(IsHeapNumber(arg), &if_argisheapnumber, &if_argisnotheapnumber); BIND(&if_argisheapnumber); { @@ -4640,17 +4898,17 @@ Node* CodeStubAssembler::ToInteger(Node* context, Node* input, BIND(&if_argisnotheapnumber); { // Need to convert {arg} to a Number first. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_arg.Bind(CallStub(callable, context, arg)); + var_arg.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, arg)); Goto(&loop); } BIND(&return_zero); - var_arg.Bind(SmiConstant(Smi::kZero)); + var_arg.Bind(SmiConstant(0)); Goto(&out); } BIND(&out); + CSA_SLOW_ASSERT(this, IsNumber(var_arg.value())); return var_arg.value(); } @@ -4731,14 +4989,11 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, GotoIfNot(IsStringInstanceType(key_instance_type), if_bailout); // |key| is a String. Check if it has a cached array index. Node* hash = LoadNameHashField(key); - Node* contains_index = - Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); - GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); + 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. - Node* not_an_index = - Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); - GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); + GotoIf(IsClearWord32(hash, Name::kIsNotArrayIndexMask), if_bailout); // Check if we have a ThinString. GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)), &if_thinstring); @@ -4747,9 +5002,7 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, &if_thinstring); // Finally, check if |key| is internalized. STATIC_ASSERT(kNotInternalizedTag != 0); - Node* not_internalized = - Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); - GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), + GotoIf(IsSetWord32(key_instance_type, kIsNotInternalizedMask), if_notinternalized != nullptr ? if_notinternalized : if_bailout); Goto(if_keyisunique); @@ -4767,6 +5020,7 @@ void CodeStubAssembler::TryInternalizeString( Variable* var_internalized, Label* if_not_internalized, Label* if_bailout) { DCHECK(var_index->rep() == MachineType::PointerRepresentation()); DCHECK(var_internalized->rep() == MachineRepresentation::kTagged); + CSA_SLOW_ASSERT(this, IsString(string)); Node* function = ExternalConstant( ExternalReference::try_internalize_string_function(isolate())); Node* result = CallCFunction1(MachineType::AnyTagged(), @@ -4828,6 +5082,19 @@ void CodeStubAssembler::SetNextEnumerationIndex(Node* dictionary, next_enum_index_smi, SKIP_WRITE_BARRIER); } +template <> +Node* CodeStubAssembler::LoadName<NameDictionary>(Node* key) { + CSA_ASSERT(this, Word32Or(IsTheHole(key), IsName(key))); + return key; +} + +template <> +Node* CodeStubAssembler::LoadName<GlobalDictionary>(Node* key) { + CSA_ASSERT(this, IsPropertyCell(key)); + CSA_ASSERT(this, IsNotTheHole(key)); + return LoadObjectField(key, PropertyCell::kNameOffset); +} + template <typename Dictionary> void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, Node* unique_name, Label* if_found, @@ -4848,12 +5115,15 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, // See Dictionary::FirstProbe(). Node* count = IntPtrConstant(0); Node* entry = WordAnd(hash, mask); + Node* undefined = UndefinedConstant(); for (int i = 0; i < inlined_probes; i++) { Node* index = EntryToIndex<Dictionary>(entry); var_name_index->Bind(index); Node* current = LoadFixedArrayElement(dictionary, index); + GotoIf(WordEqual(current, undefined), if_not_found); + current = LoadName<Dictionary>(current); GotoIf(WordEqual(current, unique_name), if_found); // See Dictionary::NextProbe(). @@ -4865,7 +5135,6 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, var_name_index->Bind(IntPtrConstant(0)); } - Node* undefined = UndefinedConstant(); Node* the_hole = mode == kFindExisting ? nullptr : TheHoleConstant(); VARIABLE(var_count, MachineType::PointerRepresentation(), count); @@ -4883,6 +5152,7 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, Node* current = LoadFixedArrayElement(dictionary, index); GotoIf(WordEqual(current, undefined), if_not_found); if (mode == kFindExisting) { + current = LoadName<Dictionary>(current); GotoIf(WordEqual(current, unique_name), if_found); } else { DCHECK_EQ(kFindInsertionIndex, mode); @@ -4904,6 +5174,10 @@ template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>( template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>( Node*, Node*, Label*, Variable*, Label*, int, LookupMode); +Node* CodeStubAssembler::ComputeIntegerHash(Node* key) { + return ComputeIntegerHash(key, IntPtrConstant(kZeroHashSeed)); +} + Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) { // See v8::internal::ComputeIntegerHash() Node* hash = TruncateWordToWord32(key); @@ -4931,12 +5205,9 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* capacity = SmiUntag(GetCapacity<Dictionary>(dictionary)); Node* mask = IntPtrSub(capacity, IntPtrConstant(1)); - Node* int32_seed; - if (Dictionary::ShapeT::UsesSeed) { - int32_seed = HashSeed(); - } else { - int32_seed = Int32Constant(kZeroHashSeed); - } + Node* int32_seed = std::is_same<Dictionary, SeededNumberDictionary>::value + ? HashSeed() + : Int32Constant(kZeroHashSeed); Node* hash = ChangeUint32ToWord(ComputeIntegerHash(intptr_index, int32_seed)); Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index); @@ -5014,16 +5285,18 @@ void CodeStubAssembler::InsertEntry<NameDictionary>(Node* dictionary, Node* name, Node* value, Node* index, Node* enum_index) { + CSA_SLOW_ASSERT(this, IsDictionary(dictionary)); + // Store name and value. StoreFixedArrayElement(dictionary, index, name); StoreValueByKeyIndex<NameDictionary>(dictionary, index, value); // Prepare details of the new property. - const int kInitialIndex = 0; - PropertyDetails d(kData, NONE, kInitialIndex, PropertyCellType::kNoCell); + PropertyDetails d(kData, NONE, PropertyCellType::kNoCell); enum_index = SmiShl(enum_index, PropertyDetails::DictionaryStorageField::kShift); - STATIC_ASSERT(kInitialIndex == 0); + // We OR over the actual index below, so we expect the initial value to be 0. + DCHECK_EQ(0, d.dictionary_index()); VARIABLE(var_details, MachineRepresentation::kTaggedSigned, SmiOr(SmiConstant(d.AsSmi()), enum_index)); @@ -5055,6 +5328,7 @@ void CodeStubAssembler::InsertEntry<GlobalDictionary>(Node* dictionary, template <class Dictionary> void CodeStubAssembler::Add(Node* dictionary, Node* key, Node* value, Label* bailout) { + CSA_SLOW_ASSERT(this, IsDictionary(dictionary)); Node* capacity = GetCapacity<Dictionary>(dictionary); Node* nof = GetNumberOfElements<Dictionary>(dictionary); Node* new_nof = SmiAdd(nof, SmiConstant(1)); @@ -5068,21 +5342,17 @@ void CodeStubAssembler::Add(Node* dictionary, Node* key, Node* value, CSA_ASSERT(this, SmiAbove(capacity, new_nof)); Node* half_of_free_elements = SmiShr(SmiSub(capacity, new_nof), 1); GotoIf(SmiAbove(deleted, half_of_free_elements), bailout); - Node* enum_index = nullptr; - if (Dictionary::kIsEnumerable) { - enum_index = GetNextEnumerationIndex<Dictionary>(dictionary); - Node* new_enum_index = SmiAdd(enum_index, SmiConstant(1)); - Node* max_enum_index = - SmiConstant(PropertyDetails::DictionaryStorageField::kMax); - GotoIf(SmiAbove(new_enum_index, max_enum_index), bailout); - - // No more bailouts after this point. - // Operations from here on can have side effects. - - SetNextEnumerationIndex<Dictionary>(dictionary, new_enum_index); - } else { - USE(enum_index); - } + + Node* enum_index = GetNextEnumerationIndex<Dictionary>(dictionary); + Node* new_enum_index = SmiAdd(enum_index, SmiConstant(1)); + Node* max_enum_index = + SmiConstant(PropertyDetails::DictionaryStorageField::kMax); + GotoIf(SmiAbove(new_enum_index, max_enum_index), bailout); + + // No more bailouts after this point. + // Operations from here on can have side effects. + + SetNextEnumerationIndex<Dictionary>(dictionary, new_enum_index); SetNumberOfElements<Dictionary>(dictionary, new_nof); VARIABLE(var_key_index, MachineType::PointerRepresentation()); @@ -5294,10 +5564,8 @@ void CodeStubAssembler::TryLookupProperty( // Handle interceptors and access checks in runtime. Node* bit_field = LoadMapBitField(map); - Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor | - 1 << Map::kIsAccessCheckNeeded); - GotoIf(Word32NotEqual(Word32And(bit_field, mask), Int32Constant(0)), - if_bailout); + int mask = 1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded; + GotoIf(IsSetWord32(bit_field, mask), if_bailout); Node* dictionary = LoadProperties(object); var_meta_storage->Bind(dictionary); @@ -5455,8 +5723,8 @@ void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary, Comment("[ LoadPropertyFromGlobalDictionary"); CSA_ASSERT(this, IsDictionary(dictionary)); - Node* property_cell = - LoadValueByKeyIndex<GlobalDictionary>(dictionary, name_index); + Node* property_cell = LoadFixedArrayElement(dictionary, name_index); + CSA_ASSERT(this, IsPropertyCell(property_cell)); Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); GotoIf(WordEqual(value, TheHoleConstant()), if_deleted); @@ -5640,10 +5908,10 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, // clang-format off int32_t values[] = { // Handled by {if_isobjectorsmi}. - FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, - FAST_HOLEY_ELEMENTS, + PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, + HOLEY_ELEMENTS, // Handled by {if_isdouble}. - FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, + PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS, // Handled by {if_isdictionary}. DICTIONARY_ELEMENTS, // Handled by {if_isfaststringwrapper}. @@ -5867,34 +6135,77 @@ void CodeStubAssembler::TryPrototypeChainLookup( } } -Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, - Node* object) { +Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object, + Node* prototype) { + CSA_ASSERT(this, TaggedIsNotSmi(object)); VARIABLE(var_result, MachineRepresentation::kTagged); Label return_false(this), return_true(this), return_runtime(this, Label::kDeferred), return_result(this); - // Goto runtime if {object} is a Smi. - GotoIf(TaggedIsSmi(object), &return_runtime); + // Loop through the prototype chain looking for the {prototype}. + VARIABLE(var_object_map, MachineRepresentation::kTagged, 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(); + Node* object_instance_type = LoadMapInstanceType(object_map); + Branch(IsSpecialReceiverInstanceType(object_instance_type), + &if_objectisspecial, &if_objectisdirect); + BIND(&if_objectisspecial); + { + // The {object_map} is a special receiver map or a primitive map, check + // if we need to use the if_objectisspecial path in the runtime. + GotoIf(InstanceTypeEqual(object_instance_type, JS_PROXY_TYPE), + &return_runtime); + Node* object_bitfield = LoadMapBitField(object_map); + int mask = + 1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded; + Branch(IsSetWord32(object_bitfield, mask), &return_runtime, + &if_objectisdirect); + } + BIND(&if_objectisdirect); - // Load map of {object}. - Node* object_map = LoadMap(object); + // Check the current {object} prototype. + Node* object_prototype = LoadMapPrototype(object_map); + GotoIf(IsNull(object_prototype), &return_false); + GotoIf(WordEqual(object_prototype, prototype), &return_true); - // Lookup the {callable} and {object} map in the global instanceof cache. - // Note: This is safe because we clear the global instanceof cache whenever - // we change the prototype of any object. - Node* instanceof_cache_function = - LoadRoot(Heap::kInstanceofCacheFunctionRootIndex); - Node* instanceof_cache_map = LoadRoot(Heap::kInstanceofCacheMapRootIndex); - { - Label instanceof_cache_miss(this); - GotoIfNot(WordEqual(instanceof_cache_function, callable), - &instanceof_cache_miss); - GotoIfNot(WordEqual(instanceof_cache_map, object_map), - &instanceof_cache_miss); - var_result.Bind(LoadRoot(Heap::kInstanceofCacheAnswerRootIndex)); - Goto(&return_result); - BIND(&instanceof_cache_miss); + // Continue with the prototype. + CSA_ASSERT(this, TaggedIsNotSmi(object_prototype)); + var_object_map.Bind(LoadMap(object_prototype)); + Goto(&loop); + } + + BIND(&return_true); + var_result.Bind(TrueConstant()); + Goto(&return_result); + + BIND(&return_false); + var_result.Bind(FalseConstant()); + Goto(&return_result); + + BIND(&return_runtime); + { + // Fallback to the runtime implementation. + var_result.Bind( + CallRuntime(Runtime::kHasInPrototypeChain, context, object, prototype)); } + Goto(&return_result); + + BIND(&return_result); + return var_result.value(); +} + +Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, + Node* object) { + VARIABLE(var_result, MachineRepresentation::kTagged); + Label return_runtime(this, Label::kDeferred), return_result(this); + + // Goto runtime if {object} is a Smi. + GotoIf(TaggedIsSmi(object), &return_runtime); // Goto runtime if {callable} is a Smi. GotoIf(TaggedIsSmi(callable), &return_runtime); @@ -5942,56 +6253,12 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, callable_prototype = var_callable_prototype.value(); } - // Update the global instanceof cache with the current {object} map and - // {callable}. The cached answer will be set when it is known below. - StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, callable); - StoreRoot(Heap::kInstanceofCacheMapRootIndex, object_map); - // Loop through the prototype chain looking for the {callable} prototype. - VARIABLE(var_object_map, MachineRepresentation::kTagged, object_map); - Label loop(this, &var_object_map); - Goto(&loop); - BIND(&loop); - { - Node* object_map = var_object_map.value(); - - // Check if the current {object} needs to be access checked. - Node* object_bitfield = LoadMapBitField(object_map); - GotoIfNot( - Word32Equal(Word32And(object_bitfield, - Int32Constant(1 << Map::kIsAccessCheckNeeded)), - Int32Constant(0)), - &return_runtime); - - // Check if the current {object} is a proxy. - Node* object_instance_type = LoadMapInstanceType(object_map); - GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)), - &return_runtime); - - // Check the current {object} prototype. - Node* object_prototype = LoadMapPrototype(object_map); - GotoIf(WordEqual(object_prototype, NullConstant()), &return_false); - GotoIf(WordEqual(object_prototype, callable_prototype), &return_true); - - // Continue with the prototype. - var_object_map.Bind(LoadMap(object_prototype)); - Goto(&loop); - } - - BIND(&return_true); - StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(true)); - var_result.Bind(BooleanConstant(true)); - Goto(&return_result); - - BIND(&return_false); - StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(false)); - var_result.Bind(BooleanConstant(false)); + var_result.Bind(HasInPrototypeChain(context, object, callable_prototype)); Goto(&return_result); BIND(&return_runtime); { - // Invalidate the global instanceof cache. - StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, SmiConstant(0)); // Fallback to the runtime implementation. var_result.Bind( CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object)); @@ -6042,14 +6309,28 @@ Node* CodeStubAssembler::LoadFeedbackVectorForStub() { } void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* feedback_vector, - Node* slot_id) { + Node* slot_id, Node* function) { // This method is used for binary op and compare feedback. These // vector nodes are initialized with a smi 0, so we can simply OR // our new feedback in place. Node* previous_feedback = LoadFixedArrayElement(feedback_vector, slot_id); Node* combined_feedback = SmiOr(previous_feedback, feedback); - StoreFixedArrayElement(feedback_vector, slot_id, combined_feedback, - SKIP_WRITE_BARRIER); + Label end(this); + + GotoIf(SmiEqual(previous_feedback, combined_feedback), &end); + { + StoreFixedArrayElement(feedback_vector, slot_id, combined_feedback, + SKIP_WRITE_BARRIER); + // Reset profiler ticks. + Node* shared_info = + LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset); + StoreObjectFieldNoWriteBarrier( + shared_info, SharedFunctionInfo::kProfilerTicksOffset, Int32Constant(0), + MachineRepresentation::kWord32); + Goto(&end); + } + + BIND(&end); } void CodeStubAssembler::CombineFeedback(Variable* existing_feedback, @@ -6084,7 +6365,7 @@ Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { 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(IsHeapNumberMap(LoadMap(key)), miss); + GotoIfNot(IsHeapNumber(key), miss); { Node* value = LoadHeapNumberValue(key); Node* int_value = RoundFloat64ToInt32(value); @@ -6231,7 +6512,6 @@ MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) { return MachineRepresentation::kFloat64; default: UNREACHABLE(); - return MachineRepresentation::kNone; } } @@ -6252,8 +6532,8 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, } WriteBarrierMode barrier_mode = - IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; - if (IsFastDoubleElementsKind(kind)) { + IsSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; + if (IsDoubleElementsKind(kind)) { // Make sure we do not store signalling NaNs into double arrays. value = Float64SilenceNaN(value); StoreFixedDoubleArrayElement(elements, index, value, mode); @@ -6314,14 +6594,13 @@ Node* CodeStubAssembler::PrepareValueForWriteToTypedArray( break; default: UNREACHABLE(); - return nullptr; } VARIABLE(var_result, rep); Label done(this, &var_result), if_smi(this); GotoIf(TaggedIsSmi(input), &if_smi); // Try to convert a heap number to a Smi. - GotoIfNot(IsHeapNumberMap(LoadMap(input)), bailout); + GotoIfNot(IsHeapNumber(input), bailout); { Node* value = LoadHeapNumberValue(input); if (rep == MachineRepresentation::kWord32) { @@ -6366,7 +6645,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, KeyedAccessStoreMode store_mode, Label* bailout) { Node* elements = LoadElements(object); - if (IsFastSmiOrObjectElementsKind(elements_kind) && + if (IsSmiOrObjectElementsKind(elements_kind) && store_mode != STORE_NO_TRANSITION_HANDLE_COW) { // Bailout in case of COW elements. GotoIf(WordNotEqual(LoadMap(elements), @@ -6420,8 +6699,8 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, BIND(&done); return; } - DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || - IsFastDoubleElementsKind(elements_kind)); + DCHECK(IsSmiOrObjectElementsKind(elements_kind) || + IsDoubleElementsKind(elements_kind)); Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset) : LoadFixedArrayBaseLength(elements); @@ -6430,9 +6709,9 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, // In case value is stored into a fast smi array, assure that the value is // a smi before manipulating the backing store. Otherwise the backing store // may be left in an invalid state. - if (IsFastSmiElementsKind(elements_kind)) { + if (IsSmiElementsKind(elements_kind)) { GotoIfNot(TaggedIsSmi(value), bailout); - } else if (IsFastDoubleElementsKind(elements_kind)) { + } else if (IsDoubleElementsKind(elements_kind)) { value = TryTaggedToFloat64(value, bailout); } @@ -6443,7 +6722,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, GotoIfNot(UintPtrLessThan(key, length), bailout); if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && - IsFastSmiOrObjectElementsKind(elements_kind)) { + IsSmiOrObjectElementsKind(elements_kind)) { elements = CopyElementsOnWrite(object, elements, elements_kind, length, parameter_mode, bailout); } @@ -6460,7 +6739,7 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, Label grow_case(this), no_grow_case(this), done(this); Node* condition; - if (IsHoleyElementsKind(kind)) { + if (IsHoleyOrDictionaryElementsKind(kind)) { condition = UintPtrGreaterThanOrEqual(key, length); } else { condition = WordEqual(key, length); @@ -6533,9 +6812,8 @@ void CodeStubAssembler::TransitionElementsKind(Node* object, Node* map, ElementsKind to_kind, bool is_jsarray, Label* bailout) { - DCHECK(!IsFastHoleyElementsKind(from_kind) || - IsFastHoleyElementsKind(to_kind)); - if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) { + DCHECK(!IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind)); + if (AllocationSite::ShouldTrack(from_kind, to_kind)) { TrapAllocationMemento(object, bailout); } @@ -6637,8 +6915,8 @@ Node* CodeStubAssembler::CreateAllocationSiteInFeedbackVector( StoreMap(site, AllocationSiteMapConstant()); Node* kind = SmiConstant(GetInitialFastElementsKind()); - StoreObjectFieldNoWriteBarrier(site, AllocationSite::kTransitionInfoOffset, - kind); + StoreObjectFieldNoWriteBarrier( + site, AllocationSite::kTransitionInfoOrBoilerplateOffset, kind); // Unlike literals, constructed arrays don't have nested sites Node* zero = SmiConstant(0); @@ -6769,6 +7047,8 @@ 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 = (parameter_mode == INTPTR_PARAMETERS) ? MachineType::PointerRepresentation() : MachineRepresentation::kTaggedSigned; @@ -6806,6 +7086,10 @@ void CodeStubAssembler::BuildFastFixedArrayForEach( Node* last_element_exclusive, const FastFixedArrayForEachBody& body, ParameterMode mode, ForEachDirection direction) { STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize); + CSA_SLOW_ASSERT(this, MatchesParameterMode(first_element_inclusive, mode)); + CSA_SLOW_ASSERT(this, MatchesParameterMode(last_element_exclusive, mode)); + CSA_SLOW_ASSERT(this, Word32Or(IsFixedArrayWithKind(fixed_array, kind), + IsPropertyArray(fixed_array))); int32_t first_val; bool constant_first = ToInt32Constant(first_element_inclusive, first_val); int32_t last_val; @@ -6843,7 +7127,7 @@ void CodeStubAssembler::BuildFastFixedArrayForEach( FixedArray::kHeaderSize - kHeapObjectTag); if (direction == ForEachDirection::kReverse) std::swap(start, limit); - int increment = IsFastDoubleElementsKind(kind) ? kDoubleSize : kPointerSize; + int increment = IsDoubleElementsKind(kind) ? kDoubleSize : kPointerSize; BuildFastLoop( vars, start, limit, [fixed_array, &body](Node* offset) { body(fixed_array, offset); }, @@ -6866,6 +7150,7 @@ void CodeStubAssembler::GotoIfFixedArraySizeDoesntFitInNewSpace( void CodeStubAssembler::InitializeFieldsWithRoot( Node* object, Node* start_offset, Node* end_offset, Heap::RootListIndex root_index) { + CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object)); start_offset = IntPtrAdd(start_offset, IntPtrConstant(-kHeapObjectTag)); end_offset = IntPtrAdd(end_offset, IntPtrConstant(-kHeapObjectTag)); Node* root_value = LoadRoot(root_index); @@ -6881,6 +7166,9 @@ void CodeStubAssembler::InitializeFieldsWithRoot( void CodeStubAssembler::BranchIfNumericRelationalComparison( RelationalComparisonMode mode, Node* lhs, Node* rhs, Label* if_true, Label* if_false) { + CSA_SLOW_ASSERT(this, IsNumber(lhs)); + CSA_SLOW_ASSERT(this, IsNumber(rhs)); + Label end(this); VARIABLE(result, MachineRepresentation::kTagged); @@ -6920,7 +7208,7 @@ void CodeStubAssembler::BranchIfNumericRelationalComparison( BIND(&if_rhsisnotsmi); { - CSA_ASSERT(this, IsHeapNumberMap(LoadMap(rhs))); + CSA_ASSERT(this, IsHeapNumber(rhs)); // Convert the {lhs} and {rhs} to floating point values, and // perform a floating point comparison. var_fcmp_lhs.Bind(SmiToFloat64(lhs)); @@ -6931,7 +7219,7 @@ void CodeStubAssembler::BranchIfNumericRelationalComparison( BIND(&if_lhsisnotsmi); { - CSA_ASSERT(this, IsHeapNumberMap(LoadMap(lhs))); + CSA_ASSERT(this, IsHeapNumber(lhs)); // Check if {rhs} is a Smi or a HeapObject. Label if_rhsissmi(this), if_rhsisnotsmi(this); @@ -6948,7 +7236,7 @@ void CodeStubAssembler::BranchIfNumericRelationalComparison( BIND(&if_rhsisnotsmi); { - CSA_ASSERT(this, IsHeapNumberMap(LoadMap(rhs))); + CSA_ASSERT(this, IsHeapNumber(rhs)); // Convert the {lhs} and {rhs} to floating point values, and // perform a floating point comparison. @@ -7055,12 +7343,9 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, BIND(&if_rhsisnotsmi); { - // Load the map of {rhs}. - Node* rhs_map = LoadMap(rhs); - // Check if the {rhs} is a HeapNumber. Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); - Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber); + Branch(IsHeapNumber(rhs), &if_rhsisnumber, &if_rhsisnotnumber); BIND(&if_rhsisnumber); { @@ -7086,8 +7371,7 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, // dedicated ToPrimitive(rhs, hint Number) operation, as the // ToNumber(rhs) will by itself already invoke ToPrimitive with // a Number hint. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_rhs.Bind(CallStub(callable, context, rhs)); + var_rhs.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, rhs)); Goto(&loop); } } @@ -7132,8 +7416,7 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, // dedicated ToPrimitive(lhs, hint Number) operation, as the // ToNumber(lhs) will by itself already invoke ToPrimitive with // a Number hint. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_lhs.Bind(CallStub(callable, context, lhs)); + var_lhs.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, lhs)); Goto(&loop); } } @@ -7178,8 +7461,8 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, // dedicated ToPrimitive(rhs, hint Number) operation, as the // ToNumber(rhs) will by itself already invoke ToPrimitive with // a Number hint. - Callable callable = CodeFactory::NonNumberToNumber(isolate()); - var_rhs.Bind(CallStub(callable, context, rhs)); + var_rhs.Bind( + CallBuiltin(Builtins::kNonNumberToNumber, context, rhs)); Goto(&loop); } } @@ -7214,26 +7497,23 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, } switch (mode) { case kLessThan: - result.Bind(CallStub(CodeFactory::StringLessThan(isolate()), - context, lhs, rhs)); + result.Bind(CallBuiltin(Builtins::kStringLessThan, context, + lhs, rhs)); Goto(&end); break; case kLessThanOrEqual: - result.Bind( - CallStub(CodeFactory::StringLessThanOrEqual(isolate()), - context, lhs, rhs)); + result.Bind(CallBuiltin(Builtins::kStringLessThanOrEqual, + context, lhs, rhs)); Goto(&end); break; case kGreaterThan: - result.Bind( - CallStub(CodeFactory::StringGreaterThan(isolate()), - context, lhs, rhs)); + result.Bind(CallBuiltin(Builtins::kStringGreaterThan, context, + lhs, rhs)); Goto(&end); break; case kGreaterThanOrEqual: - result.Bind( - CallStub(CodeFactory::StringGreaterThanOrEqual(isolate()), - context, lhs, rhs)); + result.Bind(CallBuiltin(Builtins::kStringGreaterThanOrEqual, + context, lhs, rhs)); Goto(&end); break; } @@ -7268,9 +7548,8 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, BIND(&if_rhsisnotreceiver); { // Convert both {lhs} and {rhs} to Number. - Callable callable = CodeFactory::ToNumber(isolate()); - var_lhs.Bind(CallStub(callable, context, lhs)); - var_rhs.Bind(CallStub(callable, context, rhs)); + var_lhs.Bind(CallBuiltin(Builtins::kToNumber, context, lhs)); + var_rhs.Bind(CallBuiltin(Builtins::kToNumber, context, rhs)); Goto(&loop); } } @@ -7334,9 +7613,8 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode, BIND(&if_lhsisnotreceiver); { // Convert both {lhs} and {rhs} to Number. - Callable callable = CodeFactory::ToNumber(isolate()); - var_lhs.Bind(CallStub(callable, context, lhs)); - var_rhs.Bind(CallStub(callable, context, rhs)); + var_lhs.Bind(CallBuiltin(Builtins::kToNumber, context, lhs)); + var_rhs.Bind(CallBuiltin(Builtins::kToNumber, context, rhs)); Goto(&loop); } } @@ -7434,9 +7712,12 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal, // Collect type feedback. Node* instance_type = LoadMapInstanceType(value_map); - Label if_valueisstring(this), if_valueisnotstring(this); - Branch(IsStringInstanceType(instance_type), &if_valueisstring, - &if_valueisnotstring); + Label if_valueisstring(this), if_valueisreceiver(this), + if_valueissymbol(this), if_valueisother(this, Label::kDeferred); + GotoIf(IsStringInstanceType(instance_type), &if_valueisstring); + GotoIf(IsJSReceiverInstanceType(instance_type), &if_valueisreceiver); + Branch(IsSymbolInstanceType(instance_type), &if_valueissymbol, + &if_valueisother); BIND(&if_valueisstring); { @@ -7445,15 +7726,26 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal, Goto(if_equal); } - BIND(&if_valueisnotstring); + BIND(&if_valueissymbol); { - var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny)); - GotoIfNot(IsJSReceiverInstanceType(instance_type), if_equal); + CombineFeedback(var_type_feedback, + SmiConstant(CompareOperationFeedback::kSymbol)); + Goto(if_equal); + } + BIND(&if_valueisreceiver); + { CombineFeedback(var_type_feedback, SmiConstant(CompareOperationFeedback::kReceiver)); Goto(if_equal); } + + BIND(&if_valueisother); + { + CombineFeedback(var_type_feedback, + SmiConstant(CompareOperationFeedback::kAny)); + Goto(if_equal); + } } else { Goto(if_equal); } @@ -7688,8 +7980,8 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, { // Both {lhs} and {rhs} are of type String, just do the // string comparison then. - Callable callable = CodeFactory::StringEqual(isolate()); - result.Bind(CallStub(callable, context, lhs, rhs)); + result.Bind( + CallBuiltin(Builtins::kStringEqual, context, lhs, rhs)); if (var_type_feedback != nullptr) { Node* lhs_feedback = CollectFeedbackForString(lhs_instance_type); @@ -7840,25 +8132,14 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, // The {lhs} is either Null or Undefined; check if the {rhs} is // undetectable (i.e. either also Null or Undefined or some // undetectable JSReceiver). - Node* rhs_bitfield = LoadMapBitField(rhs_map); - Branch(Word32Equal( - Word32And(rhs_bitfield, - Int32Constant(1 << Map::kIsUndetectable)), - Int32Constant(0)), - &if_notequal, &if_equal); + Branch(IsUndetectableMap(rhs_map), &if_equal, &if_notequal); } } BIND(&if_lhsissymbol); { - if (var_type_feedback != nullptr) { - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kAny)); - } - // Check if the {rhs} is a JSReceiver. Label if_rhsisreceiver(this), if_rhsisnotreceiver(this); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); Branch(IsJSReceiverInstanceType(rhs_instance_type), &if_rhsisreceiver, &if_rhsisnotreceiver); @@ -7868,6 +8149,10 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, // Swapping {lhs} and {rhs} is not observable and doesn't // matter for the result, so we can just swap them and use // the JSReceiver handling below (for {lhs} being a JSReceiver). + if (var_type_feedback != nullptr) { + var_type_feedback->Bind( + SmiConstant(CompareOperationFeedback::kAny)); + } var_lhs.Bind(rhs); var_rhs.Bind(lhs); Goto(&loop); @@ -7877,7 +8162,27 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, { // The {rhs} is not a JSReceiver and also not the same Symbol // as the {lhs}, so this is equality check is considered false. - Goto(&if_notequal); + if (var_type_feedback != nullptr) { + Label if_rhsissymbol(this), if_rhsisnotsymbol(this); + Branch(IsSymbolInstanceType(rhs_instance_type), &if_rhsissymbol, + &if_rhsisnotsymbol); + + BIND(&if_rhsissymbol); + { + var_type_feedback->Bind( + SmiConstant(CompareOperationFeedback::kSymbol)); + Goto(&if_notequal); + } + + BIND(&if_rhsisnotsymbol); + { + var_type_feedback->Bind( + SmiConstant(CompareOperationFeedback::kAny)); + Goto(&if_notequal); + } + } else { + Goto(&if_notequal); + } } } @@ -7915,23 +8220,11 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, // a JSReceiver). Label if_rhsisundetectable(this), if_rhsisnotundetectable(this, Label::kDeferred); - Node* rhs_bitfield = LoadMapBitField(rhs_map); - Branch(Word32Equal( - Word32And(rhs_bitfield, - Int32Constant(1 << Map::kIsUndetectable)), - Int32Constant(0)), - &if_rhsisnotundetectable, &if_rhsisundetectable); + Branch(IsUndetectableMap(rhs_map), &if_rhsisundetectable, + &if_rhsisnotundetectable); BIND(&if_rhsisundetectable); - { - // Check if {lhs} is an undetectable JSReceiver. - Node* lhs_bitfield = LoadMapBitField(lhs_map); - Branch(Word32Equal( - Word32And(lhs_bitfield, - Int32Constant(1 << Map::kIsUndetectable)), - Int32Constant(0)), - &if_notequal, &if_equal); - } + Branch(IsUndetectableMap(lhs_map), &if_equal, &if_notequal); BIND(&if_rhsisnotundetectable); { @@ -7950,8 +8243,7 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context, BIND(&do_rhsstringtonumber); { - Callable callable = CodeFactory::StringToNumber(isolate()); - var_rhs.Bind(CallStub(callable, context, rhs)); + var_rhs.Bind(CallBuiltin(Builtins::kStringToNumber, context, rhs)); Goto(&loop); } } @@ -7994,7 +8286,7 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs, // if (!lhs->IsSmi()) { // if (lhs->IsHeapNumber()) { // if (rhs->IsSmi()) { - // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); + // return Smi::ToInt(rhs) == HeapNumber::cast(lhs)->value(); // } else if (rhs->IsHeapNumber()) { // return HeapNumber::cast(rhs)->value() == // HeapNumber::cast(lhs)->value(); @@ -8021,7 +8313,7 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs, // return false; // } else { // if (rhs->IsHeapNumber()) { - // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); + // return Smi::ToInt(lhs) == HeapNumber::cast(rhs)->value(); // } else { // return false; // } @@ -8149,7 +8441,6 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs, BIND(&if_rhsisstring); { - Callable callable = CodeFactory::StringEqual(isolate()); if (var_type_feedback != nullptr) { Node* lhs_feedback = CollectFeedbackForString(lhs_instance_type); @@ -8157,7 +8448,8 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs, CollectFeedbackForString(rhs_instance_type); var_type_feedback->Bind(SmiOr(lhs_feedback, rhs_feedback)); } - result.Bind(CallStub(callable, NoContextConstant(), lhs, rhs)); + result.Bind(CallBuiltin(Builtins::kStringEqual, + NoContextConstant(), lhs, rhs)); Goto(&end); } @@ -8167,14 +8459,31 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs, BIND(&if_lhsisnotstring); if (var_type_feedback != nullptr) { - GotoIfNot(IsJSReceiverInstanceType(lhs_instance_type), - &if_notequal); - GotoIfNot(IsJSReceiverInstanceType(rhs_instance_type), - &if_notequal); - var_type_feedback->Bind( - SmiConstant(CompareOperationFeedback::kReceiver)); + Label if_lhsissymbol(this), if_lhsisreceiver(this); + GotoIf(IsJSReceiverInstanceType(lhs_instance_type), + &if_lhsisreceiver); + Branch(IsSymbolInstanceType(lhs_instance_type), &if_lhsissymbol, + &if_notequal); + + BIND(&if_lhsisreceiver); + { + GotoIfNot(IsJSReceiverInstanceType(rhs_instance_type), + &if_notequal); + var_type_feedback->Bind( + SmiConstant(CompareOperationFeedback::kReceiver)); + Goto(&if_notequal); + } + + BIND(&if_lhsissymbol); + { + GotoIfNot(IsSymbolInstanceType(rhs_instance_type), &if_notequal); + var_type_feedback->Bind( + SmiConstant(CompareOperationFeedback::kSymbol)); + Goto(&if_notequal); + } + } else { + Goto(&if_notequal); } - Goto(&if_notequal); } } } @@ -8604,8 +8913,8 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, GotoIfNot(IsCallable(callable), &if_notcallable); // Use the OrdinaryHasInstance algorithm. - Node* result = CallStub(CodeFactory::OrdinaryHasInstance(isolate()), - context, callable, object); + Node* result = + CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable, object); var_result.Bind(result); Goto(&return_result); } @@ -8643,7 +8952,7 @@ Node* CodeStubAssembler::NumberInc(Node* value) { BIND(&if_issmi); { // Try fast Smi addition first. - Node* one = SmiConstant(Smi::FromInt(1)); + Node* one = SmiConstant(1); Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(value), BitcastTaggedToWord(one)); Node* overflow = Projection(1, pair); @@ -8665,8 +8974,7 @@ Node* CodeStubAssembler::NumberInc(Node* value) { BIND(&if_isnotsmi); { - // Check if the value is a HeapNumber. - CSA_ASSERT(this, IsHeapNumberMap(LoadMap(value))); + CSA_ASSERT(this, IsHeapNumber(value)); // Load the HeapNumber value. var_finc_value.Bind(LoadHeapNumberValue(value)); @@ -8695,7 +9003,7 @@ Node* CodeStubAssembler::NumberDec(Node* value) { BIND(&if_issmi); { // Try fast Smi addition first. - Node* one = SmiConstant(Smi::FromInt(1)); + Node* one = SmiConstant(1); Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(value), BitcastTaggedToWord(one)); Node* overflow = Projection(1, pair); @@ -8717,8 +9025,7 @@ Node* CodeStubAssembler::NumberDec(Node* value) { BIND(&if_isnotsmi); { - // Check if the value is a HeapNumber. - CSA_ASSERT(this, IsHeapNumberMap(LoadMap(value))); + CSA_ASSERT(this, IsHeapNumber(value)); // Load the HeapNumber value. var_fdec_value.Bind(LoadHeapNumberValue(value)); @@ -8741,15 +9048,13 @@ Node* CodeStubAssembler::NumberDec(Node* value) { void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) { Label is_number(this); GotoIf(TaggedIsSmi(input), &is_number); - Node* input_map = LoadMap(input); - Branch(IsHeapNumberMap(input_map), &is_number, is_not_number); + Branch(IsHeapNumber(input), &is_number, is_not_number); BIND(&is_number); } void CodeStubAssembler::GotoIfNumber(Node* input, Label* is_number) { GotoIf(TaggedIsSmi(input), is_number); - Node* input_map = LoadMap(input); - GotoIf(IsHeapNumberMap(input_map), is_number); + GotoIf(IsHeapNumber(input), is_number); } Node* CodeStubAssembler::CreateArrayIterator(Node* array, Node* array_map, @@ -8862,11 +9167,10 @@ Node* CodeStubAssembler::CreateArrayIterator(Node* array, Node* array_map, // here, and take the slow path if any fail. Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); - GotoIfNot( - WordEqual( - LoadObjectField(protector_cell, PropertyCell::kValueOffset), - SmiConstant(Smi::FromInt(Isolate::kProtectorValid))), - &if_isslow); + GotoIfNot(WordEqual(LoadObjectField(protector_cell, + PropertyCell::kValueOffset), + SmiConstant(Isolate::kProtectorValid)), + &if_isslow); Node* native_context = LoadNativeContext(context); @@ -8945,19 +9249,71 @@ Node* CodeStubAssembler::AllocateJSArrayIterator(Node* array, Node* array_map, Node* map) { Node* iterator = Allocate(JSArrayIterator::kSize); StoreMapNoWriteBarrier(iterator, map); - StoreObjectFieldRoot(iterator, JSArrayIterator::kPropertiesOffset, + StoreObjectFieldRoot(iterator, JSArrayIterator::kPropertiesOrHashOffset, Heap::kEmptyFixedArrayRootIndex); StoreObjectFieldRoot(iterator, JSArrayIterator::kElementsOffset, Heap::kEmptyFixedArrayRootIndex); StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kIteratedObjectOffset, array); StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset, - SmiConstant(Smi::FromInt(0))); + SmiConstant(0)); StoreObjectFieldNoWriteBarrier( iterator, JSArrayIterator::kIteratedObjectMapOffset, array_map); return iterator; } +Node* CodeStubAssembler::AllocateJSIteratorResult(Node* context, Node* value, + Node* done) { + CSA_ASSERT(this, IsBoolean(done)); + Node* native_context = LoadNativeContext(context); + Node* map = + LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); + Node* result = Allocate(JSIteratorResult::kSize); + StoreMapNoWriteBarrier(result, map); + StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value); + StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done); + return result; +} + +Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context, + Node* key, + Node* value) { + Node* native_context = LoadNativeContext(context); + Node* length = SmiConstant(2); + int const elements_size = FixedArray::SizeFor(2); + Node* elements = + Allocate(elements_size + JSArray::kSize + JSIteratorResult::kSize); + StoreObjectFieldRoot(elements, FixedArray::kMapOffset, + Heap::kFixedArrayMapRootIndex); + StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length); + StoreFixedArrayElement(elements, 0, key); + StoreFixedArrayElement(elements, 1, value); + Node* array_map = LoadContextElement( + native_context, Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX); + Node* array = InnerAllocate(elements, elements_size); + StoreMapNoWriteBarrier(array, array_map); + StoreObjectFieldRoot(array, JSArray::kPropertiesOrHashOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset, elements); + StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); + Node* iterator_map = + LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); + Node* result = InnerAllocate(array, JSArray::kSize); + StoreMapNoWriteBarrier(result, iterator_map); + StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, + Heap::kEmptyFixedArrayRootIndex); + StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, array); + StoreObjectFieldRoot(result, JSIteratorResult::kDoneOffset, + Heap::kFalseValueRootIndex); + return result; +} + Node* CodeStubAssembler::TypedArraySpeciesCreateByLength(Node* context, Node* originalArray, Node* len) { @@ -8975,21 +9331,23 @@ Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) { return IsSetWord32<JSArrayBuffer::WasNeutered>(buffer_bit_field); } -CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler, Node* argc, - Node* fp, - CodeStubAssembler::ParameterMode mode) +CodeStubArguments::CodeStubArguments( + CodeStubAssembler* assembler, Node* argc, Node* fp, + CodeStubAssembler::ParameterMode param_mode, ReceiverMode receiver_mode) : assembler_(assembler), - argc_mode_(mode), + argc_mode_(param_mode), + receiver_mode_(receiver_mode), argc_(argc), arguments_(nullptr), fp_(fp != nullptr ? fp : assembler_->LoadFramePointer()) { Node* offset = assembler_->ElementOffsetFromIndex( - argc_, FAST_ELEMENTS, mode, + argc_, PACKED_ELEMENTS, param_mode, (StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kPointerSize); arguments_ = assembler_->IntPtrAdd(fp_, offset); } Node* CodeStubArguments::GetReceiver() const { + DCHECK_EQ(receiver_mode_, ReceiverMode::kHasReceiver); return assembler_->Load(MachineType::AnyTagged(), arguments_, assembler_->IntPtrConstant(kPointerSize)); } @@ -8999,8 +9357,8 @@ Node* CodeStubArguments::AtIndexPtr( typedef compiler::Node Node; Node* negated_index = assembler_->IntPtrOrSmiSub( assembler_->IntPtrOrSmiConstant(0, mode), index, mode); - Node* offset = - assembler_->ElementOffsetFromIndex(negated_index, FAST_ELEMENTS, mode, 0); + Node* offset = assembler_->ElementOffsetFromIndex(negated_index, + PACKED_ELEMENTS, mode, 0); return assembler_->IntPtrAdd(arguments_, offset); } @@ -9052,10 +9410,10 @@ void CodeStubArguments::ForEach( } Node* start = assembler_->IntPtrSub( arguments_, - assembler_->ElementOffsetFromIndex(first, FAST_ELEMENTS, mode)); + assembler_->ElementOffsetFromIndex(first, PACKED_ELEMENTS, mode)); Node* end = assembler_->IntPtrSub( arguments_, - assembler_->ElementOffsetFromIndex(last, FAST_ELEMENTS, mode)); + assembler_->ElementOffsetFromIndex(last, PACKED_ELEMENTS, mode)); assembler_->BuildFastLoop(vars, start, end, [this, &body](Node* current) { Node* arg = assembler_->Load( @@ -9067,8 +9425,14 @@ void CodeStubArguments::ForEach( } void CodeStubArguments::PopAndReturn(Node* value) { - assembler_->PopAndReturn( - assembler_->IntPtrAdd(argc_, assembler_->IntPtrConstant(1)), value); + Node* pop_count; + if (receiver_mode_ == ReceiverMode::kHasReceiver) { + pop_count = assembler_->IntPtrOrSmiAdd( + argc_, assembler_->IntPtrOrSmiConstant(1, argc_mode_), argc_mode_); + } else { + pop_count = argc_; + } + assembler_->PopAndReturn(pop_count, value); } Node* CodeStubAssembler::IsFastElementsKind(Node* elements_kind) { @@ -9079,13 +9443,10 @@ Node* CodeStubAssembler::IsFastElementsKind(Node* elements_kind) { Node* CodeStubAssembler::IsHoleyFastElementsKind(Node* elements_kind) { CSA_ASSERT(this, IsFastElementsKind(elements_kind)); - STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == (FAST_SMI_ELEMENTS | 1)); - STATIC_ASSERT(FAST_HOLEY_ELEMENTS == (FAST_ELEMENTS | 1)); - STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == (FAST_DOUBLE_ELEMENTS | 1)); - - // Check prototype chain if receiver does not have packed elements. - Node* holey_elements = Word32And(elements_kind, Int32Constant(1)); - return Word32Equal(holey_elements, Int32Constant(1)); + STATIC_ASSERT(HOLEY_SMI_ELEMENTS == (PACKED_SMI_ELEMENTS | 1)); + STATIC_ASSERT(HOLEY_ELEMENTS == (PACKED_ELEMENTS | 1)); + STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == (PACKED_DOUBLE_ELEMENTS | 1)); + return IsSetWord32(elements_kind, 1); } Node* CodeStubAssembler::IsElementsKindGreaterThan( @@ -9112,6 +9473,8 @@ Node* CodeStubAssembler::IsPromiseHookEnabledOrDebugIsActive() { Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map, Node* shared_info, Node* context) { + CSA_SLOW_ASSERT(this, IsMap(map)); + Node* const code = BitcastTaggedToWord( LoadObjectField(shared_info, SharedFunctionInfo::kCodeOffset)); Node* const code_entry = @@ -9119,7 +9482,7 @@ Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map, Node* const fun = Allocate(JSFunction::kSize); StoreMapNoWriteBarrier(fun, map); - StoreObjectFieldRoot(fun, JSObject::kPropertiesOffset, + StoreObjectFieldRoot(fun, JSObject::kPropertiesOrHashOffset, Heap::kEmptyFixedArrayRootIndex); StoreObjectFieldRoot(fun, JSObject::kElementsOffset, Heap::kEmptyFixedArrayRootIndex); @@ -9176,9 +9539,8 @@ void CodeStubAssembler::Print(const char* s) { #ifdef DEBUG std::string formatted(s); formatted += "\n"; - Handle<String> string = isolate()->factory()->NewStringFromAsciiChecked( - formatted.c_str(), TENURED); - CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), HeapConstant(string)); + CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), + StringConstant(formatted.c_str())); #endif } |