Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 6adec9aff6fd100da4efb4b4baa942b281566f2f..ea2eb303f57d2c630497d7a37c3e7f1ad16050a3 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -1350,6 +1350,40 @@ Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent, |
| return result; |
| } |
| +Node* CodeStubAssembler::AllocateOneByteConsString(Node* length, Node* first, |
| + Node* second) { |
| + Node* result = Allocate(ConsString::kSize); |
| + Node* map = LoadRoot(Heap::kConsOneByteStringMapRootIndex); |
| + StoreMapNoWriteBarrier(result, map); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length, |
| + MachineRepresentation::kTagged); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset, |
| + Int32Constant(String::kEmptyHashField), |
| + MachineRepresentation::kWord32); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first, |
| + MachineRepresentation::kTagged); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second, |
| + MachineRepresentation::kTagged); |
| + return result; |
| +} |
| + |
| +Node* CodeStubAssembler::AllocateTwoByteConsString(Node* length, Node* first, |
| + Node* second) { |
| + Node* result = Allocate(ConsString::kSize); |
| + Node* map = LoadRoot(Heap::kConsStringMapRootIndex); |
| + StoreMapNoWriteBarrier(result, map); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length, |
| + MachineRepresentation::kTagged); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset, |
| + Int32Constant(String::kEmptyHashField), |
| + MachineRepresentation::kWord32); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first, |
| + MachineRepresentation::kTagged); |
| + StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second, |
| + MachineRepresentation::kTagged); |
| + return result; |
| +} |
| + |
| Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, |
| Node* index, Node* input) { |
| Node* const max_length = |
| @@ -1687,6 +1721,7 @@ void CodeStubAssembler::CopyFixedArrayElements( |
| void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, |
| compiler::Node* to_string, |
| compiler::Node* from_index, |
| + compiler::Node* to_index, |
| compiler::Node* character_count, |
| String::Encoding encoding) { |
| Label out(this); |
| @@ -1704,20 +1739,22 @@ void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, |
| { |
| Node* byte_count = SmiUntag(character_count); |
| Node* from_byte_index = SmiUntag(from_index); |
| + Node* to_byte_index = SmiUntag(to_index); |
| if (encoding == String::ONE_BYTE_ENCODING) { |
| const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; |
| from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); |
| limit_offset = IntPtrAdd(from_offset, byte_count); |
| - to_offset = IntPtrConstant(offset); |
| + to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); |
| } else { |
| STATIC_ASSERT(2 == sizeof(uc16)); |
| byte_count = WordShl(byte_count, 1); |
| from_byte_index = WordShl(from_byte_index, 1); |
| + to_byte_index = WordShl(to_byte_index, 1); |
| const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; |
| from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); |
| limit_offset = IntPtrAdd(from_offset, byte_count); |
| - to_offset = IntPtrConstant(offset); |
| + to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); |
| } |
| } |
| @@ -2515,6 +2552,8 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
| Label end(a), two_byte_sequential(a); |
| Variable var_result(a, MachineRepresentation::kTagged); |
| + Node* const smi_zero = a->SmiConstant(Smi::FromInt(0)); |
|
Igor Sheludko
2016/10/13 10:45:16
Smi::kZero, here and below.
jgruber
2016/10/13 10:50:48
Done.
|
| + |
| STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
| a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, |
| a->Int32Constant(kStringEncodingMask)), |
| @@ -2525,7 +2564,7 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
| { |
| Node* result = |
| a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); |
| - a->CopyStringCharacters(from, result, from_index, character_count, |
| + a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
| String::ONE_BYTE_ENCODING); |
| var_result.Bind(result); |
| @@ -2537,7 +2576,7 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
| { |
| Node* result = |
| a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); |
| - a->CopyStringCharacters(from, result, from_index, character_count, |
| + a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
| String::TWO_BYTE_ENCODING); |
| var_result.Bind(result); |
| @@ -2772,6 +2811,146 @@ Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| return var_result.value(); |
| } |
| +Node* CodeStubAssembler::StringConcat(Node* context, Node* first, |
| + Node* second) { |
| + Variable var_result(this, MachineRepresentation::kTagged); |
| + |
| + Label out(this), runtime(this, Label::kDeferred); |
| + |
| + // TODO(jgruber): Handle indirect, external, and two-byte strings. |
| + |
| + Node* const one_byte_seq_mask = Int32Constant( |
| + kIsIndirectStringMask | kExternalStringTag | kStringEncodingMask); |
| + Node* const expected_masked = Int32Constant(kOneByteStringTag); |
| + |
| + Node* const first_instance_type = LoadInstanceType(first); |
| + GotoUnless(Word32Equal(Word32And(first_instance_type, one_byte_seq_mask), |
| + expected_masked), |
| + &runtime); |
| + |
| + Node* const second_instance_type = LoadInstanceType(second); |
| + GotoUnless(Word32Equal(Word32And(second_instance_type, one_byte_seq_mask), |
| + expected_masked), |
| + &runtime); |
| + |
| + Node* const smi_zero = SmiConstant(Smi::FromInt(0)); |
| + Node* const first_length = LoadStringLength(first); |
| + Node* const second_length = LoadStringLength(second); |
| + Node* const length = SmiAdd(first_length, second_length); |
| + |
| + Label if_makeseqstring(this), if_makeconsstring(this); |
| + Node* const min_cons_length = |
| + SmiConstant(Smi::FromInt(ConsString::kMinLength)); |
| + Branch(SmiLessThan(length, min_cons_length), &if_makeseqstring, |
| + &if_makeconsstring); |
| + |
| + Bind(&if_makeseqstring); |
| + { |
| + Node* result = AllocateSeqOneByteString(context, SmiToWord(length)); |
| + |
| + CopyStringCharacters(first, result, smi_zero, smi_zero, first_length, |
| + String::ONE_BYTE_ENCODING); |
| + CopyStringCharacters(second, result, smi_zero, first_length, second_length, |
| + String::ONE_BYTE_ENCODING); |
| + |
| + var_result.Bind(result); |
| + Goto(&out); |
| + } |
| + |
| + Bind(&if_makeconsstring); |
| + { |
| + Node* result = AllocateOneByteConsString(length, first, second); |
| + var_result.Bind(result); |
| + Goto(&out); |
| + } |
| + |
| + Bind(&runtime); |
| + { |
| + Node* const result = |
| + CallRuntime(Runtime::kStringAdd, context, first, second); |
| + var_result.Bind(result); |
| + Goto(&out); |
| + } |
| + |
| + Bind(&out); |
| + return var_result.value(); |
| +} |
| + |
| +Node* CodeStubAssembler::StringIndexOfChar(Node* context, Node* string, |
| + Node* needle_char, Node* from) { |
| + Variable var_result(this, MachineRepresentation::kTagged); |
| + |
| + Label out(this), runtime(this, Label::kDeferred); |
| + |
| + // Let runtime handle non-one-byte {needle_char}. |
| + |
| + Node* const one_byte_char_mask = IntPtrConstant(0xFF); |
| + GotoUnless(WordEqual(WordAnd(needle_char, one_byte_char_mask), needle_char), |
| + &runtime); |
| + |
| + // TODO(jgruber): Handle external and two-byte strings. |
| + |
| + Node* const one_byte_seq_mask = Int32Constant( |
| + kIsIndirectStringMask | kExternalStringTag | kStringEncodingMask); |
| + Node* const expected_masked = Int32Constant(kOneByteStringTag); |
| + |
| + Node* const string_instance_type = LoadInstanceType(string); |
| + GotoUnless(Word32Equal(Word32And(string_instance_type, one_byte_seq_mask), |
| + expected_masked), |
| + &runtime); |
| + |
| + // If we reach this, {string} is a non-indirect, non-external one-byte string. |
| + |
| + Node* const length = LoadStringLength(string); |
| + Node* const search_range_length = SmiUntag(SmiSub(length, from)); |
| + |
| + const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; |
| + Node* const begin = IntPtrConstant(offset); |
| + Node* const cursor = IntPtrAdd(begin, SmiUntag(from)); |
| + Node* const end = IntPtrAdd(cursor, search_range_length); |
| + |
| + Variable var_cursor(this, MachineType::PointerRepresentation()); |
| + Variable* vars[] = {&var_cursor}; |
| + Label loop(this, 1, vars), loop_tail(this); |
| + |
| + var_cursor.Bind(cursor); |
| + var_result.Bind(SmiConstant(Smi::FromInt(-1))); |
| + |
| + Goto(&loop); |
| + Bind(&loop); |
| + { |
| + Node* const cursor = var_cursor.value(); |
| + |
| + Node* value = Load(MachineType::Uint8(), string, cursor); |
| + GotoUnless(WordEqual(value, needle_char), &loop_tail); |
| + |
| + // Found a match. |
| + Node* index = SmiTag(IntPtrSub(cursor, begin)); |
| + var_result.Bind(index); |
| + Goto(&out); |
| + |
| + Bind(&loop_tail); |
| + { |
| + Node* const new_cursor = IntPtrAdd(cursor, IntPtrConstant(1)); |
| + var_cursor.Bind(new_cursor); |
| + Branch(IntPtrLessThan(new_cursor, end), &loop, &out); |
| + } |
| + } |
| + |
| + Bind(&runtime); |
| + { |
| + Node* const pattern = StringFromCharCode(needle_char); |
| + Node* const result = |
| + CallRuntime(Runtime::kStringIndexOf, context, string, pattern, from); |
| + var_result.Bind(result); |
| + var_cursor.Bind(IntPtrConstant(0)); |
| + Goto(&out); |
| + } |
| + |
| + Bind(&out); |
| + return var_result.value(); |
| +} |
| + |
| Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, |
| UnicodeEncoding encoding) { |
| Variable var_result(this, MachineRepresentation::kTagged); |