summaryrefslogtreecommitdiff
path: root/deps/v8/src/code-stub-assembler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/code-stub-assembler.cc')
-rw-r--r--deps/v8/src/code-stub-assembler.cc1083
1 files changed, 867 insertions, 216 deletions
diff --git a/deps/v8/src/code-stub-assembler.cc b/deps/v8/src/code-stub-assembler.cc
index 7b062b6bf6..edfe2de86c 100644
--- a/deps/v8/src/code-stub-assembler.cc
+++ b/deps/v8/src/code-stub-assembler.cc
@@ -43,41 +43,45 @@ void CodeStubAssembler::HandleBreakOnNode() {
BreakOnNode(node_id);
}
-void CodeStubAssembler::Assert(const NodeGenerator& codition_body,
+void CodeStubAssembler::Assert(const NodeGenerator& condition_body,
const char* message, const char* file,
int line) {
#if defined(DEBUG)
if (FLAG_debug_code) {
- Label ok(this);
- Label not_ok(this, Label::kDeferred);
- if (message != nullptr && FLAG_code_comments) {
- Comment("[ Assert: %s", message);
+ Check(condition_body, message, file, line);
+ }
+#endif
+}
+
+void CodeStubAssembler::Check(const NodeGenerator& condition_body,
+ const char* message, const char* file, int line) {
+ Label ok(this);
+ Label not_ok(this, Label::kDeferred);
+ if (message != nullptr && FLAG_code_comments) {
+ Comment("[ Assert: %s", message);
+ } else {
+ Comment("[ Assert");
+ }
+ Node* condition = condition_body();
+ DCHECK_NOT_NULL(condition);
+ Branch(condition, &ok, &not_ok);
+ BIND(&not_ok);
+ if (message != nullptr) {
+ char chars[1024];
+ Vector<char> buffer(chars);
+ if (file != nullptr) {
+ SNPrintF(buffer, "CSA_ASSERT failed: %s [%s:%d]\n", message, file, line);
} else {
- Comment("[ Assert");
+ SNPrintF(buffer, "CSA_ASSERT failed: %s\n", message);
}
- Node* condition = codition_body();
- DCHECK_NOT_NULL(condition);
- Branch(condition, &ok, &not_ok);
- BIND(&not_ok);
- if (message != nullptr) {
- char chars[1024];
- Vector<char> buffer(chars);
- if (file != nullptr) {
- SNPrintF(buffer, "CSA_ASSERT failed: %s [%s:%d]\n", message, file,
- line);
- } else {
- SNPrintF(buffer, "CSA_ASSERT failed: %s\n", message);
- }
- CallRuntime(
- Runtime::kGlobalPrint, SmiConstant(Smi::kZero),
- HeapConstant(factory()->NewStringFromAsciiChecked(&(buffer[0]))));
- }
- DebugBreak();
- Goto(&ok);
- BIND(&ok);
- Comment("] Assert");
+ CallRuntime(
+ Runtime::kGlobalPrint, SmiConstant(Smi::kZero),
+ HeapConstant(factory()->NewStringFromAsciiChecked(&(buffer[0]))));
}
-#endif
+ DebugBreak();
+ Goto(&ok);
+ BIND(&ok);
+ Comment("] Assert");
}
Node* CodeStubAssembler::Select(Node* condition, const NodeGenerator& true_body,
@@ -593,12 +597,12 @@ Node* CodeStubAssembler::TrySmiDiv(Node* dividend, Node* divisor,
Branch(WordEqual(dividend, SmiConstant(0)), &dividend_is_zero,
&dividend_is_not_zero);
- Bind(&dividend_is_zero);
+ BIND(&dividend_is_zero);
{
GotoIf(SmiLessThan(divisor, SmiConstant(0)), bailout);
Goto(&dividend_is_not_zero);
}
- Bind(&dividend_is_not_zero);
+ BIND(&dividend_is_not_zero);
Node* untagged_divisor = SmiToWord32(divisor);
Node* untagged_dividend = SmiToWord32(dividend);
@@ -609,7 +613,7 @@ Node* CodeStubAssembler::TrySmiDiv(Node* dividend, Node* divisor,
Branch(Word32Equal(untagged_divisor, Int32Constant(-1)),
&divisor_is_minus_one, &divisor_is_not_minus_one);
- Bind(&divisor_is_minus_one);
+ BIND(&divisor_is_minus_one);
{
GotoIf(Word32Equal(
untagged_dividend,
@@ -617,7 +621,7 @@ Node* CodeStubAssembler::TrySmiDiv(Node* dividend, Node* divisor,
bailout);
Goto(&divisor_is_not_minus_one);
}
- Bind(&divisor_is_not_minus_one);
+ BIND(&divisor_is_not_minus_one);
Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor);
Node* truncated = Int32Mul(untagged_result, untagged_divisor);
@@ -654,8 +658,16 @@ Node* CodeStubAssembler::TaggedIsPositiveSmi(Node* a) {
Node* CodeStubAssembler::WordIsWordAligned(Node* word) {
return WordEqual(IntPtrConstant(0),
- WordAnd(word, IntPtrConstant((1 << kPointerSizeLog2) - 1)));
+ WordAnd(word, IntPtrConstant(kPointerSize - 1)));
+}
+
+#if DEBUG
+void CodeStubAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
+ CodeAssembler::Bind(label, debug_info);
}
+#else
+void CodeStubAssembler::Bind(Label* label) { CodeAssembler::Bind(label); }
+#endif // DEBUG
void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
Node* receiver_map, Label* definitely_no_elements,
@@ -1238,6 +1250,16 @@ Node* CodeStubAssembler::LoadStringLength(Node* object) {
return LoadObjectField(object, String::kLengthOffset);
}
+Node* CodeStubAssembler::PointerToSeqStringData(Node* seq_string) {
+ CSA_ASSERT(this, IsString(seq_string));
+ CSA_ASSERT(this,
+ IsSequentialStringInstanceType(LoadInstanceType(seq_string)));
+ STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
+ return IntPtrAdd(
+ BitcastTaggedToWord(seq_string),
+ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+}
+
Node* CodeStubAssembler::LoadJSValueValue(Node* object) {
CSA_ASSERT(this, IsJSValue(object));
return LoadObjectField(object, JSValue::kValueOffset);
@@ -1393,7 +1415,7 @@ Node* CodeStubAssembler::LoadContextElement(Node* context, int slot_index) {
Node* CodeStubAssembler::LoadContextElement(Node* context, Node* slot_index) {
Node* offset =
- IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
+ IntPtrAdd(TimesPointerSize(slot_index),
IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
return Load(MachineType::AnyTagged(), context, offset);
}
@@ -1407,7 +1429,7 @@ Node* CodeStubAssembler::StoreContextElement(Node* context, int slot_index,
Node* CodeStubAssembler::StoreContextElement(Node* context, Node* slot_index,
Node* value) {
Node* offset =
- IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
+ IntPtrAdd(TimesPointerSize(slot_index),
IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
return Store(context, offset, value);
}
@@ -1430,6 +1452,27 @@ Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind,
return LoadContextElement(native_context, Context::ArrayMapIndex(kind));
}
+Node* CodeStubAssembler::LoadJSFunctionPrototype(Node* function,
+ Label* if_bailout) {
+ CSA_ASSERT(this, TaggedIsNotSmi(function));
+ CSA_ASSERT(this, IsJSFunction(function));
+ CSA_ASSERT(this, IsClearWord32(LoadMapBitField(LoadMap(function)),
+ 1 << Map::kHasNonInstancePrototype));
+ Node* proto_or_map =
+ LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
+ GotoIf(IsTheHole(proto_or_map), if_bailout);
+
+ VARIABLE(var_result, MachineRepresentation::kTagged, proto_or_map);
+ Label done(this, &var_result);
+ GotoIfNot(IsMap(proto_or_map), &done);
+
+ var_result.Bind(LoadMapPrototype(proto_or_map));
+ Goto(&done);
+
+ BIND(&done);
+ return var_result.value();
+}
+
Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) {
return StoreObjectFieldNoWriteBarrier(object, HeapNumber::kValueOffset, value,
MachineRepresentation::kFloat64);
@@ -1523,8 +1566,57 @@ Node* CodeStubAssembler::StoreFixedDoubleArrayElement(
return StoreNoWriteBarrier(rep, object, offset, value);
}
-Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
- Node* array,
+void CodeStubAssembler::EnsureArrayLengthWritable(Node* map, Label* bailout) {
+ // Check whether the length property is writable. The length property is the
+ // only default named property on arrays. It's nonconfigurable, hence is
+ // guaranteed to stay the first property.
+ Node* descriptors = LoadMapDescriptors(map);
+ Node* details =
+ LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
+ GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), bailout);
+}
+
+Node* CodeStubAssembler::EnsureArrayPushable(Node* receiver, Label* bailout) {
+ // Disallow pushing onto prototypes. It might be the JSArray prototype.
+ // Disallow pushing onto non-extensible objects.
+ Comment("Disallow pushing onto prototypes");
+ Node* map = LoadMap(receiver);
+ Node* bit_field2 = LoadMapBitField2(map);
+ int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
+ (1 << Map::kIsExtensible);
+ Node* test = Word32And(bit_field2, Int32Constant(mask));
+ GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), bailout);
+
+ // Disallow pushing onto arrays in dictionary named property mode. We need
+ // to figure out whether the length property is still writable.
+ Comment("Disallow pushing onto arrays in dictionary named property mode");
+ GotoIf(IsDictionaryMap(map), bailout);
+
+ EnsureArrayLengthWritable(map, bailout);
+
+ Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
+ return kind;
+}
+
+void CodeStubAssembler::PossiblyGrowElementsCapacity(
+ ParameterMode mode, ElementsKind kind, Node* array, Node* length,
+ Variable* var_elements, Node* growth, Label* bailout) {
+ Label fits(this, var_elements);
+ Node* capacity =
+ TaggedToParameter(LoadFixedArrayBaseLength(var_elements->value()), mode);
+ // length and growth nodes are already in a ParameterMode appropriate
+ // representation.
+ Node* new_length = IntPtrOrSmiAdd(growth, length, mode);
+ GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
+ Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
+ var_elements->Bind(GrowElementsCapacity(array, var_elements->value(), kind,
+ kind, capacity, new_capacity, mode,
+ bailout));
+ Goto(&fits);
+ BIND(&fits);
+}
+
+Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
CodeStubArguments& args,
Variable& arg_index,
Label* bailout) {
@@ -1536,46 +1628,22 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
VARIABLE(var_length, OptimalParameterRepresentation(),
TaggedToParameter(LoadJSArrayLength(array), mode));
VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
- Node* capacity =
- TaggedToParameter(LoadFixedArrayBaseLength(var_elements.value()), mode);
// Resize the capacity of the fixed array if it doesn't fit.
- Label fits(this, &var_elements);
Node* first = arg_index.value();
- Node* growth = IntPtrSub(args.GetLength(), first);
- Node* new_length =
- IntPtrOrSmiAdd(WordToParameter(growth, mode), var_length.value(), mode);
- GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
- Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
- var_elements.Bind(GrowElementsCapacity(array, var_elements.value(), kind,
- kind, capacity, new_capacity, mode,
- &pre_bailout));
- Goto(&fits);
- BIND(&fits);
- Node* elements = var_elements.value();
+ Node* growth = WordToParameter(IntPtrSub(args.GetLength(), first), mode);
+ PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
+ &var_elements, growth, &pre_bailout);
// Push each argument onto the end of the array now that there is enough
// capacity.
CodeStubAssembler::VariableList push_vars({&var_length}, zone());
+ Node* elements = var_elements.value();
args.ForEach(
push_vars,
[this, kind, mode, elements, &var_length, &pre_bailout](Node* arg) {
- if (IsFastSmiElementsKind(kind)) {
- GotoIf(TaggedIsNotSmi(arg), &pre_bailout);
- } else if (IsFastDoubleElementsKind(kind)) {
- GotoIfNotNumber(arg, &pre_bailout);
- }
- if (IsFastDoubleElementsKind(kind)) {
- Node* double_value = ChangeNumberToFloat64(arg);
- StoreFixedDoubleArrayElement(elements, var_length.value(),
- Float64SilenceNaN(double_value), mode);
- } else {
- WriteBarrierMode barrier_mode = IsFastSmiElementsKind(kind)
- ? SKIP_WRITE_BARRIER
- : UPDATE_WRITE_BARRIER;
- StoreFixedArrayElement(elements, var_length.value(), arg,
- barrier_mode, 0, mode);
- }
+ TryStoreArrayElement(kind, mode, &pre_bailout, elements,
+ var_length.value(), arg);
Increment(var_length, 1, mode);
},
first, nullptr);
@@ -1600,6 +1668,49 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
return var_tagged_length.value();
}
+void CodeStubAssembler::TryStoreArrayElement(ElementsKind kind,
+ ParameterMode mode, Label* bailout,
+ Node* elements, Node* index,
+ Node* value) {
+ if (IsFastSmiElementsKind(kind)) {
+ GotoIf(TaggedIsNotSmi(value), bailout);
+ } else if (IsFastDoubleElementsKind(kind)) {
+ GotoIfNotNumber(value, bailout);
+ }
+ if (IsFastDoubleElementsKind(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;
+ StoreFixedArrayElement(elements, index, value, barrier_mode, 0, mode);
+ }
+}
+
+void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
+ Node* value, Label* bailout) {
+ Comment("BuildAppendJSArray: %s", ElementsKindToString(kind));
+ ParameterMode mode = OptimalParameterMode();
+ VARIABLE(var_length, OptimalParameterRepresentation(),
+ TaggedToParameter(LoadJSArrayLength(array), mode));
+ VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
+
+ // Resize the capacity of the fixed array if it doesn't fit.
+ Node* growth = IntPtrOrSmiConstant(1, mode);
+ PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
+ &var_elements, growth, bailout);
+
+ // Push each argument onto the end of the array now that there is enough
+ // capacity.
+ TryStoreArrayElement(kind, mode, bailout, var_elements.value(),
+ var_length.value(), value);
+ Increment(var_length, 1, mode);
+
+ Node* length = ParameterToTagged(var_length.value(), mode);
+ StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
+}
+
Node* CodeStubAssembler::AllocateHeapNumber(MutableMode mode) {
Node* result = Allocate(HeapNumber::kSize, kNone);
Heap::RootListIndex heap_map_index =
@@ -1939,14 +2050,15 @@ Node* CodeStubAssembler::AllocateNameDictionary(Node* at_least_space_for) {
CSA_ASSERT(this, UintPtrLessThanOrEqual(
at_least_space_for,
IntPtrConstant(NameDictionary::kMaxCapacity)));
-
Node* capacity = HashTableComputeCapacity(at_least_space_for);
- CSA_ASSERT(this, WordIsPowerOfTwo(capacity));
+ return AllocateNameDictionaryWithCapacity(capacity);
+}
+Node* CodeStubAssembler::AllocateNameDictionaryWithCapacity(Node* capacity) {
+ CSA_ASSERT(this, WordIsPowerOfTwo(capacity));
Node* length = EntryToIndex<NameDictionary>(capacity);
- Node* store_size =
- IntPtrAdd(WordShl(length, IntPtrConstant(kPointerSizeLog2)),
- IntPtrConstant(NameDictionary::kHeaderSize));
+ Node* store_size = IntPtrAdd(TimesPointerSize(length),
+ IntPtrConstant(NameDictionary::kHeaderSize));
Node* result = AllocateInNewSpace(store_size);
Comment("Initialize NameDictionary");
@@ -1983,12 +2095,27 @@ Node* CodeStubAssembler::AllocateNameDictionary(Node* at_least_space_for) {
return result;
}
+Node* CodeStubAssembler::CopyNameDictionary(Node* dictionary,
+ Label* large_object_fallback) {
+ CSA_ASSERT(this, IsHashTable(dictionary));
+ Comment("Copy boilerplate property dict");
+ Node* capacity = SmiUntag(GetCapacity<NameDictionary>(dictionary));
+ CSA_ASSERT(this, IntPtrGreaterThanOrEqual(capacity, IntPtrConstant(0)));
+ GotoIf(UintPtrGreaterThan(
+ capacity, IntPtrConstant(NameDictionary::kMaxRegularCapacity)),
+ large_object_fallback);
+ Node* properties = AllocateNameDictionaryWithCapacity(capacity);
+ Node* length = SmiUntag(LoadFixedArrayBaseLength(dictionary));
+ CopyFixedArrayElements(FAST_ELEMENTS, dictionary, properties, length,
+ SKIP_WRITE_BARRIER, INTPTR_PARAMETERS);
+ return properties;
+}
+
Node* CodeStubAssembler::AllocateJSObjectFromMap(Node* map, Node* properties,
Node* elements,
AllocationFlags flags) {
CSA_ASSERT(this, IsMap(map));
- Node* size =
- IntPtrMul(LoadMapInstanceSize(map), IntPtrConstant(kPointerSize));
+ Node* size = TimesPointerSize(LoadMapInstanceSize(map));
Node* object = AllocateInNewSpace(size, flags);
StoreMapNoWriteBarrier(object, map);
InitializeJSObjectFromMap(object, map, size, properties, elements);
@@ -2839,6 +2966,10 @@ Node* CodeStubAssembler::ChangeNumberToIntPtr(Node* value) {
return result.value();
}
+Node* CodeStubAssembler::TimesPointerSize(Node* value) {
+ return WordShl(value, IntPtrConstant(kPointerSizeLog2));
+}
+
Node* CodeStubAssembler::ToThisValue(Node* context, Node* value,
PrimitiveType primitive_type,
char const* method_name) {
@@ -2900,10 +3031,27 @@ Node* CodeStubAssembler::ToThisValue(Node* context, Node* value,
BIND(&done_throw);
{
+ const char* primitive_name = nullptr;
+ switch (primitive_type) {
+ case PrimitiveType::kBoolean:
+ primitive_name = "Boolean";
+ break;
+ case PrimitiveType::kNumber:
+ primitive_name = "Number";
+ break;
+ case PrimitiveType::kString:
+ primitive_name = "String";
+ break;
+ case PrimitiveType::kSymbol:
+ primitive_name = "Symbol";
+ break;
+ }
+ CHECK_NOT_NULL(primitive_name);
+
// The {value} is not a compatible receiver for this method.
- CallRuntime(Runtime::kThrowNotGeneric, context,
- HeapConstant(factory()->NewStringFromAsciiChecked(method_name,
- TENURED)));
+ CallRuntime(Runtime::kThrowTypeError, context,
+ SmiConstant(MessageTemplate::kNotGeneric),
+ CStringConstant(method_name), CStringConstant(primitive_name));
Unreachable();
}
@@ -3009,6 +3157,20 @@ Node* CodeStubAssembler::IsSequentialStringInstanceType(Node* instance_type) {
Int32Constant(kSeqStringTag));
}
+Node* CodeStubAssembler::IsConsStringInstanceType(Node* instance_type) {
+ CSA_ASSERT(this, IsStringInstanceType(instance_type));
+ return Word32Equal(
+ Word32And(instance_type, Int32Constant(kStringRepresentationMask)),
+ Int32Constant(kConsStringTag));
+}
+
+Node* CodeStubAssembler::IsIndirectStringInstanceType(Node* instance_type) {
+ CSA_ASSERT(this, IsStringInstanceType(instance_type));
+ STATIC_ASSERT(kIsIndirectStringMask == 0x1);
+ STATIC_ASSERT(kIsIndirectStringTag == 0x1);
+ return Word32And(instance_type, Int32Constant(kIsIndirectStringMask));
+}
+
Node* CodeStubAssembler::IsExternalStringInstanceType(Node* instance_type) {
CSA_ASSERT(this, IsStringInstanceType(instance_type));
return Word32Equal(
@@ -3031,20 +3193,23 @@ Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) {
Int32Constant(FIRST_JS_RECEIVER_TYPE));
}
+Node* CodeStubAssembler::IsJSReceiverMap(Node* map) {
+ return IsJSReceiverInstanceType(LoadMapInstanceType(map));
+}
+
Node* CodeStubAssembler::IsJSReceiver(Node* object) {
- STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
- return IsJSReceiverInstanceType(LoadInstanceType(object));
+ return IsJSReceiverMap(LoadMap(object));
}
-Node* CodeStubAssembler::IsJSReceiverMap(Node* map) {
+Node* CodeStubAssembler::IsJSObjectMap(Node* map) {
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
- return IsJSReceiverInstanceType(LoadMapInstanceType(map));
+ CSA_ASSERT(this, IsMap(map));
+ return Int32GreaterThanOrEqual(LoadMapInstanceType(map),
+ Int32Constant(FIRST_JS_OBJECT_TYPE));
}
Node* CodeStubAssembler::IsJSObject(Node* object) {
- STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
- return Int32GreaterThanOrEqual(LoadInstanceType(object),
- Int32Constant(FIRST_JS_RECEIVER_TYPE));
+ return IsJSObjectMap(LoadMap(object));
}
Node* CodeStubAssembler::IsJSGlobalProxy(Node* object) {
@@ -3056,12 +3221,28 @@ Node* CodeStubAssembler::IsMap(Node* map) {
return HasInstanceType(map, MAP_TYPE);
}
-Node* CodeStubAssembler::IsJSValue(Node* map) {
- return HasInstanceType(map, JS_VALUE_TYPE);
+Node* CodeStubAssembler::IsJSValueInstanceType(Node* instance_type) {
+ return Word32Equal(instance_type, Int32Constant(JS_VALUE_TYPE));
+}
+
+Node* CodeStubAssembler::IsJSValue(Node* object) {
+ return IsJSValueMap(LoadMap(object));
+}
+
+Node* CodeStubAssembler::IsJSValueMap(Node* map) {
+ return IsJSValueInstanceType(LoadMapInstanceType(map));
+}
+
+Node* CodeStubAssembler::IsJSArrayInstanceType(Node* instance_type) {
+ return Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
}
Node* CodeStubAssembler::IsJSArray(Node* object) {
- return HasInstanceType(object, JS_ARRAY_TYPE);
+ return IsJSArrayMap(LoadMap(object));
+}
+
+Node* CodeStubAssembler::IsJSArrayMap(Node* map) {
+ return IsJSArrayInstanceType(LoadMapInstanceType(map));
}
Node* CodeStubAssembler::IsWeakCell(Node* object) {
@@ -3076,6 +3257,10 @@ Node* CodeStubAssembler::IsPropertyCell(Node* object) {
return IsPropertyCellMap(LoadMap(object));
}
+Node* CodeStubAssembler::IsAccessorInfo(Node* object) {
+ return IsAccessorInfoMap(LoadMap(object));
+}
+
Node* CodeStubAssembler::IsAccessorPair(Node* object) {
return IsAccessorPairMap(LoadMap(object));
}
@@ -3084,6 +3269,10 @@ Node* CodeStubAssembler::IsHeapNumber(Node* object) {
return IsHeapNumberMap(LoadMap(object));
}
+Node* CodeStubAssembler::IsFeedbackVector(Node* object) {
+ return IsFeedbackVectorMap(LoadMap(object));
+}
+
Node* CodeStubAssembler::IsName(Node* object) {
return Int32LessThanOrEqual(LoadInstanceType(object),
Int32Constant(LAST_NAME_TYPE));
@@ -3131,14 +3320,26 @@ Node* CodeStubAssembler::IsUnseededNumberDictionary(Node* object) {
LoadRoot(Heap::kUnseededNumberDictionaryMapRootIndex));
}
+Node* CodeStubAssembler::IsJSFunctionInstanceType(Node* instance_type) {
+ return Word32Equal(instance_type, Int32Constant(JS_FUNCTION_TYPE));
+}
+
Node* CodeStubAssembler::IsJSFunction(Node* object) {
- return HasInstanceType(object, JS_FUNCTION_TYPE);
+ return IsJSFunctionMap(LoadMap(object));
+}
+
+Node* CodeStubAssembler::IsJSFunctionMap(Node* map) {
+ return IsJSFunctionInstanceType(LoadMapInstanceType(map));
}
Node* CodeStubAssembler::IsJSTypedArray(Node* object) {
return HasInstanceType(object, JS_TYPED_ARRAY_TYPE);
}
+Node* CodeStubAssembler::IsJSArrayBuffer(Node* object) {
+ return HasInstanceType(object, JS_ARRAY_BUFFER_TYPE);
+}
+
Node* CodeStubAssembler::IsFixedTypedArray(Node* object) {
Node* instance_type = LoadInstanceType(object);
return Word32And(
@@ -3181,6 +3382,18 @@ Node* CodeStubAssembler::IsNumberNormalized(Node* number) {
return var_result.value();
}
+Node* CodeStubAssembler::IsNumberPositive(Node* number) {
+ CSA_ASSERT(this, IsNumber(number));
+ Node* const float_zero = Float64Constant(0.);
+ return Select(TaggedIsSmi(number),
+ [=] { return TaggedIsPositiveSmi(number); },
+ [=] {
+ Node* v = LoadHeapNumberValue(number);
+ return Float64GreaterThanOrEqual(v, float_zero);
+ },
+ MachineRepresentation::kWord32);
+}
+
Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index,
ParameterMode parameter_mode) {
if (parameter_mode == SMI_PARAMETERS) CSA_ASSERT(this, TaggedIsSmi(index));
@@ -3298,64 +3511,59 @@ Node* CodeStubAssembler::StringFromCharCode(Node* code) {
return var_result.value();
}
-namespace {
-
// A wrapper around CopyStringCharacters which determines the correct string
// encoding, allocates a corresponding sequential string, and then copies the
// given character range using CopyStringCharacters.
// |from_string| must be a sequential string. |from_index| and
// |character_count| must be Smis s.t.
// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length.
-Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context,
- Node* from, Node* from_instance_type,
- Node* from_index, Node* character_count) {
- typedef CodeStubAssembler::Label Label;
- typedef CodeStubAssembler::Variable Variable;
-
- Label end(a), one_byte_sequential(a), two_byte_sequential(a);
- Variable var_result(a, MachineRepresentation::kTagged);
+Node* CodeStubAssembler::AllocAndCopyStringCharacters(Node* context, Node* from,
+ Node* from_instance_type,
+ Node* from_index,
+ Node* character_count) {
+ Label end(this), one_byte_sequential(this), two_byte_sequential(this);
+ Variable var_result(this, MachineRepresentation::kTagged);
- Node* const smi_zero = a->SmiConstant(Smi::kZero);
+ Node* const smi_zero = SmiConstant(Smi::kZero);
- a->Branch(a->IsOneByteStringInstanceType(from_instance_type),
- &one_byte_sequential, &two_byte_sequential);
+ Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential,
+ &two_byte_sequential);
// The subject string is a sequential one-byte string.
- a->BIND(&one_byte_sequential);
+ BIND(&one_byte_sequential);
{
Node* result =
- a->AllocateSeqOneByteString(context, a->SmiToWord(character_count));
- a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
- String::ONE_BYTE_ENCODING,
- String::ONE_BYTE_ENCODING,
- CodeStubAssembler::SMI_PARAMETERS);
+ AllocateSeqOneByteString(context, SmiToWord(character_count));
+ CopyStringCharacters(from, result, from_index, smi_zero, character_count,
+ String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING,
+ CodeStubAssembler::SMI_PARAMETERS);
var_result.Bind(result);
- a->Goto(&end);
+ Goto(&end);
}
// The subject string is a sequential two-byte string.
- a->BIND(&two_byte_sequential);
+ BIND(&two_byte_sequential);
{
Node* result =
- a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count));
- a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
- String::TWO_BYTE_ENCODING,
- String::TWO_BYTE_ENCODING,
- CodeStubAssembler::SMI_PARAMETERS);
+ AllocateSeqTwoByteString(context, SmiToWord(character_count));
+ CopyStringCharacters(from, result, from_index, smi_zero, character_count,
+ String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING,
+ CodeStubAssembler::SMI_PARAMETERS);
var_result.Bind(result);
- a->Goto(&end);
+ Goto(&end);
}
- a->BIND(&end);
+ BIND(&end);
return var_result.value();
}
-} // namespace
Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
- Node* to) {
+ Node* to, SubStringFlags flags) {
+ DCHECK(flags == SubStringFlags::NONE ||
+ flags == SubStringFlags::FROM_TO_ARE_BOUNDED);
VARIABLE(var_result, MachineRepresentation::kTagged);
ToDirectStringAssembler to_direct(state(), string);
Label end(this), runtime(this);
@@ -3366,8 +3574,13 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
// Make sure that both from and to are non-negative smis.
- GotoIfNot(TaggedIsPositiveSmi(from), &runtime);
- GotoIfNot(TaggedIsPositiveSmi(to), &runtime);
+ if (flags == SubStringFlags::NONE) {
+ GotoIfNot(TaggedIsPositiveSmi(from), &runtime);
+ GotoIfNot(TaggedIsPositiveSmi(to), &runtime);
+ } else {
+ CSA_ASSERT(this, TaggedIsPositiveSmi(from));
+ CSA_ASSERT(this, TaggedIsPositiveSmi(to));
+ }
Node* const substr_length = SmiSub(to, from);
Node* const string_length = LoadStringLength(string);
@@ -3435,7 +3648,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
GotoIf(to_direct.is_external(), &external_string);
var_result.Bind(AllocAndCopyStringCharacters(
- this, context, direct_string, instance_type, offset, substr_length));
+ context, direct_string, instance_type, offset, substr_length));
Counters* counters = isolate()->counters();
IncrementCounter(counters->sub_string_native(), 1);
@@ -3448,9 +3661,8 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
{
Node* const fake_sequential_string = to_direct.PointerToString(&runtime);
- var_result.Bind(
- AllocAndCopyStringCharacters(this, context, fake_sequential_string,
- instance_type, offset, substr_length));
+ var_result.Bind(AllocAndCopyStringCharacters(
+ context, fake_sequential_string, instance_type, offset, substr_length));
Counters* counters = isolate()->counters();
IncrementCounter(counters->sub_string_native(), 1);
@@ -3468,8 +3680,14 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
BIND(&original_string_or_invalid_length);
{
- // Longer than original string's length or negative: unsafe arguments.
- GotoIf(SmiAbove(substr_length, string_length), &runtime);
+ if (flags == SubStringFlags::NONE) {
+ // Longer than original string's length or negative: unsafe arguments.
+ GotoIf(SmiAbove(substr_length, string_length), &runtime);
+ } else {
+ // with flag SubStringFlags::FROM_TO_ARE_BOUNDED, the only way we can
+ // get here is if substr_length is equal to string_length.
+ CSA_ASSERT(this, SmiEqual(substr_length, string_length));
+ }
// Equal length - check if {from, to} == {0, str.length}.
GotoIf(SmiAbove(from, SmiConstant(Smi::kZero)), &runtime);
@@ -3496,12 +3714,13 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from,
}
ToDirectStringAssembler::ToDirectStringAssembler(
- compiler::CodeAssemblerState* state, Node* string)
+ compiler::CodeAssemblerState* state, Node* string, Flags flags)
: CodeStubAssembler(state),
var_string_(this, MachineRepresentation::kTagged, string),
var_instance_type_(this, MachineRepresentation::kWord32),
var_offset_(this, MachineType::PointerRepresentation()),
- var_is_external_(this, MachineRepresentation::kWord32) {
+ var_is_external_(this, MachineRepresentation::kWord32),
+ flags_(flags) {
CSA_ASSERT(this, TaggedIsNotSmi(string));
CSA_ASSERT(this, IsString(string));
@@ -3558,16 +3777,20 @@ Node* ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
// Sliced string. Fetch parent and correct start index by offset.
BIND(&if_issliced);
{
- Node* const string = var_string_.value();
- Node* const sliced_offset =
- LoadAndUntagObjectField(string, SlicedString::kOffsetOffset);
- var_offset_.Bind(IntPtrAdd(var_offset_.value(), sliced_offset));
+ if (flags_ & kDontUnpackSlicedStrings) {
+ Goto(if_bailout);
+ } else {
+ Node* const string = var_string_.value();
+ Node* const sliced_offset =
+ LoadAndUntagObjectField(string, SlicedString::kOffsetOffset);
+ var_offset_.Bind(IntPtrAdd(var_offset_.value(), sliced_offset));
- Node* const parent = LoadObjectField(string, SlicedString::kParentOffset);
- var_string_.Bind(parent);
- var_instance_type_.Bind(LoadInstanceType(parent));
+ Node* const parent = LoadObjectField(string, SlicedString::kParentOffset);
+ var_string_.Bind(parent);
+ var_instance_type_.Bind(LoadInstanceType(parent));
- Goto(&dispatch);
+ Goto(&dispatch);
+ }
}
// Thin string. Fetch the actual string.
@@ -4269,6 +4492,22 @@ Node* CodeStubAssembler::ToString(Node* context, Node* input) {
return result.value();
}
+Node* CodeStubAssembler::ToString_Inline(Node* const context,
+ Node* const input) {
+ VARIABLE(var_result, MachineRepresentation::kTagged, input);
+ Label stub_call(this, Label::kDeferred), out(this);
+
+ GotoIf(TaggedIsSmi(input), &stub_call);
+ Branch(IsString(input), &out, &stub_call);
+
+ BIND(&stub_call);
+ var_result.Bind(CallBuiltin(Builtins::kToString, context, input));
+ Goto(&out);
+
+ BIND(&out);
+ return var_result.value();
+}
+
Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this);
VARIABLE(result, MachineRepresentation::kTagged);
@@ -4346,6 +4585,15 @@ Node* CodeStubAssembler::ToSmiLength(Node* input, Node* const context,
return result.value();
}
+Node* CodeStubAssembler::ToLength_Inline(Node* const context,
+ Node* const input) {
+ Node* const smi_zero = SmiConstant(0);
+ return Select(
+ TaggedIsSmi(input), [=] { return SmiMax(input, smi_zero); },
+ [=] { return CallBuiltin(Builtins::kToLength, context, input); },
+ MachineRepresentation::kTagged);
+}
+
Node* CodeStubAssembler::ToInteger(Node* context, Node* input,
ToIntegerTruncationMode mode) {
// We might need to loop once for ToNumber conversion.
@@ -4461,7 +4709,8 @@ void CodeStubAssembler::Use(Label* label) {
void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Variable* var_index, Label* if_keyisunique,
- Variable* var_unique, Label* if_bailout) {
+ Variable* var_unique, Label* if_bailout,
+ Label* if_notinternalized) {
DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep());
Comment("TryToName");
@@ -4500,7 +4749,8 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
STATIC_ASSERT(kNotInternalizedTag != 0);
Node* not_internalized =
Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask));
- GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout);
+ GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)),
+ if_notinternalized != nullptr ? if_notinternalized : if_bailout);
Goto(if_keyisunique);
BIND(&if_thinstring);
@@ -4512,6 +4762,30 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Goto(if_keyisindex);
}
+void CodeStubAssembler::TryInternalizeString(
+ Node* string, Label* if_index, Variable* var_index, Label* if_internalized,
+ Variable* var_internalized, Label* if_not_internalized, Label* if_bailout) {
+ DCHECK(var_index->rep() == MachineType::PointerRepresentation());
+ DCHECK(var_internalized->rep() == MachineRepresentation::kTagged);
+ Node* function = ExternalConstant(
+ ExternalReference::try_internalize_string_function(isolate()));
+ Node* result = CallCFunction1(MachineType::AnyTagged(),
+ MachineType::AnyTagged(), function, string);
+ Label internalized(this);
+ GotoIf(TaggedIsNotSmi(result), &internalized);
+ Node* word_result = SmiUntag(result);
+ GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kNotFound)),
+ if_not_internalized);
+ GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kUnsupported)),
+ if_bailout);
+ var_index->Bind(word_result);
+ Goto(if_index);
+
+ BIND(&internalized);
+ var_internalized->Bind(result);
+ Goto(if_internalized);
+}
+
template <typename Dictionary>
Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) {
Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize));
@@ -4524,9 +4798,10 @@ template Node* CodeStubAssembler::EntryToIndex<GlobalDictionary>(Node*, int);
template Node* CodeStubAssembler::EntryToIndex<SeededNumberDictionary>(Node*,
int);
+// This must be kept in sync with HashTableBase::ComputeCapacity().
Node* CodeStubAssembler::HashTableComputeCapacity(Node* at_least_space_for) {
- Node* capacity = IntPtrRoundUpToPowerOfTwo32(
- WordShl(at_least_space_for, IntPtrConstant(1)));
+ Node* capacity = IntPtrRoundUpToPowerOfTwo32(IntPtrAdd(
+ at_least_space_for, WordShr(at_least_space_for, IntPtrConstant(1))));
return IntPtrMax(capacity, IntPtrConstant(HashTableBase::kMinCapacity));
}
@@ -4541,29 +4816,6 @@ Node* CodeStubAssembler::IntPtrMin(Node* left, Node* right) {
}
template <class Dictionary>
-Node* CodeStubAssembler::GetNumberOfElements(Node* dictionary) {
- return LoadFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex);
-}
-
-template <class Dictionary>
-void CodeStubAssembler::SetNumberOfElements(Node* dictionary,
- Node* num_elements_smi) {
- StoreFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex,
- num_elements_smi, SKIP_WRITE_BARRIER);
-}
-
-template <class Dictionary>
-Node* CodeStubAssembler::GetNumberOfDeletedElements(Node* dictionary) {
- return LoadFixedArrayElement(dictionary,
- Dictionary::kNumberOfDeletedElementsIndex);
-}
-
-template <class Dictionary>
-Node* CodeStubAssembler::GetCapacity(Node* dictionary) {
- return LoadFixedArrayElement(dictionary, Dictionary::kCapacityIndex);
-}
-
-template <class Dictionary>
Node* CodeStubAssembler::GetNextEnumerationIndex(Node* dictionary) {
return LoadFixedArrayElement(dictionary,
Dictionary::kNextEnumerationIndexIndex);
@@ -5115,10 +5367,9 @@ void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
BIND(&if_inobject);
{
Comment("if_inobject");
- Node* field_offset =
- IntPtrMul(IntPtrSub(LoadMapInstanceSize(map),
- IntPtrSub(inobject_properties, field_index)),
- IntPtrConstant(kPointerSize));
+ Node* field_offset = TimesPointerSize(
+ IntPtrAdd(IntPtrSub(LoadMapInstanceSize(map), inobject_properties),
+ field_index));
Label if_double(this), if_tagged(this);
Branch(Word32NotEqual(representation,
@@ -5226,18 +5477,17 @@ Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
Node* context, Node* receiver,
Label* if_bailout) {
VARIABLE(var_value, MachineRepresentation::kTagged, value);
- Label done(this);
+ Label done(this), if_accessor_info(this, Label::kDeferred);
Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
GotoIf(Word32Equal(kind, Int32Constant(kData)), &done);
// Accessor case.
+ GotoIfNot(IsAccessorPair(value), &if_accessor_info);
+
+ // AccessorPair case.
{
Node* accessor_pair = value;
- GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
- Int32Constant(ACCESSOR_INFO_TYPE)),
- if_bailout);
- CSA_ASSERT(this, IsAccessorPair(accessor_pair));
Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
Node* getter_map = LoadMap(getter);
Node* instance_type = LoadMapInstanceType(getter_map);
@@ -5257,6 +5507,62 @@ Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
Goto(&done);
}
+ // AccessorInfo case.
+ BIND(&if_accessor_info);
+ {
+ Node* accessor_info = value;
+ CSA_ASSERT(this, IsAccessorInfo(value));
+ CSA_ASSERT(this, TaggedIsNotSmi(receiver));
+ Label if_array(this), if_function(this), if_value(this);
+
+ // Dispatch based on {receiver} instance type.
+ Node* receiver_map = LoadMap(receiver);
+ Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
+ GotoIf(IsJSArrayInstanceType(receiver_instance_type), &if_array);
+ GotoIf(IsJSFunctionInstanceType(receiver_instance_type), &if_function);
+ Branch(IsJSValueInstanceType(receiver_instance_type), &if_value,
+ if_bailout);
+
+ // JSArray AccessorInfo case.
+ BIND(&if_array);
+ {
+ // We only deal with the "length" accessor on JSArray.
+ GotoIfNot(IsLengthString(
+ LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
+ if_bailout);
+ var_value.Bind(LoadJSArrayLength(receiver));
+ Goto(&done);
+ }
+
+ // JSFunction AccessorInfo case.
+ BIND(&if_function);
+ {
+ // We only deal with the "prototype" accessor on JSFunction here.
+ GotoIfNot(IsPrototypeString(
+ LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
+ if_bailout);
+ GotoIf(IsSetWord32(LoadMapBitField(receiver_map),
+ 1 << Map::kHasNonInstancePrototype),
+ if_bailout);
+ var_value.Bind(LoadJSFunctionPrototype(receiver, if_bailout));
+ Goto(&done);
+ }
+
+ // JSValue AccessorInfo case.
+ BIND(&if_value);
+ {
+ // We only deal with the "length" accessor on JSValue string wrappers.
+ GotoIfNot(IsLengthString(
+ LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
+ if_bailout);
+ Node* receiver_value = LoadJSValueValue(receiver);
+ GotoIfNot(TaggedIsNotSmi(receiver_value), if_bailout);
+ GotoIfNot(IsString(receiver_value), if_bailout);
+ var_value.Bind(LoadStringLength(receiver_value));
+ Goto(&done);
+ }
+ }
+
BIND(&done);
return var_value.value();
}
@@ -5746,6 +6052,26 @@ void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* feedback_vector,
SKIP_WRITE_BARRIER);
}
+void CodeStubAssembler::CombineFeedback(Variable* existing_feedback,
+ Node* feedback) {
+ existing_feedback->Bind(SmiOr(existing_feedback->value(), feedback));
+}
+
+void CodeStubAssembler::CheckForAssociatedProtector(Node* name,
+ Label* if_protector) {
+ // This list must be kept in sync with LookupIterator::UpdateProtector!
+ // TODO(jkummerow): Would it be faster to have a bit in Symbol::flags()?
+ GotoIf(WordEqual(name, LoadRoot(Heap::kconstructor_stringRootIndex)),
+ if_protector);
+ GotoIf(WordEqual(name, LoadRoot(Heap::kiterator_symbolRootIndex)),
+ if_protector);
+ GotoIf(WordEqual(name, LoadRoot(Heap::kspecies_symbolRootIndex)),
+ if_protector);
+ GotoIf(WordEqual(name, LoadRoot(Heap::kis_concat_spreadable_symbolRootIndex)),
+ if_protector);
+ // Fall through if no case matched.
+}
+
Node* CodeStubAssembler::LoadReceiverMap(Node* receiver) {
return Select(TaggedIsSmi(receiver),
[=] { return LoadRoot(Heap::kHeapNumberMapRootIndex); },
@@ -6367,6 +6693,78 @@ Node* CodeStubAssembler::CreateWeakCellInFeedbackVector(Node* feedback_vector,
return cell;
}
+void CodeStubAssembler::HandleSlackTracking(Node* context, Node* object,
+ Node* initial_map,
+ int start_offset) {
+ Node* instance_size_words = ChangeUint32ToWord(LoadObjectField(
+ initial_map, Map::kInstanceSizeOffset, MachineType::Uint8()));
+ Node* instance_size = TimesPointerSize(instance_size_words);
+
+ // Perform in-object slack tracking if requested.
+ Node* bit_field3 = LoadMapBitField3(initial_map);
+ Label end(this), slack_tracking(this), finalize(this, Label::kDeferred);
+ GotoIf(IsSetWord32<Map::ConstructionCounter>(bit_field3), &slack_tracking);
+
+ // Initialize remaining fields.
+ {
+ Comment("no slack tracking");
+ InitializeFieldsWithRoot(object, IntPtrConstant(start_offset),
+ instance_size, Heap::kUndefinedValueRootIndex);
+ Goto(&end);
+ }
+
+ {
+ BIND(&slack_tracking);
+
+ // Decrease generous allocation count.
+ STATIC_ASSERT(Map::ConstructionCounter::kNext == 32);
+ Comment("update allocation count");
+ Node* new_bit_field3 = Int32Sub(
+ bit_field3, Int32Constant(1 << Map::ConstructionCounter::kShift));
+ StoreObjectFieldNoWriteBarrier(initial_map, Map::kBitField3Offset,
+ new_bit_field3,
+ MachineRepresentation::kWord32);
+ GotoIf(IsClearWord32<Map::ConstructionCounter>(new_bit_field3), &finalize);
+
+ Node* unused_fields = LoadObjectField(
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8());
+ Node* used_size = IntPtrSub(
+ instance_size, TimesPointerSize(ChangeUint32ToWord(unused_fields)));
+
+ Comment("initialize filler fields (no finalize)");
+ InitializeFieldsWithRoot(object, used_size, instance_size,
+ Heap::kOnePointerFillerMapRootIndex);
+
+ Comment("initialize undefined fields (no finalize)");
+ InitializeFieldsWithRoot(object, IntPtrConstant(start_offset), used_size,
+ Heap::kUndefinedValueRootIndex);
+ Goto(&end);
+ }
+
+ {
+ // Finalize the instance size.
+ BIND(&finalize);
+
+ Node* unused_fields = LoadObjectField(
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8());
+ Node* used_size = IntPtrSub(
+ instance_size, TimesPointerSize(ChangeUint32ToWord(unused_fields)));
+
+ Comment("initialize filler fields (finalize)");
+ InitializeFieldsWithRoot(object, used_size, instance_size,
+ Heap::kOnePointerFillerMapRootIndex);
+
+ Comment("initialize undefined fields (finalize)");
+ InitializeFieldsWithRoot(object, IntPtrConstant(start_offset), used_size,
+ Heap::kUndefinedValueRootIndex);
+
+ CallRuntime(Runtime::kFinalizeInstanceSize, context, initial_map);
+ Goto(&end);
+ }
+
+ BIND(&end);
+}
+
Node* CodeStubAssembler::BuildFastLoop(
const CodeStubAssembler::VariableList& vars, Node* start_index,
Node* end_index, const FastLoopBody& body, int increment,
@@ -6593,7 +6991,8 @@ void CodeStubAssembler::GotoUnlessNumberLessThan(Node* lhs, Node* rhs,
Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
Node* lhs, Node* rhs,
- Node* context) {
+ Node* context,
+ Variable* var_type_feedback) {
Label return_true(this), return_false(this), end(this);
VARIABLE(result, MachineRepresentation::kTagged);
@@ -6606,8 +7005,14 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
// conversions.
VARIABLE(var_lhs, MachineRepresentation::kTagged, lhs);
VARIABLE(var_rhs, MachineRepresentation::kTagged, rhs);
- Variable* loop_vars[2] = {&var_lhs, &var_rhs};
- Label loop(this, 2, loop_vars);
+ VariableList loop_variable_list({&var_lhs, &var_rhs}, zone());
+ if (var_type_feedback != nullptr) {
+ // Initialize the type feedback to None. The current feedback is combined
+ // with the previous feedback.
+ var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone));
+ loop_variable_list.Add(var_type_feedback, zone());
+ }
+ Label loop(this, loop_variable_list);
Goto(&loop);
BIND(&loop);
{
@@ -6628,6 +7033,10 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_rhsissmi);
{
// Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kSignedSmall));
+ }
switch (mode) {
case kLessThan:
BranchIfSmiLessThan(lhs, rhs, &return_true, &return_false);
@@ -6657,6 +7066,10 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
{
// Convert the {lhs} and {rhs} to floating point values, and
// perform a floating point comparison.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
var_fcmp_lhs.Bind(SmiToFloat64(lhs));
var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
Goto(&do_fcmp);
@@ -6664,6 +7077,11 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_rhsisnotnumber);
{
+ // The {rhs} is not a HeapNumber and {lhs} is an Smi.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
// Convert the {rhs} to a Number; we don't need to perform the
// dedicated ToPrimitive(rhs, hint Number) operation, as the
// ToNumber(rhs) will by itself already invoke ToPrimitive with
@@ -6694,6 +7112,10 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
{
// Convert the {lhs} and {rhs} to floating point values, and
// perform a floating point comparison.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
var_fcmp_rhs.Bind(SmiToFloat64(rhs));
Goto(&do_fcmp);
@@ -6701,6 +7123,11 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_lhsisnotnumber);
{
+ // The {lhs} is not a HeapNumber and {rhs} is an Smi.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
// Convert the {lhs} to a Number; we don't need to perform the
// dedicated ToPrimitive(lhs, hint Number) operation, as the
// ToNumber(lhs) will by itself already invoke ToPrimitive with
@@ -6731,6 +7158,10 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
{
// Convert the {lhs} and {rhs} to floating point values, and
// perform a floating point comparison.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
Goto(&do_fcmp);
@@ -6738,6 +7169,11 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_rhsisnotnumber);
{
+ // The {rhs} is not a HeapNumber and {lhs} is a HeapNumber.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
// Convert the {rhs} to a Number; we don't need to perform
// dedicated ToPrimitive(rhs, hint Number) operation, as the
// ToNumber(rhs) will by itself already invoke ToPrimitive with
@@ -6772,6 +7208,10 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_rhsisstring);
{
// Both {lhs} and {rhs} are strings.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kString));
+ }
switch (mode) {
case kLessThan:
result.Bind(CallStub(CodeFactory::StringLessThan(isolate()),
@@ -6801,6 +7241,11 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_rhsisnotstring);
{
+ // The {lhs} is a String and {rhs} is not a String.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
// The {lhs} is a String, while {rhs} is neither a Number nor a
// String, so we need to call ToPrimitive(rhs, hint Number) if
// {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
@@ -6833,6 +7278,41 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
BIND(&if_lhsisnotstring);
{
+ if (var_type_feedback != nullptr) {
+ // The {lhs} is not an Smi, HeapNumber or String and {rhs} is not
+ // an Smi: collect NumberOrOddball feedback if {lhs} is an Oddball
+ // and {rhs} is either a HeapNumber or Oddball.
+ Label collect_any_feedback(this), collect_oddball_feedback(this),
+ collect_feedback_done(this);
+ GotoIfNot(
+ Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)),
+ &collect_any_feedback);
+
+ Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
+ GotoIf(Word32Equal(rhs_instance_type,
+ Int32Constant(HEAP_NUMBER_TYPE)),
+ &collect_oddball_feedback);
+ Branch(
+ Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)),
+ &collect_oddball_feedback, &collect_any_feedback);
+
+ BIND(&collect_oddball_feedback);
+ {
+ CombineFeedback(
+ var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumberOrOddball));
+ Goto(&collect_feedback_done);
+ }
+
+ BIND(&collect_any_feedback);
+ {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ Goto(&collect_feedback_done);
+ }
+
+ BIND(&collect_feedback_done);
+ }
// The {lhs} is neither a Number nor a String, so we need to call
// ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
// ToNumber(lhs) and ToNumber(rhs) in the other cases.
@@ -6905,52 +7385,91 @@ Node* CodeStubAssembler::RelationalComparison(RelationalComparisonMode mode,
return result.value();
}
-namespace {
+Node* CodeStubAssembler::CollectFeedbackForString(Node* instance_type) {
+ Node* feedback = SelectSmiConstant(
+ Word32Equal(
+ Word32And(instance_type, Int32Constant(kIsNotInternalizedMask)),
+ Int32Constant(kInternalizedTag)),
+ CompareOperationFeedback::kInternalizedString,
+ CompareOperationFeedback::kString);
+ return feedback;
+}
-void GenerateEqual_Same(CodeStubAssembler* assembler, Node* value,
- CodeStubAssembler::Label* if_equal,
- CodeStubAssembler::Label* if_notequal) {
+void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
+ Label* if_notequal,
+ Variable* var_type_feedback) {
// In case of abstract or strict equality checks, we need additional checks
// for NaN values because they are not considered equal, even if both the
// left and the right hand side reference exactly the same value.
- typedef CodeStubAssembler::Label Label;
-
// Check if {value} is a Smi or a HeapObject.
- Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
- assembler->Branch(assembler->TaggedIsSmi(value), &if_valueissmi,
- &if_valueisnotsmi);
+ Label if_valueissmi(this), if_valueisnotsmi(this);
+ Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
- assembler->BIND(&if_valueisnotsmi);
+ BIND(&if_valueisnotsmi);
{
// Load the map of {value}.
- Node* value_map = assembler->LoadMap(value);
+ Node* value_map = LoadMap(value);
// Check if {value} (and therefore {rhs}) is a HeapNumber.
- Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
- assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber,
- &if_valueisnotnumber);
+ Label if_valueisnumber(this), if_valueisnotnumber(this);
+ Branch(IsHeapNumberMap(value_map), &if_valueisnumber, &if_valueisnotnumber);
- assembler->BIND(&if_valueisnumber);
+ BIND(&if_valueisnumber);
{
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
+
// Convert {value} (and therefore {rhs}) to floating point value.
- Node* value_value = assembler->LoadHeapNumberValue(value);
+ Node* value_value = LoadHeapNumberValue(value);
// Check if the HeapNumber value is a NaN.
- assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
+ BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
}
- assembler->BIND(&if_valueisnotnumber);
- assembler->Goto(if_equal);
+ BIND(&if_valueisnotnumber);
+ if (var_type_feedback != nullptr) {
+ // Collect type feedback.
+ Node* instance_type = LoadMapInstanceType(value_map);
+
+ Label if_valueisstring(this), if_valueisnotstring(this);
+ Branch(IsStringInstanceType(instance_type), &if_valueisstring,
+ &if_valueisnotstring);
+
+ BIND(&if_valueisstring);
+ {
+ CombineFeedback(var_type_feedback,
+ CollectFeedbackForString(instance_type));
+ Goto(if_equal);
+ }
+
+ BIND(&if_valueisnotstring);
+ {
+ var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
+ GotoIfNot(IsJSReceiverInstanceType(instance_type), if_equal);
+
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kReceiver));
+ Goto(if_equal);
+ }
+ } else {
+ Goto(if_equal);
+ }
}
- assembler->BIND(&if_valueissmi);
- assembler->Goto(if_equal);
+ BIND(&if_valueissmi);
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kSignedSmall));
+ }
+ Goto(if_equal);
}
-} // namespace
// ES6 section 7.2.12 Abstract Equality Comparison
-Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
+Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context,
+ Variable* var_type_feedback) {
// This is a slightly optimized version of Object::Equals represented as
// scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
// change something functionality wise in here, remember to update the
@@ -6969,8 +7488,14 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// conversions.
VARIABLE(var_lhs, MachineRepresentation::kTagged, lhs);
VARIABLE(var_rhs, MachineRepresentation::kTagged, rhs);
- Variable* loop_vars[2] = {&var_lhs, &var_rhs};
- Label loop(this, 2, loop_vars);
+ VariableList loop_variable_list({&var_lhs, &var_rhs}, zone());
+ if (var_type_feedback != nullptr) {
+ // Initialize the type feedback to None. The current feedback is combined
+ // with the previous feedback.
+ var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone));
+ loop_variable_list.Add(var_type_feedback, zone());
+ }
+ Label loop(this, loop_variable_list);
Goto(&loop);
BIND(&loop);
{
@@ -6986,7 +7511,7 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
{
// The {lhs} and {rhs} reference the exact same value, yet we need special
// treatment for HeapNumber, as NaN is not equal to NaN.
- GenerateEqual_Same(this, lhs, &if_equal, &if_notequal);
+ GenerateEqual_Same(lhs, &if_equal, &if_notequal, var_type_feedback);
}
BIND(&if_notsame);
@@ -7004,6 +7529,10 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
BIND(&if_rhsissmi);
// We have already checked for {lhs} and {rhs} being the same value, so
// if both are Smis when we get here they must not be equal.
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kSignedSmall));
+ }
Goto(&if_notequal);
BIND(&if_rhsisnotsmi);
@@ -7021,11 +7550,21 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// perform a floating point comparison.
var_fcmp_lhs.Bind(SmiToFloat64(lhs));
var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
Goto(&do_fcmp);
}
BIND(&if_rhsisnotnumber);
{
+ // The {lhs} is Smi and {rhs} is not HeapNumber or Smi.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
+
// Load the instance type of the {rhs}.
Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
@@ -7132,7 +7671,7 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
Switch(lhs_instance_type, &if_lhsisreceiver, case_values, case_labels,
arraysize(case_values));
for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
- Bind(case_labels[i]);
+ BIND(case_labels[i]);
Goto(&if_lhsisstring);
delete case_labels[i];
}
@@ -7151,6 +7690,14 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// string comparison then.
Callable callable = CodeFactory::StringEqual(isolate());
result.Bind(CallStub(callable, context, lhs, rhs));
+ if (var_type_feedback != nullptr) {
+ Node* lhs_feedback =
+ CollectFeedbackForString(lhs_instance_type);
+ Node* rhs_feedback =
+ CollectFeedbackForString(rhs_instance_type);
+ CombineFeedback(var_type_feedback,
+ SmiOr(lhs_feedback, rhs_feedback));
+ }
Goto(&end);
}
@@ -7162,6 +7709,10 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// handling below (for {rhs} being a String).
var_lhs.Bind(rhs);
var_rhs.Bind(lhs);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
Goto(&loop);
}
}
@@ -7179,6 +7730,10 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// perform a floating point comparison.
var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
+ if (var_type_feedback != nullptr) {
+ CombineFeedback(var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
Goto(&do_fcmp);
}
@@ -7187,6 +7742,12 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
// The {lhs} is a Number, the {rhs} is some other HeapObject.
Label if_rhsisstring(this, Label::kDeferred),
if_rhsisnotstring(this);
+
+ if (var_type_feedback != nullptr) {
+ // The {lhs} is number and {rhs} is not Smi or HeapNumber.
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
&if_rhsisnotstring);
@@ -7242,6 +7803,11 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
BIND(&if_lhsisoddball);
{
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
+
// The {lhs} is an Oddball and {rhs} is some other HeapObject.
Label if_lhsisboolean(this), if_lhsisnotboolean(this);
Node* boolean_map = BooleanMapConstant();
@@ -7285,6 +7851,11 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
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);
@@ -7320,6 +7891,13 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
BIND(&if_rhsisreceiver);
{
+ if (var_type_feedback != nullptr) {
+ // The {lhs} and {rhs} are receivers.
+ CombineFeedback(
+ var_type_feedback,
+ SmiConstant(CompareOperationFeedback::kReceiver));
+ }
+
// Both {lhs} and {rhs} are different JSReceiver references, so
// this cannot be considered equal.
Goto(&if_notequal);
@@ -7327,6 +7905,11 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
BIND(&if_rhsisnotreceiver);
{
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kAny));
+ }
+
// Check if {rhs} is Null or Undefined (an undetectable check
// is sufficient here, since we already know that {rhs} is not
// a JSReceiver).
@@ -7399,7 +7982,8 @@ Node* CodeStubAssembler::Equal(Node* lhs, Node* rhs, Node* context) {
return result.value();
}
-Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
+Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs,
+ Variable* var_type_feedback) {
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
// mode; for kNegateResult mode we properly negate the result.
//
@@ -7455,7 +8039,10 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
{
// The {lhs} and {rhs} reference the exact same value, yet we need special
// treatment for HeapNumber, as NaN is not equal to NaN.
- GenerateEqual_Same(this, lhs, &if_equal, &if_notequal);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone));
+ }
+ GenerateEqual_Same(lhs, &if_equal, &if_notequal, var_type_feedback);
}
BIND(&if_notsame);
@@ -7463,6 +8050,10 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
// The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber
// and String they can still be considered equal.
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
+ }
+
// Check if {lhs} is a Smi or a HeapObject.
Label if_lhsissmi(this), if_lhsisnotsmi(this);
Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
@@ -7488,6 +8079,11 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
Node* lhs_value = LoadHeapNumberValue(lhs);
Node* rhs_value = SmiToFloat64(rhs);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
+
// Perform a floating point comparison of {lhs} and {rhs}.
Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
}
@@ -7507,6 +8103,11 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
Node* lhs_value = LoadHeapNumberValue(lhs);
Node* rhs_value = LoadHeapNumberValue(rhs);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
+
// Perform a floating point comparison of {lhs} and {rhs}.
Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
}
@@ -7530,6 +8131,9 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
// Load the instance type of {lhs}.
Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
+ // Load the instance type of {rhs}.
+ Node* rhs_instance_type = LoadInstanceType(rhs);
+
// Check if {lhs} is a String.
Label if_lhsisstring(this), if_lhsisnotstring(this);
Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring,
@@ -7537,9 +8141,6 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
BIND(&if_lhsisstring);
{
- // Load the instance type of {rhs}.
- Node* rhs_instance_type = LoadInstanceType(rhs);
-
// Check if {rhs} is also a String.
Label if_rhsisstring(this, Label::kDeferred),
if_rhsisnotstring(this);
@@ -7549,6 +8150,13 @@ 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);
+ Node* rhs_feedback =
+ CollectFeedbackForString(rhs_instance_type);
+ var_type_feedback->Bind(SmiOr(lhs_feedback, rhs_feedback));
+ }
result.Bind(CallStub(callable, NoContextConstant(), lhs, rhs));
Goto(&end);
}
@@ -7558,6 +8166,14 @@ 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));
+ }
Goto(&if_notequal);
}
}
@@ -7574,6 +8190,10 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
BIND(&if_rhsissmi);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kSignedSmall));
+ }
Goto(&if_notequal);
BIND(&if_rhsisnotsmi);
@@ -7591,6 +8211,11 @@ Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs) {
Node* lhs_value = SmiToFloat64(lhs);
Node* rhs_value = LoadHeapNumberValue(rhs);
+ if (var_type_feedback != nullptr) {
+ var_type_feedback->Bind(
+ SmiConstant(CompareOperationFeedback::kNumber));
+ }
+
// Perform a floating point comparison of {lhs} and {rhs}.
Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
}
@@ -8333,14 +8958,13 @@ Node* CodeStubAssembler::AllocateJSArrayIterator(Node* array, Node* array_map,
return iterator;
}
-Node* CodeStubAssembler::ArraySpeciesCreate(Node* context, Node* originalArray,
- Node* len) {
- // TODO(mvstanton): Install a fast path as well, which avoids the runtime
+Node* CodeStubAssembler::TypedArraySpeciesCreateByLength(Node* context,
+ Node* originalArray,
+ Node* len) {
+ // TODO(tebbi): Install a fast path as well, which avoids the runtime
// call.
- Node* constructor =
- CallRuntime(Runtime::kArraySpeciesConstructor, context, originalArray);
- return ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
- len);
+ return CallRuntime(Runtime::kTypedArraySpeciesCreateByLength, context,
+ originalArray, len);
}
Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
@@ -8358,8 +8982,8 @@ CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler, Node* argc,
argc_mode_(mode),
argc_(argc),
arguments_(nullptr),
- fp_(fp != nullptr ? fp : assembler->LoadFramePointer()) {
- Node* offset = assembler->ElementOffsetFromIndex(
+ fp_(fp != nullptr ? fp : assembler_->LoadFramePointer()) {
+ Node* offset = assembler_->ElementOffsetFromIndex(
argc_, FAST_ELEMENTS, mode,
(StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kPointerSize);
arguments_ = assembler_->IntPtrAdd(fp_, offset);
@@ -8392,6 +9016,28 @@ Node* CodeStubArguments::AtIndex(int index) const {
return AtIndex(assembler_->IntPtrConstant(index));
}
+Node* CodeStubArguments::GetOptionalArgumentValue(int index,
+ Node* default_value) {
+ typedef CodeStubAssembler::Variable Variable;
+ Variable result(assembler_, MachineRepresentation::kTagged);
+ CodeStubAssembler::Label argument_missing(assembler_),
+ argument_done(assembler_, &result);
+
+ assembler_->GotoIf(assembler_->UintPtrOrSmiGreaterThanOrEqual(
+ assembler_->IntPtrOrSmiConstant(index, argc_mode_),
+ argc_, argc_mode_),
+ &argument_missing);
+ result.Bind(AtIndex(index));
+ assembler_->Goto(&argument_done);
+
+ assembler_->BIND(&argument_missing);
+ result.Bind(default_value);
+ assembler_->Goto(&argument_done);
+
+ assembler_->BIND(&argument_done);
+ return result.value();
+}
+
void CodeStubArguments::ForEach(
const CodeStubAssembler::VariableList& vars,
const CodeStubArguments::ForEachBodyFunction& body, Node* first, Node* last,
@@ -8442,6 +9088,11 @@ Node* CodeStubAssembler::IsHoleyFastElementsKind(Node* elements_kind) {
return Word32Equal(holey_elements, Int32Constant(1));
}
+Node* CodeStubAssembler::IsElementsKindGreaterThan(
+ Node* target_kind, ElementsKind reference_kind) {
+ return Int32GreaterThan(target_kind, Int32Constant(reference_kind));
+}
+
Node* CodeStubAssembler::IsDebugActive() {
Node* is_debug_active = Load(
MachineType::Uint8(),