Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 53b9835ab46eb2334bbb526d346c290eeb5a05d5..52a64bc4e78511d1b31010b9a739d6b5ab37f76c 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -2904,6 +2904,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, |
@@ -3013,188 +3029,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(); |
} |
@@ -3313,27 +3199,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); |
@@ -3356,132 +3229,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); |
+ // and extract the underlying string. |
- // 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); |
- |
- 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())); |
+ 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); |
@@ -3492,12 +3289,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); |
@@ -3508,7 +3304,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); |
} |
@@ -3542,45 +3338,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); |
@@ -3592,12 +3373,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)); |
} |
@@ -3605,13 +3386,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); |
} |
@@ -3619,14 +3400,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(parent); |
+ var_instance_type_.Bind(LoadInstanceType(parent)); |
Goto(&dispatch); |
} |
@@ -3634,36 +3415,65 @@ 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); |
- 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(&dispatch); |
} |
// 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, |
@@ -3671,9 +3481,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); |