Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 4a96e81ebf843ed9848a40311de0c7b36e4127c6..84867265cbc61814a95db26fd58f4a73c6ccadd6 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -1572,6 +1572,9 @@ Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value, |
| 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); |
| @@ -1591,8 +1594,10 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
| Variable var_result(this, MachineRepresentation::kTagged); |
| // Compute the SeqOneByteString size and check if it fits into new space. |
| - Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
| - if_join(this); |
| + Label if_lengthiszero(this), if_sizeissmall(this), |
| + if_notsizeissmall(this, Label::kDeferred), if_join(this); |
| + GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); |
| + |
| Node* raw_size = GetArrayAllocationSize( |
| length, UINT8_ELEMENTS, mode, |
| SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| @@ -1625,6 +1630,12 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
| Goto(&if_join); |
| } |
| + Bind(&if_lengthiszero); |
| + { |
| + var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); |
| + Goto(&if_join); |
| + } |
| + |
| Bind(&if_join); |
| return var_result.value(); |
| } |
| @@ -1632,6 +1643,9 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
| 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); |
| @@ -1651,8 +1665,10 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, |
| Variable var_result(this, MachineRepresentation::kTagged); |
| // Compute the SeqTwoByteString size and check if it fits into new space. |
| - Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
| - if_join(this); |
| + Label if_lengthiszero(this), if_sizeissmall(this), |
| + if_notsizeissmall(this, Label::kDeferred), if_join(this); |
| + GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); |
| + |
| Node* raw_size = GetArrayAllocationSize( |
| length, UINT16_ELEMENTS, mode, |
| SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| @@ -1687,6 +1703,12 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, |
| Goto(&if_join); |
| } |
| + Bind(&if_lengthiszero); |
| + { |
| + var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); |
| + Goto(&if_join); |
| + } |
| + |
| Bind(&if_join); |
| return var_result.value(); |
| } |
| @@ -3002,7 +3024,7 @@ Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| // Translate the {index} into a Word. |
| index = ParameterToWord(index, parameter_mode); |
| - // We may need to loop in case of cons or sliced strings. |
| + // We may need to loop in case of cons, thin, or sliced strings. |
| Variable var_index(this, MachineType::PointerRepresentation()); |
| Variable var_result(this, MachineRepresentation::kWord32); |
| Variable var_string(this, MachineRepresentation::kTagged); |
| @@ -3154,14 +3176,29 @@ Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| Bind(&if_stringisnotexternal); |
| { |
| - // 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); |
| + 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); |
| + } |
| } |
| } |
| } |
| @@ -3292,11 +3329,13 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| 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); |
| @@ -3337,7 +3376,8 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| // 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)); |
| + STATIC_ASSERT(kIsIndirectStringMask == |
| + (kSlicedStringTag & kConsStringTag & kThinStringTag)); |
| STATIC_ASSERT(kIsIndirectStringMask != 0); |
| Label underlying_unpacked(this); |
| GotoIf(Word32Equal( |
| @@ -3345,13 +3385,14 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| Int32Constant(0)), |
| &underlying_unpacked); |
| - // The subject string is either a sliced or cons string. |
| + // The subject string is a sliced, cons, or thin string. |
| - Label sliced_string(this); |
| - GotoIf(Word32NotEqual( |
| - Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), |
| - Int32Constant(0)), |
| - &sliced_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); |
| // Cons string. Check whether it is flat, then fetch first part. |
| // Flat cons strings have an empty second part. |
| @@ -3363,14 +3404,33 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| 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(string, SlicedString::kOffsetOffset); |
| + Node* sliced_offset = |
| + LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); |
| var_from.Bind(SmiAdd(from, sliced_offset)); |
| Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
| @@ -3509,12 +3569,49 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| return var_result.value(); |
| } |
| +void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string, |
| + Node* instance_type, |
| + Variable* var_did_something) { |
| + Label deref(this), done(this, var_did_something); |
| + Node* representation = |
| + Word32And(instance_type, Int32Constant(kStringRepresentationMask)); |
| + STATIC_ASSERT(ThinString::kActualOffset == ConsString::kFirstOffset); |
| + GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), &deref); |
| + GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), &done); |
| + // Cons string. |
| + Node* rhs = LoadObjectField(var_string->value(), ConsString::kSecondOffset); |
| + GotoIf(WordEqual(rhs, EmptyStringConstant()), &deref); |
|
Igor Sheludko
2017/01/18 14:55:20
Maybe we should stop using ConsStrings this way on
Jakob Kummerow
2017/01/19 10:20:16
Yes, maybe.
Pro: code checking for indirect strin
|
| + Goto(&done); |
| + |
| + Bind(&deref); |
|
Igor Sheludko
2017/01/18 14:55:20
STATIC_ASSERT(ConsString::kFirstOffset == ThinStri
Jakob Kummerow
2017/01/19 10:20:16
Done.
|
| + var_string->Bind( |
| + LoadObjectField(var_string->value(), ThinString::kActualOffset)); |
| + var_did_something->Bind(IntPtrConstant(1)); |
| + Goto(&done); |
| + |
| + Bind(&done); |
| +} |
| + |
| +void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left, |
| + Node* left_instance_type, |
| + Variable* var_right, |
| + Node* right_instance_type, |
| + Label* did_something) { |
| + Variable var_did_something(this, MachineType::PointerRepresentation()); |
| + var_did_something.Bind(IntPtrConstant(0)); |
| + MaybeDerefIndirectString(var_left, left_instance_type, &var_did_something); |
| + MaybeDerefIndirectString(var_right, right_instance_type, &var_did_something); |
| + |
| + GotoIf(WordNotEqual(var_did_something.value(), IntPtrConstant(0)), |
| + did_something); |
| + // Fall through if neither string was an indirect string. |
| +} |
| + |
| Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, |
| AllocationFlags flags) { |
| Label check_right(this); |
| Label runtime(this, Label::kDeferred); |
| Label cons(this); |
| - Label non_cons(this); |
| Variable result(this, MachineRepresentation::kTagged); |
| Label done(this, &result); |
| Label done_native(this, &result); |
| @@ -3532,72 +3629,92 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, |
| Goto(&done_native); |
| Bind(&cons); |
| - CSA_ASSERT(this, TaggedIsSmi(left_length)); |
| - CSA_ASSERT(this, TaggedIsSmi(right_length)); |
| - Node* new_length = SmiAdd(left_length, right_length); |
| - GotoIf(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)), |
| - &runtime); |
| - |
| - GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)), |
| - &non_cons); |
| - |
| - result.Bind(NewConsString(context, new_length, left, right, flags)); |
| - Goto(&done_native); |
| - |
| - Bind(&non_cons); |
| + { |
| + CSA_ASSERT(this, TaggedIsSmi(left_length)); |
| + CSA_ASSERT(this, TaggedIsSmi(right_length)); |
| + Node* new_length = SmiAdd(left_length, right_length); |
| + GotoIf(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)), |
| + &runtime); |
| - Comment("Full string concatenate"); |
| - Node* left_instance_type = LoadInstanceType(left); |
| - Node* right_instance_type = LoadInstanceType(right); |
| - // Compute intersection and difference of instance types. |
| + Variable var_left(this, MachineRepresentation::kTagged); |
| + Variable var_right(this, MachineRepresentation::kTagged); |
| + Variable* input_vars[2] = {&var_left, &var_right}; |
| + Label non_cons(this, 2, input_vars); |
| + Label slow(this, Label::kDeferred); |
| + var_left.Bind(left); |
| + var_right.Bind(right); |
| + GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)), |
| + &non_cons); |
| + |
| + result.Bind(NewConsString(context, new_length, var_left.value(), |
| + var_right.value(), flags)); |
| + Goto(&done_native); |
| - Node* ored_instance_types = Word32Or(left_instance_type, right_instance_type); |
| - Node* xored_instance_types = |
| - Word32Xor(left_instance_type, right_instance_type); |
| + Bind(&non_cons); |
| - // 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)), |
| - &runtime); |
| + Comment("Full string concatenate"); |
| + Node* left_instance_type = LoadInstanceType(var_left.value()); |
| + Node* right_instance_type = LoadInstanceType(var_right.value()); |
| + // Compute intersection and difference of instance types. |
| - Label two_byte(this); |
| - GotoIf(Word32Equal( |
| - Word32And(ored_instance_types, Int32Constant(kStringEncodingMask)), |
| - Int32Constant(kTwoByteStringTag)), |
| - &two_byte); |
| - // One-byte sequential string case |
| - Node* new_string = |
| - AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS); |
| - CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), |
| - SmiConstant(Smi::kZero), left_length, |
| - String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, |
| - SMI_PARAMETERS); |
| - CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), left_length, |
| - right_length, String::ONE_BYTE_ENCODING, |
| - String::ONE_BYTE_ENCODING, SMI_PARAMETERS); |
| - result.Bind(new_string); |
| - Goto(&done_native); |
| + Node* ored_instance_types = |
| + Word32Or(left_instance_type, right_instance_type); |
| + Node* xored_instance_types = |
| + Word32Xor(left_instance_type, right_instance_type); |
| - Bind(&two_byte); |
| - { |
| - // Two-byte sequential string case |
| - new_string = AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS); |
| - CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), |
| + // 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); |
| + |
| + Label two_byte(this); |
| + GotoIf(Word32Equal(Word32And(ored_instance_types, |
| + Int32Constant(kStringEncodingMask)), |
| + Int32Constant(kTwoByteStringTag)), |
| + &two_byte); |
| + // 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::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, |
| + String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, |
| SMI_PARAMETERS); |
| - CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), |
| - left_length, right_length, String::TWO_BYTE_ENCODING, |
| - String::TWO_BYTE_ENCODING, SMI_PARAMETERS); |
| + CopyStringCharacters(var_right.value(), new_string, SmiConstant(Smi::kZero), |
| + left_length, right_length, String::ONE_BYTE_ENCODING, |
| + String::ONE_BYTE_ENCODING, SMI_PARAMETERS); |
| result.Bind(new_string); |
| Goto(&done_native); |
| - } |
| + Bind(&two_byte); |
| + { |
| + // 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, |
| + String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, |
| + SMI_PARAMETERS); |
| + result.Bind(new_string); |
| + Goto(&done_native); |
| + } |
| + |
| + Bind(&slow); |
| + { |
| + // Try to unwrap indirect strings, restart the above attempt on success. |
| + MaybeDerefIndirectStrings(&var_left, left_instance_type, &var_right, |
| + right_instance_type, &non_cons); |
| + Goto(&runtime); |
| + } |
| + } |
| Bind(&runtime); |
| { |
| result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right)); |
| @@ -4143,45 +4260,6 @@ Node* CodeStubAssembler::ToString(Node* context, Node* input) { |
| 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); |
| @@ -4323,17 +4401,19 @@ void CodeStubAssembler::Use(Label* label) { |
| void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
| Variable* var_index, Label* if_keyisunique, |
| - Label* if_bailout) { |
| + Variable* var_unique, 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); |
| + Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(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); |
| @@ -4350,6 +4430,12 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
| 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 = |
| @@ -4357,6 +4443,10 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
| 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); |
| var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); |
| Goto(if_keyisindex); |
| @@ -5206,9 +5296,11 @@ void CodeStubAssembler::TryPrototypeChainLookup( |
| } |
| 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, if_bailout); |
| + TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, |
| + if_bailout); |
| Bind(&if_iskeyunique); |
| { |
| @@ -5230,8 +5322,8 @@ void CodeStubAssembler::TryPrototypeChainLookup( |
| Label next_proto(this); |
| lookup_property_in_holder(receiver, var_holder.value(), holder_map, |
| - holder_instance_type, key, &next_proto, |
| - if_bailout); |
| + holder_instance_type, var_unique.value(), |
| + &next_proto, if_bailout); |
| Bind(&next_proto); |
| // Bailout if it can be an integer indexed exotic case. |