Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 9a27b511da277e9f810a4f345ea9e3ccc7de64ee..225c3c02f2176a66b8e0e5b927e9585bcc7a730e 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -2912,6 +2912,22 @@ Node* CodeStubAssembler::IsSequentialStringInstanceType(Node* instance_type) { |
| Int32Constant(kSeqStringTag)); |
| } |
| +Node* CodeStubAssembler::IsExternalStringInstanceType(Node* instance_type) { |
| + CSA_ASSERT(this, IsStringInstanceType(instance_type)); |
| + return Word32Equal( |
| + Word32And(instance_type, Int32Constant(kStringRepresentationMask)), |
| + Int32Constant(kExternalStringTag)); |
| +} |
| + |
| +Node* CodeStubAssembler::IsShortExternalStringInstanceType( |
| + Node* instance_type) { |
| + CSA_ASSERT(this, IsStringInstanceType(instance_type)); |
| + STATIC_ASSERT(kShortExternalStringTag != 0); |
| + return Word32NotEqual( |
| + Word32And(instance_type, Int32Constant(kShortExternalStringMask)), |
| + Int32Constant(0)); |
| +} |
| + |
| Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { |
| STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| return Int32GreaterThanOrEqual(instance_type, |
| @@ -3017,188 +3033,58 @@ Node* CodeStubAssembler::IsJSFunction(Node* object) { |
| Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| ParameterMode parameter_mode) { |
| CSA_ASSERT(this, IsString(string)); |
| + |
| // Translate the {index} into a Word. |
| - index = ParameterToWord(index, parameter_mode); |
| + Node* const int_index = ParameterToWord(index, parameter_mode); |
| - // We may need to loop in case of cons, thin, or sliced strings. |
| - Variable var_index(this, MachineType::PointerRepresentation(), index); |
| - Variable var_string(this, MachineRepresentation::kTagged, string); |
| Variable var_result(this, MachineRepresentation::kWord32); |
| - Variable* loop_vars[] = {&var_index, &var_string}; |
| - Label done_loop(this, &var_result), loop(this, 2, loop_vars); |
| - Goto(&loop); |
| - Bind(&loop); |
| - { |
| - // Load the current {index}. |
| - index = var_index.value(); |
| - // Load the current {string}. |
| - string = var_string.value(); |
| + Label out(this, &var_result), runtime_generic(this), runtime_external(this); |
| - // Load the instance type of the {string}. |
| - Node* string_instance_type = LoadInstanceType(string); |
| + ToDirectStringAssembler to_direct(state(), string); |
| + Node* const direct_string = to_direct.TryToDirect(&runtime_generic); |
| + Node* const offset = IntPtrAdd(int_index, to_direct.offset()); |
| + Node* const instance_type = to_direct.instance_type(); |
| - // Check if the {string} is a SeqString. |
| - Label if_stringissequential(this), if_stringisnotsequential(this); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kStringRepresentationMask)), |
| - Int32Constant(kSeqStringTag)), |
| - &if_stringissequential, &if_stringisnotsequential); |
| + Node* const string_data = to_direct.PointerToData(&runtime_external); |
| - Bind(&if_stringissequential); |
| - { |
| - // Check if the {string} is a TwoByteSeqString or a OneByteSeqString. |
| - Label if_stringistwobyte(this), if_stringisonebyte(this); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kStringEncodingMask)), |
| - Int32Constant(kTwoByteStringTag)), |
| - &if_stringistwobyte, &if_stringisonebyte); |
| - |
| - Bind(&if_stringisonebyte); |
| - { |
| - var_result.Bind( |
| - Load(MachineType::Uint8(), string, |
| - IntPtrAdd(index, IntPtrConstant(SeqOneByteString::kHeaderSize - |
| - kHeapObjectTag)))); |
| - Goto(&done_loop); |
| - } |
| - |
| - Bind(&if_stringistwobyte); |
| - { |
| - var_result.Bind( |
| - Load(MachineType::Uint16(), string, |
| - IntPtrAdd(WordShl(index, IntPtrConstant(1)), |
| - IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| - kHeapObjectTag)))); |
| - Goto(&done_loop); |
| - } |
| - } |
| - |
| - Bind(&if_stringisnotsequential); |
| - { |
| - // Check if the {string} is a ConsString. |
| - Label if_stringiscons(this), if_stringisnotcons(this); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kStringRepresentationMask)), |
| - Int32Constant(kConsStringTag)), |
| - &if_stringiscons, &if_stringisnotcons); |
| - |
| - Bind(&if_stringiscons); |
| - { |
| - // Check whether the right hand side is the empty string (i.e. if |
| - // this is really a flat string in a cons string). If that is not |
| - // the case we flatten the string first. |
| - Label if_rhsisempty(this), if_rhsisnotempty(this, Label::kDeferred); |
| - Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); |
| - Branch(WordEqual(rhs, EmptyStringConstant()), &if_rhsisempty, |
| - &if_rhsisnotempty); |
| - |
| - Bind(&if_rhsisempty); |
| - { |
| - // Just operate on the left hand side of the {string}. |
| - var_string.Bind(LoadObjectField(string, ConsString::kFirstOffset)); |
| - Goto(&loop); |
| - } |
| - |
| - Bind(&if_rhsisnotempty); |
| - { |
| - // Flatten the {string} and lookup in the resulting string. |
| - var_string.Bind(CallRuntime(Runtime::kFlattenString, |
| - NoContextConstant(), string)); |
| - Goto(&loop); |
| - } |
| - } |
| + // Check if the {string} is a TwoByteSeqString or a OneByteSeqString. |
| + Label if_stringistwobyte(this), if_stringisonebyte(this); |
| + Branch(IsOneByteStringInstanceType(instance_type), &if_stringisonebyte, |
| + &if_stringistwobyte); |
| - Bind(&if_stringisnotcons); |
| - { |
| - // Check if the {string} is an ExternalString. |
| - Label if_stringisexternal(this), if_stringisnotexternal(this); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kStringRepresentationMask)), |
| - Int32Constant(kExternalStringTag)), |
| - &if_stringisexternal, &if_stringisnotexternal); |
| - |
| - Bind(&if_stringisexternal); |
| - { |
| - // Check if the {string} is a short external string. |
| - Label if_stringisnotshort(this), |
| - if_stringisshort(this, Label::kDeferred); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kShortExternalStringMask)), |
| - Int32Constant(0)), |
| - &if_stringisnotshort, &if_stringisshort); |
| - |
| - Bind(&if_stringisnotshort); |
| - { |
| - // Load the actual resource data from the {string}. |
| - Node* string_resource_data = |
| - LoadObjectField(string, ExternalString::kResourceDataOffset, |
| - MachineType::Pointer()); |
| - |
| - // Check if the {string} is a TwoByteExternalString or a |
| - // OneByteExternalString. |
| - Label if_stringistwobyte(this), if_stringisonebyte(this); |
| - Branch(Word32Equal(Word32And(string_instance_type, |
| - Int32Constant(kStringEncodingMask)), |
| - Int32Constant(kTwoByteStringTag)), |
| - &if_stringistwobyte, &if_stringisonebyte); |
| - |
| - Bind(&if_stringisonebyte); |
| - { |
| - var_result.Bind( |
| - Load(MachineType::Uint8(), string_resource_data, index)); |
| - Goto(&done_loop); |
| - } |
| + Bind(&if_stringisonebyte); |
| + { |
| + var_result.Bind(Load(MachineType::Uint8(), string_data, offset)); |
| + Goto(&out); |
| + } |
| - Bind(&if_stringistwobyte); |
| - { |
| - var_result.Bind(Load(MachineType::Uint16(), string_resource_data, |
| - WordShl(index, IntPtrConstant(1)))); |
| - Goto(&done_loop); |
| - } |
| - } |
| + Bind(&if_stringistwobyte); |
| + { |
| + var_result.Bind(Load(MachineType::Uint16(), string_data, |
| + WordShl(offset, IntPtrConstant(1)))); |
| + Goto(&out); |
| + } |
| - Bind(&if_stringisshort); |
| - { |
| - // The {string} might be compressed, call the runtime. |
| - var_result.Bind(SmiToWord32( |
| - CallRuntime(Runtime::kExternalStringGetChar, |
| - NoContextConstant(), string, SmiTag(index)))); |
| - Goto(&done_loop); |
| - } |
| - } |
| + Bind(&runtime_generic); |
| + { |
| + Node* const smi_index = ParameterToTagged(index, parameter_mode); |
| + Node* const result = CallRuntime(Runtime::kStringCharCodeAtRT, |
| + NoContextConstant(), string, smi_index); |
| + var_result.Bind(SmiToWord32(result)); |
| + Goto(&out); |
| + } |
| - 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); |
| - } |
| - } |
| - } |
| - } |
| + Bind(&runtime_external); |
| + { |
| + Node* const result = |
| + CallRuntime(Runtime::kExternalStringGetChar, NoContextConstant(), |
| + direct_string, SmiTag(offset)); |
| + var_result.Bind(SmiToWord32(result)); |
| + Goto(&out); |
| } |
| - Bind(&done_loop); |
| + Bind(&out); |
| return var_result.value(); |
| } |
| @@ -3317,27 +3203,14 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
| Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| Node* to) { |
| - Label end(this); |
| - Label runtime(this); |
| - |
| - Node* const int_zero = Int32Constant(0); |
| - |
| - // Int32 variables. |
| - Variable var_instance_type(this, MachineRepresentation::kWord32, int_zero); |
| - Variable var_representation(this, MachineRepresentation::kWord32, int_zero); |
| - |
| - Variable var_from(this, MachineRepresentation::kTagged, from); // Smi. |
| - Variable var_string(this, MachineRepresentation::kTagged, string); // String. |
| - Variable var_result(this, MachineRepresentation::kTagged); // String. |
| + Variable var_result(this, MachineRepresentation::kTagged); |
| + ToDirectStringAssembler to_direct(state(), string); |
| + Label end(this), runtime(this); |
| // Make sure first argument is a string. |
| CSA_ASSERT(this, TaggedIsNotSmi(string)); |
| CSA_ASSERT(this, IsString(string)); |
| - // Load the instance type of the {string}. |
| - Node* const instance_type = LoadInstanceType(string); |
| - var_instance_type.Bind(instance_type); |
| - |
| // Make sure that both from and to are non-negative smis. |
| GotoIfNot(TaggedIsPositiveSmi(from), &runtime); |
| @@ -3360,132 +3233,56 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| // TODO(jgruber): Add an additional case for substring of length == 0? |
| // Deal with different string types: update the index if necessary |
| - // 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 != 0); |
| - Label underlying_unpacked(this); |
| - GotoIf(Word32Equal( |
| - Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), |
| - Int32Constant(0)), |
| - &underlying_unpacked); |
| - |
| - // The subject string is a sliced, cons, or thin string. |
| - |
| - Label thin_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. |
| - { |
| - GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), |
| - EmptyStringConstant()), |
| - &runtime); |
| + // and extract the underlying string. |
| - 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_string); |
| - } |
| - |
| - Bind(&thin_or_sliced); |
| - { |
| - GotoIf( |
| - Word32Equal(var_representation.value(), Int32Constant(kThinStringTag)), |
| - &thin_string); |
| - // Otherwise it's a sliced string. |
| - // Fetch parent and correct start index by offset. |
| - Node* sliced_offset = |
| - LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); |
| - var_from.Bind(SmiAdd(from, sliced_offset)); |
| - |
| - Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
| - var_string.Bind(slice_parent); |
| - |
| - Node* slice_parent_instance_type = LoadInstanceType(slice_parent); |
| - var_instance_type.Bind(slice_parent_instance_type); |
| - |
| - // The loaded parent might be a thin string. |
| - Branch(Word32Equal(Word32And(var_instance_type.value(), |
| - Int32Constant(kIsIndirectStringMask)), |
| - Int32Constant(0)), |
| - &underlying_unpacked, &thin_string); |
| - } |
| - |
| - Bind(&thin_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); |
| - } |
| + Node* const direct_string = to_direct.TryToDirect(&runtime); |
| + Node* const offset = SmiAdd(from, SmiTag(to_direct.offset())); |
|
Camillo Bruni
2017/03/14 09:06:04
Future refactoring: make offset an intptr, from wh
jgruber
2017/03/16 08:44:54
Acknowledged.
|
| + Node* const instance_type = to_direct.instance_type(); |
| // The subject string can only be external or sequential string of either |
| // encoding at this point. |
| Label external_string(this); |
| - Bind(&underlying_unpacked); |
| { |
| if (FLAG_string_slices) { |
| - Label copy_routine(this); |
| + Label next(this); |
| // Short slice. Copy instead of slicing. |
| GotoIf(SmiLessThan(substr_length, |
| SmiConstant(Smi::FromInt(SlicedString::kMinLength))), |
| - ©_routine); |
| + &next); |
| // Allocate new sliced string. |
| - Label two_byte_slice(this); |
| - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
| - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| - |
| Counters* counters = isolate()->counters(); |
| IncrementCounter(counters->sub_string_native(), 1); |
| - GotoIf(Word32Equal(Word32And(var_instance_type.value(), |
| - Int32Constant(kStringEncodingMask)), |
| - Int32Constant(0)), |
| - &two_byte_slice); |
| + Label one_byte_slice(this), two_byte_slice(this); |
| + Branch(IsOneByteStringInstanceType(to_direct.instance_type()), |
| + &one_byte_slice, &two_byte_slice); |
| - var_result.Bind(AllocateSlicedOneByteString( |
| - substr_length, var_string.value(), var_from.value())); |
| - Goto(&end); |
| + Bind(&one_byte_slice); |
| + { |
| + var_result.Bind( |
| + AllocateSlicedOneByteString(substr_length, direct_string, offset)); |
| + Goto(&end); |
| + } |
| Bind(&two_byte_slice); |
| + { |
| + var_result.Bind( |
| + AllocateSlicedTwoByteString(substr_length, direct_string, offset)); |
| + Goto(&end); |
| + } |
| - var_result.Bind(AllocateSlicedTwoByteString( |
| - substr_length, var_string.value(), var_from.value())); |
| - Goto(&end); |
| - |
| - Bind(©_routine); |
| + Bind(&next); |
| } |
| // The subject string can only be external or sequential string of either |
| // encoding at this point. |
| - STATIC_ASSERT(kExternalStringTag != 0); |
| - STATIC_ASSERT(kSeqStringTag == 0); |
| - GotoIfNot(Word32Equal(Word32And(var_instance_type.value(), |
| - Int32Constant(kExternalStringTag)), |
| - Int32Constant(0)), |
| - &external_string); |
| + GotoIf(to_direct.is_external(), &external_string); |
| var_result.Bind(AllocAndCopyStringCharacters( |
| - this, context, var_string.value(), var_instance_type.value(), |
| - var_from.value(), substr_length)); |
| + this, context, direct_string, instance_type, offset, substr_length)); |
| Counters* counters = isolate()->counters(); |
| IncrementCounter(counters->sub_string_native(), 1); |
| @@ -3496,12 +3293,11 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| // Handle external string. |
| Bind(&external_string); |
| { |
| - Node* const fake_sequential_string = TryDerefExternalString( |
| - var_string.value(), var_instance_type.value(), &runtime); |
| + Node* const fake_sequential_string = to_direct.PointerToString(&runtime); |
| - var_result.Bind(AllocAndCopyStringCharacters( |
| - this, context, fake_sequential_string, var_instance_type.value(), |
| - var_from.value(), substr_length)); |
| + var_result.Bind( |
| + AllocAndCopyStringCharacters(this, context, fake_sequential_string, |
| + instance_type, offset, substr_length)); |
| Counters* counters = isolate()->counters(); |
| IncrementCounter(counters->sub_string_native(), 1); |
| @@ -3512,7 +3308,7 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| // Substrings of length 1 are generated through CharCodeAt and FromCharCode. |
| Bind(&single_char); |
| { |
| - Node* char_code = StringCharCodeAt(var_string.value(), var_from.value()); |
| + Node* char_code = StringCharCodeAt(string, from); |
| var_result.Bind(StringFromCharCode(char_code)); |
| Goto(&end); |
| } |
| @@ -3546,45 +3342,30 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| return var_result.value(); |
| } |
| -namespace { |
| - |
| -Node* IsExternalStringInstanceType(CodeStubAssembler* a, |
| - Node* const instance_type) { |
| - CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); |
| - return a->Word32Equal( |
| - a->Word32And(instance_type, a->Int32Constant(kStringRepresentationMask)), |
| - a->Int32Constant(kExternalStringTag)); |
| -} |
| +ToDirectStringAssembler::ToDirectStringAssembler( |
| + compiler::CodeAssemblerState* state, Node* string) |
| + : 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) { |
| + CSA_ASSERT(this, TaggedIsNotSmi(string)); |
| + CSA_ASSERT(this, IsString(string)); |
| -Node* IsShortExternalStringInstanceType(CodeStubAssembler* a, |
| - Node* const instance_type) { |
| - CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); |
| - STATIC_ASSERT(kShortExternalStringTag != 0); |
| - return a->Word32NotEqual( |
| - a->Word32And(instance_type, a->Int32Constant(kShortExternalStringMask)), |
| - a->Int32Constant(0)); |
| + var_string_.Bind(string); |
| + var_offset_.Bind(IntPtrConstant(0)); |
| + var_instance_type_.Bind(LoadInstanceType(string)); |
| + var_is_external_.Bind(Int32Constant(0)); |
| } |
| -} // namespace |
| - |
| -void CodeStubAssembler::TryUnpackString(Variable* var_string, |
| - Variable* var_offset, |
| - Variable* var_instance_type, |
| - Label* if_bailout) { |
| - DCHECK_EQ(var_string->rep(), MachineType::PointerRepresentation()); |
| - DCHECK_EQ(var_offset->rep(), MachineType::PointerRepresentation()); |
| - DCHECK_EQ(var_instance_type->rep(), MachineRepresentation::kWord32); |
| - CSA_ASSERT(this, IsString(var_string->value())); |
| - |
| - Label out(this); |
| - |
| - VariableList vars({var_string, var_offset, var_instance_type}, zone()); |
| +Node* ToDirectStringAssembler::TryToDirect(Label* if_bailout) { |
| + VariableList vars({&var_string_, &var_offset_, &var_instance_type_}, zone()); |
| Label dispatch(this, vars); |
| - Label if_isdirect(this); |
| - Label if_iscons(this, Label::kDeferred); |
| - Label if_isexternal(this, Label::kDeferred); |
| - Label if_issliced(this, Label::kDeferred); |
| - Label if_isthin(this, Label::kDeferred); |
| + Label if_iscons(this); |
| + Label if_isexternal(this); |
| + Label if_issliced(this); |
| + Label if_isthin(this); |
| + Label out(this); |
| Goto(&dispatch); |
| @@ -3596,12 +3377,12 @@ void CodeStubAssembler::TryUnpackString(Variable* var_string, |
| kSlicedStringTag, kThinStringTag, |
| }; |
| Label* labels[] = { |
| - &if_isdirect, &if_iscons, &if_isexternal, &if_issliced, &if_isthin, |
| + &out, &if_iscons, &if_isexternal, &if_issliced, &if_isthin, |
| }; |
| STATIC_ASSERT(arraysize(values) == arraysize(labels)); |
| Node* const representation = Word32And( |
| - var_instance_type->value(), Int32Constant(kStringRepresentationMask)); |
| + var_instance_type_.value(), Int32Constant(kStringRepresentationMask)); |
| Switch(representation, if_bailout, values, labels, arraysize(values)); |
| } |
| @@ -3609,13 +3390,13 @@ void CodeStubAssembler::TryUnpackString(Variable* var_string, |
| // Flat cons strings have an empty second part. |
| Bind(&if_iscons); |
| { |
| - Node* const string = var_string->value(); |
| + Node* const string = var_string_.value(); |
| GotoIfNot(IsEmptyString(LoadObjectField(string, ConsString::kSecondOffset)), |
| if_bailout); |
| Node* const lhs = LoadObjectField(string, ConsString::kFirstOffset); |
| - var_string->Bind(BitcastTaggedToWord(lhs)); |
| - var_instance_type->Bind(LoadInstanceType(lhs)); |
| + var_string_.Bind(lhs); |
| + var_instance_type_.Bind(LoadInstanceType(lhs)); |
| Goto(&dispatch); |
| } |
| @@ -3623,14 +3404,14 @@ void CodeStubAssembler::TryUnpackString(Variable* var_string, |
| // Sliced string. Fetch parent and correct start index by offset. |
| Bind(&if_issliced); |
| { |
| - Node* const string = var_string->value(); |
| + Node* const string = var_string_.value(); |
| Node* const sliced_offset = |
| - LoadObjectField(string, SlicedString::kOffsetOffset); |
| - var_offset->Bind(IntPtrAdd(var_offset->value(), SmiUntag(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(BitcastTaggedToWord(parent)); |
| - var_instance_type->Bind(LoadInstanceType(parent)); |
| + var_string_.Bind(LoadObjectField(string, SlicedString::kParentOffset)); |
| + var_instance_type_.Bind(LoadInstanceType(parent)); |
| Goto(&dispatch); |
| } |
| @@ -3638,37 +3419,66 @@ void CodeStubAssembler::TryUnpackString(Variable* var_string, |
| // Thin string. Fetch the actual string. |
| Bind(&if_isthin); |
| { |
| - Node* const string = var_string->value(); |
| + Node* const string = var_string_.value(); |
| Node* const actual_string = |
| LoadObjectField(string, ThinString::kActualOffset); |
| Node* const actual_instance_type = LoadInstanceType(actual_string); |
| CSA_ASSERT(this, IsSequentialStringInstanceType(actual_instance_type)); |
| - var_string->Bind(BitcastTaggedToWord(actual_string)); |
| - var_instance_type->Bind(actual_instance_type); |
| + var_string_.Bind(actual_string); |
| + var_instance_type_.Bind(actual_instance_type); |
| - Goto(&if_isdirect); |
| + Goto(&out); |
| } |
| // External string. |
| Bind(&if_isexternal); |
| - { |
| - Node* const string = var_string->value(); |
| - Node* const faked_seq_string = |
| - TryDerefExternalString(string, var_instance_type->value(), if_bailout); |
| + var_is_external_.Bind(Int32Constant(1)); |
| + Goto(&out); |
| - STATIC_ASSERT(kSeqStringTag == 0x0); |
| - Node* const faked_seq_instance_type = Word32Xor( |
| - var_instance_type->value(), Int32Constant(kExternalStringTag)); |
| - CSA_ASSERT(this, IsSequentialStringInstanceType(faked_seq_instance_type)); |
| + Bind(&out); |
| + return var_string_.value(); |
| +} |
| + |
| +Node* ToDirectStringAssembler::TryToSequential(StringPointerKind ptr_kind, |
| + Label* if_bailout) { |
| + CHECK(ptr_kind == PTR_TO_DATA || ptr_kind == PTR_TO_STRING); |
| + |
| + Variable var_result(this, MachineType::PointerRepresentation()); |
| + Label out(this), if_issequential(this), if_isexternal(this); |
| + Branch(is_external(), &if_isexternal, &if_issequential); |
| + |
| + Bind(&if_issequential); |
| + { |
| + STATIC_ASSERT(SeqOneByteString::kHeaderSize == |
| + SeqTwoByteString::kHeaderSize); |
| + Node* result = BitcastTaggedToWord(var_string_.value()); |
| + if (ptr_kind == PTR_TO_DATA) { |
| + result = IntPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize - |
| + kHeapObjectTag)); |
| + } |
| + var_result.Bind(result); |
| + Goto(&out); |
| + } |
| - var_string->Bind(faked_seq_string); |
| - var_instance_type->Bind(faked_seq_instance_type); |
| + Bind(&if_isexternal); |
| + { |
| + GotoIf(IsShortExternalStringInstanceType(var_instance_type_.value()), |
| + if_bailout); |
| - Goto(&if_isdirect); |
| + Node* const string = var_string_.value(); |
| + Node* result = LoadObjectField(string, ExternalString::kResourceDataOffset, |
| + MachineType::Pointer()); |
| + if (ptr_kind == PTR_TO_STRING) { |
| + result = IntPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize - |
| + kHeapObjectTag)); |
| + } |
| + var_result.Bind(result); |
| + Goto(&out); |
| } |
| - Bind(&if_isdirect); |
| + Bind(&out); |
| + return var_result.value(); |
| } |
| Node* CodeStubAssembler::TryDerefExternalString(Node* const string, |
| @@ -3676,9 +3486,8 @@ Node* CodeStubAssembler::TryDerefExternalString(Node* const string, |
| Label* if_bailout) { |
| Label out(this); |
| - USE(IsExternalStringInstanceType); |
| - CSA_ASSERT(this, IsExternalStringInstanceType(this, instance_type)); |
| - GotoIf(IsShortExternalStringInstanceType(this, instance_type), if_bailout); |
| + CSA_ASSERT(this, IsExternalStringInstanceType(instance_type)); |
| + GotoIf(IsShortExternalStringInstanceType(instance_type), if_bailout); |
| // Move the pointer so that offset-wise, it looks like a sequential string. |
| STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |