| Index: src/code-stub-assembler.cc
|
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
|
| index 6adec9aff6fd100da4efb4b4baa942b281566f2f..a72e267f391581a840defb56e0dfe7e5b25a3dc7 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::kZero);
|
| +
|
| 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::kZero);
|
| + 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);
|
|
|