Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1367)

Unified Diff: src/code-stub-assembler.cc

Issue 2407813002: [stubs] Port StringAddStub to TF (Closed)
Patch Set: Make ASSERT cheaper Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/code-stub-assembler.cc
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
index 7ed1fbfda56e9725b27bca24ec5e820a524bee1a..3bc5ee57df6f9c24ac784279c7b71aa7d9d55977 100644
--- a/src/code-stub-assembler.cc
+++ b/src/code-stub-assembler.cc
@@ -30,13 +30,15 @@ void CodeStubAssembler::Assert(Node* condition, const char* message,
const char* file, int line) {
#if defined(DEBUG)
Label ok(this);
+ Label not_ok(this, Label::kDeferred);
if (message != nullptr && FLAG_code_comments) {
Comment("[ Assert: %s", message);
} else {
Comment("[ Assert ");
}
- GotoIf(condition, &ok);
+ Branch(condition, &ok, &not_ok);
+ Bind(&not_ok);
if (message != nullptr) {
char chars[1024];
Vector<char> buffer(chars);
@@ -89,6 +91,43 @@ Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
}
}
+Node* CodeStubAssembler::IntPtrAddFoldConstants(Node* left, Node* right) {
+ int32_t left_constant;
+ bool is_left_constant = ToInt32Constant(left, left_constant);
+ int32_t right_constant;
+ bool is_right_constant = ToInt32Constant(right, right_constant);
+ if (is_left_constant) {
+ if (is_right_constant) {
+ return IntPtrConstant(left_constant + right_constant);
+ }
+ if (left_constant == 0) {
+ return right;
+ }
+ } else if (is_right_constant) {
+ if (right_constant == 0) {
+ return left;
+ }
+ }
+ return IntPtrAdd(left, right);
+}
+
+Node* CodeStubAssembler::IntPtrSubFoldConstants(Node* left, Node* right) {
+ int32_t left_constant;
+ bool is_left_constant = ToInt32Constant(left, left_constant);
+ int32_t right_constant;
+ bool is_right_constant = ToInt32Constant(right, right_constant);
+ if (is_left_constant) {
+ if (is_right_constant) {
+ return IntPtrConstant(left_constant - right_constant);
+ }
+ } else if (is_right_constant) {
+ if (right_constant == 0) {
+ return left;
+ }
+ }
+ return IntPtrSub(left, right);
+}
+
Node* CodeStubAssembler::Float64Round(Node* x) {
Node* one = Float64Constant(1.0);
Node* one_half = Float64Constant(0.5);
@@ -1223,8 +1262,11 @@ Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value,
return result;
}
-Node* CodeStubAssembler::AllocateSeqOneByteString(int length) {
- Node* result = Allocate(SeqOneByteString::SizeFor(length));
+Node* CodeStubAssembler::AllocateSeqOneByteString(int length,
+ AllocationFlags flags) {
+ Comment("AllocateSeqOneByteString");
+ Node* result = Allocate(SeqOneByteString::SizeFor(length), flags);
+ DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex));
StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex));
StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
SmiConstant(Smi::FromInt(length)));
@@ -1234,27 +1276,31 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length) {
return result;
}
-Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) {
+Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length,
+ ParameterMode mode,
+ AllocationFlags flags) {
+ Comment("AllocateSeqOneByteString");
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);
- Node* size = WordAnd(
- IntPtrAdd(
- IntPtrAdd(length, IntPtrConstant(SeqOneByteString::kHeaderSize)),
- IntPtrConstant(kObjectAlignmentMask)),
- IntPtrConstant(~kObjectAlignmentMask));
+ Node* raw_size = GetArrayAllocationSize(
+ length, UINT8_ELEMENTS, mode,
+ SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
+ Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
&if_sizeissmall, &if_notsizeissmall);
Bind(&if_sizeissmall);
{
// Just allocate the SeqOneByteString in new space.
- Node* result = Allocate(size);
+ Node* result = Allocate(size, flags);
+ DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex));
StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex));
- StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
- SmiFromWord(length));
+ StoreObjectFieldNoWriteBarrier(
+ result, SeqOneByteString::kLengthOffset,
+ mode == SMI_PARAMETERS ? length : SmiFromWord(length));
StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset,
IntPtrConstant(String::kEmptyHashField),
MachineRepresentation::kWord32);
@@ -1265,8 +1311,9 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) {
Bind(&if_notsizeissmall);
{
// We might need to allocate in large object space, go to the runtime.
- Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context,
- SmiFromWord(length));
+ Node* result =
+ CallRuntime(Runtime::kAllocateSeqOneByteString, context,
+ mode == SMI_PARAMETERS ? length : SmiFromWord(length));
var_result.Bind(result);
Goto(&if_join);
}
@@ -1275,8 +1322,11 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) {
return var_result.value();
}
-Node* CodeStubAssembler::AllocateSeqTwoByteString(int length) {
- Node* result = Allocate(SeqTwoByteString::SizeFor(length));
+Node* CodeStubAssembler::AllocateSeqTwoByteString(int length,
+ AllocationFlags flags) {
+ Comment("AllocateSeqTwoByteString");
+ Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags);
+ DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex));
StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex));
StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
SmiConstant(Smi::FromInt(length)));
@@ -1286,27 +1336,31 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(int length) {
return result;
}
-Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) {
+Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length,
+ ParameterMode mode,
+ AllocationFlags flags) {
+ Comment("AllocateSeqTwoByteString");
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);
- Node* size = WordAnd(
- IntPtrAdd(IntPtrAdd(WordShl(length, 1),
- IntPtrConstant(SeqTwoByteString::kHeaderSize)),
- IntPtrConstant(kObjectAlignmentMask)),
- IntPtrConstant(~kObjectAlignmentMask));
+ Node* raw_size = GetArrayAllocationSize(
+ length, UINT16_ELEMENTS, mode,
+ SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
+ Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
&if_sizeissmall, &if_notsizeissmall);
Bind(&if_sizeissmall);
{
// Just allocate the SeqTwoByteString in new space.
- Node* result = Allocate(size);
+ Node* result = Allocate(size, flags);
+ DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex));
StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex));
- StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
- SmiFromWord(length));
+ StoreObjectFieldNoWriteBarrier(
+ result, SeqTwoByteString::kLengthOffset,
+ mode == SMI_PARAMETERS ? length : SmiFromWord(length));
StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset,
IntPtrConstant(String::kEmptyHashField),
MachineRepresentation::kWord32);
@@ -1317,8 +1371,9 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) {
Bind(&if_notsizeissmall);
{
// We might need to allocate in large object space, go to the runtime.
- Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
- SmiFromWord(length));
+ Node* result =
+ CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
+ mode == SMI_PARAMETERS ? length : SmiFromWord(length));
var_result.Bind(result);
Goto(&if_join);
}
@@ -1346,6 +1401,7 @@ Node* CodeStubAssembler::AllocateSlicedOneByteString(Node* length, Node* parent,
Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent,
Node* offset) {
+ CSA_ASSERT(TaggedIsSmi(length));
Node* result = Allocate(SlicedString::kSize);
Node* map = LoadRoot(Heap::kSlicedStringMapRootIndex);
StoreMapNoWriteBarrier(result, map);
@@ -1362,39 +1418,110 @@ Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent,
}
Node* CodeStubAssembler::AllocateOneByteConsString(Node* length, Node* first,
- Node* second) {
- Node* result = Allocate(ConsString::kSize);
+ Node* second,
+ AllocationFlags flags) {
+ CSA_ASSERT(TaggedIsSmi(length));
+ Node* result = Allocate(ConsString::kSize, flags);
Node* map = LoadRoot(Heap::kConsOneByteStringMapRootIndex);
+ DCHECK(Heap::RootIsImmortalImmovable(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);
+ bool const new_space = !(flags & kPretenured);
+ if (new_space) {
+ StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first,
+ MachineRepresentation::kTagged);
+ StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second,
+ MachineRepresentation::kTagged);
+ } else {
+ StoreObjectField(result, ConsString::kFirstOffset, first);
+ StoreObjectField(result, ConsString::kSecondOffset, second);
+ }
return result;
}
Node* CodeStubAssembler::AllocateTwoByteConsString(Node* length, Node* first,
- Node* second) {
- Node* result = Allocate(ConsString::kSize);
+ Node* second,
+ AllocationFlags flags) {
+ CSA_ASSERT(TaggedIsSmi(length));
+ Node* result = Allocate(ConsString::kSize, flags);
Node* map = LoadRoot(Heap::kConsStringMapRootIndex);
+ DCHECK(Heap::RootIsImmortalImmovable(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);
+ bool const new_space = !(flags & kPretenured);
+ if (new_space) {
+ StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first,
+ MachineRepresentation::kTagged);
+ StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second,
+ MachineRepresentation::kTagged);
+ } else {
+ StoreObjectField(result, ConsString::kFirstOffset, first);
+ StoreObjectField(result, ConsString::kSecondOffset, second);
+ }
return result;
}
+Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left,
+ Node* right, AllocationFlags flags) {
+ CSA_ASSERT(TaggedIsSmi(length));
+ // Added string can be a cons string.
+ Comment("Allocating ConsString");
+ Node* left_instance_type = LoadInstanceType(left);
+ Node* right_instance_type = LoadInstanceType(right);
+
+ // Compute intersection and difference of instance types.
+ Node* anded_instance_types = WordAnd(left_instance_type, right_instance_type);
+ Node* xored_instance_types = WordXor(left_instance_type, right_instance_type);
+
+ // We create a one-byte cons string if
+ // 1. both strings are one-byte, or
+ // 2. at least one of the strings is two-byte, but happens to contain only
+ // one-byte characters.
+ // To do this, we check
+ // 1. if both strings are one-byte, or if the one-byte data hint is set in
+ // both strings, or
+ // 2. if one of the strings has the one-byte data hint set and the other
+ // string is one-byte.
+ STATIC_ASSERT(kOneByteStringTag != 0);
+ STATIC_ASSERT(kOneByteDataHintTag != 0);
+ Label one_byte_map(this);
+ Label two_byte_map(this);
+ Variable result(this, MachineRepresentation::kTagged);
+ Label done(this, &result);
+ GotoIf(WordNotEqual(
+ WordAnd(anded_instance_types,
+ IntPtrConstant(kStringEncodingMask | kOneByteDataHintTag)),
+ IntPtrConstant(0)),
+ &one_byte_map);
+ Branch(WordNotEqual(WordAnd(xored_instance_types,
+ IntPtrConstant(kStringEncodingMask |
+ kOneByteDataHintMask)),
+ IntPtrConstant(kOneByteStringTag | kOneByteDataHintTag)),
+ &two_byte_map, &one_byte_map);
+
+ Bind(&one_byte_map);
+ Comment("One-byte ConsString");
+ result.Bind(AllocateOneByteConsString(length, left, right, flags));
+ Goto(&done);
+
+ Bind(&two_byte_map);
+ Comment("Two-byte ConsString");
+ result.Bind(AllocateTwoByteConsString(length, left, right, flags));
+ Goto(&done);
+
+ Bind(&done);
+
+ return result.value();
+}
+
Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length,
Node* index, Node* input) {
Node* const max_length =
@@ -1734,70 +1861,42 @@ void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string,
compiler::Node* from_index,
compiler::Node* to_index,
compiler::Node* character_count,
- String::Encoding encoding) {
- Label out(this);
-
- // Nothing to do for zero characters.
-
- GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::kZero)), &out);
-
- // Calculate offsets into the strings.
-
- Node* from_offset;
- Node* limit_offset;
- Node* to_offset;
-
- {
- 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 = 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 = IntPtrAdd(IntPtrConstant(offset), to_byte_index);
- }
- }
-
- Variable var_from_offset(this, MachineType::PointerRepresentation());
- Variable var_to_offset(this, MachineType::PointerRepresentation());
-
- var_from_offset.Bind(from_offset);
- var_to_offset.Bind(to_offset);
-
- Variable* vars[] = {&var_from_offset, &var_to_offset};
- Label decrement(this, 2, vars);
-
- Label loop(this, 2, vars);
- Goto(&loop);
- Bind(&loop);
- {
- from_offset = var_from_offset.value();
- to_offset = var_to_offset.value();
-
- // TODO(jgruber): We could make this faster through larger copy unit sizes.
- Node* value = Load(MachineType::Uint8(), from_string, from_offset);
- StoreNoWriteBarrier(MachineRepresentation::kWord8, to_string, to_offset,
- value);
-
- Node* new_from_offset = IntPtrAdd(from_offset, IntPtrConstant(1));
- var_from_offset.Bind(new_from_offset);
- var_to_offset.Bind(IntPtrAdd(to_offset, IntPtrConstant(1)));
-
- Branch(WordNotEqual(new_from_offset, limit_offset), &loop, &out);
- }
-
- Bind(&out);
+ String::Encoding encoding,
+ ParameterMode mode) {
+ bool one_byte = encoding == String::ONE_BYTE_ENCODING;
+ Comment(one_byte ? "CopyStringCharacters ONE_BYTE_ENCODING"
+ : "CopyStringCharacters TWO_BYTE_ENCODING");
+
+ ElementsKind kind = one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
+ int header_size = (one_byte ? SeqOneByteString::kHeaderSize
+ : SeqTwoByteString::kHeaderSize) -
+ kHeapObjectTag;
+ Node* from_offset = ElementOffsetFromIndex(from_index, kind, mode);
+ Node* to_offset = ElementOffsetFromIndex(to_index, kind, mode);
+ Node* byte_count = ElementOffsetFromIndex(character_count, kind, mode);
+ Node* limit_offset = IntPtrAddFoldConstants(from_offset, byte_count);
+
+ // Prepare the fast loop
+ MachineType type = one_byte ? MachineType::Uint8() : MachineType::Uint16();
+ MachineRepresentation rep =
+ one_byte ? MachineRepresentation::kWord8 : MachineRepresentation::kWord16;
+ int increment = -(1 << ElementsKindToShiftSize(kind));
+
+ Node* to_string_adjusted = IntPtrAddFoldConstants(
+ to_string, IntPtrSubFoldConstants(to_offset, from_offset));
+ limit_offset =
+ IntPtrAddFoldConstants(limit_offset, IntPtrConstant(header_size));
+ from_offset =
+ IntPtrAddFoldConstants(from_offset, IntPtrConstant(header_size));
+
+ BuildFastLoop(MachineType::PointerRepresentation(), limit_offset, from_offset,
+ [from_string, to_string_adjusted, type, rep](
+ CodeStubAssembler* assembler, Node* offset) {
+ Node* value = assembler->Load(type, from_string, offset);
+ assembler->StoreNoWriteBarrier(rep, to_string_adjusted,
+ offset, value);
+ },
+ increment);
}
Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
@@ -2576,7 +2675,8 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context,
Node* result =
a->AllocateSeqOneByteString(context, a->SmiToWord(character_count));
a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
- String::ONE_BYTE_ENCODING);
+ String::ONE_BYTE_ENCODING,
+ CodeStubAssembler::SMI_PARAMETERS);
var_result.Bind(result);
a->Goto(&end);
@@ -2588,7 +2688,8 @@ Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context,
Node* result =
a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count));
a->CopyStringCharacters(from, result, from_index, smi_zero, character_count,
- String::TWO_BYTE_ENCODING);
+ String::TWO_BYTE_ENCODING,
+ CodeStubAssembler::SMI_PARAMETERS);
var_result.Bind(result);
a->Goto(&end);
@@ -2822,69 +2923,107 @@ 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);
+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);
+ Counters* counters = isolate()->counters();
- var_result.Bind(result);
- Goto(&out);
+ Node* left_length = LoadStringLength(left);
+ GotoIf(WordNotEqual(IntPtrConstant(0), left_length), &check_right);
+ result.Bind(right);
+ Goto(&done_native);
+
+ Bind(&check_right);
+ Node* right_length = LoadStringLength(right);
+ GotoIf(WordNotEqual(IntPtrConstant(0), right_length), &cons);
+ result.Bind(left);
+ Goto(&done_native);
+
+ Bind(&cons);
+ CSA_ASSERT(TaggedIsSmi(left_length));
+ CSA_ASSERT(TaggedIsSmi(right_length));
+ Node* new_length = SmiAdd(left_length, right_length);
+ GotoIf(UintPtrGreaterThanOrEqual(
+ new_length, SmiConstant(Smi::FromInt(String::kMaxLength))),
+ &runtime);
+
+ GotoIf(IntPtrLessThan(new_length,
+ SmiConstant(Smi::FromInt(ConsString::kMinLength))),
+ &non_cons);
+
+ result.Bind(NewConsString(context, new_length, left, right, flags));
+ Goto(&done_native);
+
+ Bind(&non_cons);
+
+ Comment("Full string concatenate");
+ Node* left_instance_type = LoadInstanceType(left);
+ Node* right_instance_type = LoadInstanceType(right);
+ // Compute intersection and difference of instance types.
+
+ Node* ored_instance_types = WordOr(left_instance_type, right_instance_type);
+ Node* xored_instance_types = WordXor(left_instance_type, right_instance_type);
+
+ // Check if both strings have the same encoding and both are sequential.
+ GotoIf(WordNotEqual(
+ WordAnd(xored_instance_types, IntPtrConstant(kStringEncodingMask)),
+ IntPtrConstant(0)),
+ &runtime);
+ GotoIf(WordNotEqual(WordAnd(ored_instance_types,
+ IntPtrConstant(kStringRepresentationMask)),
+ IntPtrConstant(0)),
+ &runtime);
+
+ Label two_byte(this);
+ GotoIf(WordEqual(
+ WordAnd(ored_instance_types, IntPtrConstant(kStringEncodingMask)),
+ IntPtrConstant(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, SMI_PARAMETERS);
+ CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), left_length,
+ right_length, 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(left, new_string, SmiConstant(Smi::kZero),
+ SmiConstant(Smi::kZero), left_length,
+ String::TWO_BYTE_ENCODING, SMI_PARAMETERS);
+ CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero),
+ left_length, right_length, String::TWO_BYTE_ENCODING,
+ SMI_PARAMETERS);
+ result.Bind(new_string);
+ Goto(&done_native);
}
- Bind(&if_makeconsstring);
+ Bind(&runtime);
{
- Node* result = AllocateOneByteConsString(length, first, second);
- var_result.Bind(result);
- Goto(&out);
+ result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right));
+ Goto(&done);
}
- Bind(&runtime);
+ Bind(&done_native);
{
- Node* const result =
- CallRuntime(Runtime::kStringAdd, context, first, second);
- var_result.Bind(result);
- Goto(&out);
+ IncrementCounter(counters->string_add_native(), 1);
+ Goto(&done);
}
- Bind(&out);
- return var_result.value();
+ Bind(&done);
+ return result.value();
}
Node* CodeStubAssembler::StringIndexOfChar(Node* context, Node* string,
@@ -3286,6 +3425,77 @@ Node* CodeStubAssembler::ToNumber(Node* context, Node* input) {
return var_result.value();
}
+Node* CodeStubAssembler::ToString(Node* context, Node* input) {
+ Label is_number(this);
+ Label runtime(this, Label::kDeferred);
+ Variable result(this, MachineRepresentation::kTagged);
+ Label done(this, &result);
+
+ GotoIf(TaggedIsSmi(input), &is_number);
+
+ Node* input_map = LoadMap(input);
+ Node* input_instance_type = LoadMapInstanceType(input_map);
+
+ result.Bind(input);
+ GotoIf(IsStringInstanceType(input_instance_type), &done);
+
+ Label not_heap_number(this);
+ Branch(WordNotEqual(input_map, HeapNumberMapConstant()), &not_heap_number,
+ &is_number);
+
+ Bind(&is_number);
+ result.Bind(NumberToString(context, input));
+ Goto(&done);
+
+ Bind(&not_heap_number);
+ {
+ GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)),
+ &runtime);
+ result.Bind(LoadObjectField(input, Oddball::kToStringOffset));
+ Goto(&done);
+ }
+
+ Bind(&runtime);
+ {
+ result.Bind(CallRuntime(Runtime::kToString, context, input));
+ Goto(&done);
+ }
+
+ Bind(&done);
+ return result.value();
+}
+
+Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+ Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this);
+ Variable result(this, MachineRepresentation::kTagged);
+ Label done(this, &result);
+
+ GotoIf(TaggedIsSmi(input), &if_isnotreceiver);
+
+ Node* map = LoadMap(input);
+ Node* instance_type = LoadMapInstanceType(map);
+ Branch(IsJSReceiverInstanceType(instance_type), &if_isreceiver,
+ &if_isnotreceiver);
+
+ Bind(&if_isreceiver);
+ {
+ // Convert {input} to a primitive first passing Number hint.
+ Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
+ result.Bind(CallStub(callable, context, input));
+ Goto(&done);
+ }
+
+ Bind(&if_isnotreceiver);
+ {
+ result.Bind(input);
+ Goto(&done);
+ }
+
+ Bind(&done);
+ return result.value();
+}
+
Node* CodeStubAssembler::ToInteger(Node* context, Node* input,
ToIntegerTruncationMode mode) {
// We might need to loop once for ToNumber conversion.
@@ -4332,8 +4542,9 @@ compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
bool constant_index = false;
if (mode == SMI_PARAMETERS) {
element_size_shift -= kSmiShiftBits;
- constant_index = ToIntPtrConstant(index_node, index);
- index = index >> kSmiShiftBits;
+ Smi* smi_index;
+ constant_index = ToSmiConstant(index_node, smi_index);
+ if (constant_index) index = smi_index->value();
index_node = BitcastTaggedToWord(index_node);
} else if (mode == INTEGER_PARAMETERS) {
int32_t temp = 0;
@@ -4349,16 +4560,14 @@ compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
if (Is64() && mode == INTEGER_PARAMETERS) {
index_node = ChangeInt32ToInt64(index_node);
}
- if (base_size == 0) {
- return (element_size_shift >= 0)
- ? WordShl(index_node, IntPtrConstant(element_size_shift))
- : WordShr(index_node, IntPtrConstant(-element_size_shift));
- }
- return IntPtrAdd(
- IntPtrConstant(base_size),
- (element_size_shift >= 0)
- ? WordShl(index_node, IntPtrConstant(element_size_shift))
- : WordShr(index_node, IntPtrConstant(-element_size_shift)));
+
+ Node* shifted_index =
+ (element_size_shift == 0)
+ ? index_node
+ : ((element_size_shift > 0)
+ ? WordShl(index_node, IntPtrConstant(element_size_shift))
+ : WordShr(index_node, IntPtrConstant(-element_size_shift)));
+ return IntPtrAddFoldConstants(IntPtrConstant(base_size), shifted_index);
}
compiler::Node* CodeStubAssembler::LoadTypeFeedbackVectorForStub() {
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698