Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index a6f831d935b87423125bc7b4f2993f364ce6058b..97f77e22244d1b043c4cadfe483a075a9425b256 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -1566,9 +1566,6 @@ |
Node* CodeStubAssembler::AllocateSeqOneByteString(int length, |
AllocationFlags flags) { |
Comment("AllocateSeqOneByteString"); |
- if (length == 0) { |
- return LoadRoot(Heap::kempty_stringRootIndex); |
- } |
Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); |
DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); |
StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); |
@@ -1588,10 +1585,8 @@ |
Variable var_result(this, MachineRepresentation::kTagged); |
// Compute the SeqOneByteString size and check if it fits into new space. |
- Label if_lengthiszero(this), if_sizeissmall(this), |
- if_notsizeissmall(this, Label::kDeferred), if_join(this); |
- GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); |
- |
+ Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
+ if_join(this); |
Node* raw_size = GetArrayAllocationSize( |
length, UINT8_ELEMENTS, mode, |
SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
@@ -1624,12 +1619,6 @@ |
Goto(&if_join); |
} |
- Bind(&if_lengthiszero); |
- { |
- var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); |
- Goto(&if_join); |
- } |
- |
Bind(&if_join); |
return var_result.value(); |
} |
@@ -1637,9 +1626,6 @@ |
Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, |
AllocationFlags flags) { |
Comment("AllocateSeqTwoByteString"); |
- if (length == 0) { |
- return LoadRoot(Heap::kempty_stringRootIndex); |
- } |
Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); |
DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); |
StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); |
@@ -1659,10 +1645,8 @@ |
Variable var_result(this, MachineRepresentation::kTagged); |
// Compute the SeqTwoByteString size and check if it fits into new space. |
- Label if_lengthiszero(this), if_sizeissmall(this), |
- if_notsizeissmall(this, Label::kDeferred), if_join(this); |
- GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); |
- |
+ Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
+ if_join(this); |
Node* raw_size = GetArrayAllocationSize( |
length, UINT16_ELEMENTS, mode, |
SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
@@ -1694,12 +1678,6 @@ |
CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
mode == SMI_PARAMETERS ? length : SmiFromWord(length)); |
var_result.Bind(result); |
- Goto(&if_join); |
- } |
- |
- Bind(&if_lengthiszero); |
- { |
- var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); |
Goto(&if_join); |
} |
@@ -3013,7 +2991,7 @@ |
// Translate the {index} into a Word. |
index = ParameterToWord(index, parameter_mode); |
- // We may need to loop in case of cons, thin, or sliced strings. |
+ // We may need to loop in case of cons or sliced strings. |
Variable var_index(this, MachineType::PointerRepresentation()); |
Variable var_result(this, MachineRepresentation::kWord32); |
Variable var_string(this, MachineRepresentation::kTagged); |
@@ -3165,29 +3143,14 @@ |
Bind(&if_stringisnotexternal); |
{ |
- Label if_stringissliced(this), if_stringisthin(this); |
- Branch( |
- Word32Equal(Word32And(string_instance_type, |
- Int32Constant(kStringRepresentationMask)), |
- Int32Constant(kSlicedStringTag)), |
- &if_stringissliced, &if_stringisthin); |
- Bind(&if_stringissliced); |
- { |
- // The {string} is a SlicedString, continue with its parent. |
- Node* string_offset = |
- LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); |
- Node* string_parent = |
- LoadObjectField(string, SlicedString::kParentOffset); |
- var_index.Bind(IntPtrAdd(index, string_offset)); |
- var_string.Bind(string_parent); |
- Goto(&loop); |
- } |
- Bind(&if_stringisthin); |
- { |
- // The {string} is a ThinString, continue with its actual value. |
- var_string.Bind(LoadObjectField(string, ThinString::kActualOffset)); |
- Goto(&loop); |
- } |
+ // The {string} is a SlicedString, continue with its parent. |
+ Node* string_offset = |
+ LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); |
+ Node* string_parent = |
+ LoadObjectField(string, SlicedString::kParentOffset); |
+ var_index.Bind(IntPtrAdd(index, string_offset)); |
+ var_string.Bind(string_parent); |
+ Goto(&loop); |
} |
} |
} |
@@ -3318,13 +3281,11 @@ |
Label runtime(this); |
Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. |
- Variable var_representation(this, MachineRepresentation::kWord32); // Int32. |
Variable var_result(this, MachineRepresentation::kTagged); // String. |
Variable var_from(this, MachineRepresentation::kTagged); // Smi. |
Variable var_string(this, MachineRepresentation::kTagged); // String. |
var_instance_type.Bind(Int32Constant(0)); |
- var_representation.Bind(Int32Constant(0)); |
var_string.Bind(string); |
var_from.Bind(from); |
@@ -3365,8 +3326,7 @@ |
// and put the underlying string into var_string. |
// If the string is not indirect, it can only be sequential or external. |
- STATIC_ASSERT(kIsIndirectStringMask == |
- (kSlicedStringTag & kConsStringTag & kThinStringTag)); |
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
STATIC_ASSERT(kIsIndirectStringMask != 0); |
Label underlying_unpacked(this); |
GotoIf(Word32Equal( |
@@ -3374,14 +3334,13 @@ |
Int32Constant(0)), |
&underlying_unpacked); |
- // The subject string is a sliced, cons, or thin string. |
- |
- Label sliced_string(this), thin_or_sliced(this); |
- var_representation.Bind( |
- Word32And(instance_type, Int32Constant(kStringRepresentationMask))); |
- GotoIf( |
- Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)), |
- &thin_or_sliced); |
+ // The subject string is either a sliced or cons string. |
+ |
+ Label sliced_string(this); |
+ GotoIf(Word32NotEqual( |
+ Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), |
+ Int32Constant(0)), |
+ &sliced_string); |
// Cons string. Check whether it is flat, then fetch first part. |
// Flat cons strings have an empty second part. |
@@ -3393,33 +3352,14 @@ |
Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); |
var_string.Bind(first_string_part); |
var_instance_type.Bind(LoadInstanceType(first_string_part)); |
- var_representation.Bind(Word32And( |
- var_instance_type.value(), Int32Constant(kStringRepresentationMask))); |
- |
- // The loaded first part might be a thin string. |
- Branch(Word32Equal(Word32And(var_instance_type.value(), |
- Int32Constant(kIsIndirectStringMask)), |
- Int32Constant(0)), |
- &underlying_unpacked, &thin_or_sliced); |
- } |
- |
- Bind(&thin_or_sliced); |
- { |
- GotoIf(Word32Equal(var_representation.value(), |
- Int32Constant(kSlicedStringTag)), |
- &sliced_string); |
- Node* actual_string = |
- LoadObjectField(var_string.value(), ThinString::kActualOffset); |
- var_string.Bind(actual_string); |
- var_instance_type.Bind(LoadInstanceType(actual_string)); |
+ |
Goto(&underlying_unpacked); |
} |
Bind(&sliced_string); |
{ |
// Fetch parent and correct start index by offset. |
- Node* sliced_offset = |
- LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); |
+ Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); |
var_from.Bind(SmiAdd(from, sliced_offset)); |
Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
@@ -4192,6 +4132,45 @@ |
return result.value(); |
} |
+Node* CodeStubAssembler::FlattenString(Node* string) { |
+ CSA_ASSERT(this, IsString(string)); |
+ Variable var_result(this, MachineRepresentation::kTagged); |
+ var_result.Bind(string); |
+ |
+ Node* instance_type = LoadInstanceType(string); |
+ |
+ // Check if the {string} is not a ConsString (i.e. already flat). |
+ Label is_cons(this, Label::kDeferred), is_flat_in_cons(this), end(this); |
+ { |
+ GotoUnless(Word32Equal(Word32And(instance_type, |
+ Int32Constant(kStringRepresentationMask)), |
+ Int32Constant(kConsStringTag)), |
+ &end); |
+ |
+ // Check whether the right hand side is the empty string (i.e. if |
+ // this is really a flat string in a cons string). |
+ Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); |
+ Branch(WordEqual(rhs, EmptyStringConstant()), &is_flat_in_cons, &is_cons); |
+ } |
+ |
+ // Bail out to the runtime. |
+ Bind(&is_cons); |
+ { |
+ var_result.Bind( |
+ CallRuntime(Runtime::kFlattenString, NoContextConstant(), string)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&is_flat_in_cons); |
+ { |
+ var_result.Bind(LoadObjectField(string, ConsString::kFirstOffset)); |
+ Goto(&end); |
+ } |
+ |
+ Bind(&end); |
+ return var_result.value(); |
+} |
+ |
Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { |
Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); |
Variable result(this, MachineRepresentation::kTagged); |
@@ -4333,19 +4312,17 @@ |
void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
Variable* var_index, Label* if_keyisunique, |
- Variable* var_unique, Label* if_bailout) { |
+ Label* if_bailout) { |
DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); |
- DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep()); |
Comment("TryToName"); |
- Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this); |
+ Label if_hascachedindex(this), if_keyisnotindex(this); |
// Handle Smi and HeapNumber keys. |
var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); |
Goto(if_keyisindex); |
Bind(&if_keyisnotindex); |
Node* key_map = LoadMap(key); |
- var_unique->Bind(key); |
// Symbols are unique. |
GotoIf(IsSymbolMap(key_map), if_keyisunique); |
Node* key_instance_type = LoadMapInstanceType(key_map); |
@@ -4362,21 +4339,11 @@ |
Node* not_an_index = |
Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); |
GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); |
- // Check if we have a ThinString. |
- GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)), |
- &if_thinstring); |
- GotoIf( |
- Word32Equal(key_instance_type, Int32Constant(THIN_ONE_BYTE_STRING_TYPE)), |
- &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)), if_bailout); |
- Goto(if_keyisunique); |
- |
- Bind(&if_thinstring); |
- var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset)); |
Goto(if_keyisunique); |
Bind(&if_hascachedindex); |
@@ -5228,11 +5195,9 @@ |
} |
Variable var_index(this, MachineType::PointerRepresentation()); |
- Variable var_unique(this, MachineRepresentation::kTagged); |
Label if_keyisindex(this), if_iskeyunique(this); |
- TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, |
- if_bailout); |
+ TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout); |
Bind(&if_iskeyunique); |
{ |
@@ -5254,8 +5219,8 @@ |
Label next_proto(this); |
lookup_property_in_holder(receiver, var_holder.value(), holder_map, |
- holder_instance_type, var_unique.value(), |
- &next_proto, if_bailout); |
+ holder_instance_type, key, &next_proto, |
+ if_bailout); |
Bind(&next_proto); |
// Bailout if it can be an integer indexed exotic case. |