summaryrefslogtreecommitdiff
path: root/chromium/v8/src/code-stub-assembler.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-09-18 14:34:04 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-10-04 11:15:27 +0000
commite6430e577f105ad8813c92e75c54660c4985026e (patch)
tree88115e5d1fb471fea807111924dcccbeadbf9e4f /chromium/v8/src/code-stub-assembler.cc
parent53d399fe6415a96ea6986ec0d402a9c07da72453 (diff)
downloadqtwebengine-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.cc1312
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(&not_smi);
{
Label not_heap_number(this, Label::kDeferred);
- Node* input_map = LoadMap(input);
- GotoIfNot(IsHeapNumberMap(input_map), &not_heap_number);
+ GotoIfNot(IsHeapNumber(input), &not_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
}