| 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, ¬_ok);
|
| + Bind(¬_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()), ¬_heap_number,
|
| + &is_number);
|
| +
|
| + Bind(&is_number);
|
| + result.Bind(NumberToString(context, input));
|
| + Goto(&done);
|
| +
|
| + Bind(¬_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() {
|
|
|