| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 3fcce8046d354b469411f19d8927e3a97dfd578d..7bdc02f79c7da451c614949dac604c742906c1fc 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -1693,22 +1693,131 @@ HValue* HGraphBuilder::BuildNumberToString(HValue* object,
|
| }
|
|
|
|
|
| -HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length,
|
| - String::Encoding encoding) {
|
| - STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
|
| - HValue* size = length;
|
| - if (encoding == String::TWO_BYTE_ENCODING) {
|
| - size = AddUncasted<HShl>(length, graph()->GetConstant1());
|
| +HAllocate* HGraphBuilder::BuildAllocate(
|
| + HValue* object_size,
|
| + HType type,
|
| + InstanceType instance_type,
|
| + HAllocationMode allocation_mode) {
|
| + // Compute the effective allocation size.
|
| + HValue* size = object_size;
|
| + if (allocation_mode.CreateAllocationMementos()) {
|
| + size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
|
| size->ClearFlag(HValue::kCanOverflow);
|
| - size->SetFlag(HValue::kUint32);
|
| }
|
| - size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
|
| - SeqString::kHeaderSize + kObjectAlignmentMask)));
|
| - size->ClearFlag(HValue::kCanOverflow);
|
| - size = AddUncasted<HBitwise>(
|
| - Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
|
| - ~kObjectAlignmentMask)));
|
| - return size;
|
| +
|
| + // Perform the actual allocation.
|
| + HAllocate* object = Add<HAllocate>(
|
| + size, type, allocation_mode.GetPretenureMode(),
|
| + instance_type, allocation_mode.feedback_site());
|
| +
|
| + // Setup the allocation memento.
|
| + if (allocation_mode.CreateAllocationMementos()) {
|
| + BuildCreateAllocationMemento(
|
| + object, object_size, allocation_mode.current_site());
|
| + }
|
| +
|
| + return object;
|
| +}
|
| +
|
| +
|
| +HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
|
| + HValue* right_length) {
|
| + // Compute the combined string length. If the result is larger than the max
|
| + // supported string length, we bailout to the runtime. This is done implicitly
|
| + // when converting the result back to a smi in case the max string length
|
| + // equals the max smi value. Otherwise, for platforms with 32-bit smis, we do
|
| + HValue* length = AddUncasted<HAdd>(left_length, right_length);
|
| + STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
|
| + if (String::kMaxLength != Smi::kMaxValue) {
|
| + IfBuilder if_nooverflow(this);
|
| + if_nooverflow.If<HCompareNumericAndBranch>(
|
| + length, Add<HConstant>(String::kMaxLength), Token::LTE);
|
| + if_nooverflow.Then();
|
| + if_nooverflow.ElseDeopt("String length exceeds limit");
|
| + }
|
| + return length;
|
| +}
|
| +
|
| +
|
| +HValue* HGraphBuilder::BuildCreateConsString(
|
| + HValue* length,
|
| + HValue* left,
|
| + HValue* right,
|
| + HAllocationMode allocation_mode) {
|
| + // Determine the string instance types.
|
| + HInstruction* left_instance_type = AddLoadStringInstanceType(left);
|
| + HInstruction* right_instance_type = AddLoadStringInstanceType(right);
|
| +
|
| + // Allocate the cons string object. HAllocate does not care whether we
|
| + // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
|
| + // CONS_STRING_TYPE here. Below we decide whether the cons string is
|
| + // one-byte or two-byte and set the appropriate map.
|
| + ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
|
| + CONS_ASCII_STRING_TYPE));
|
| + HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
|
| + HType::String(), CONS_STRING_TYPE,
|
| + allocation_mode);
|
| +
|
| + // Compute intersection and difference of instance types.
|
| + HValue* anded_instance_types = AddUncasted<HBitwise>(
|
| + Token::BIT_AND, left_instance_type, right_instance_type);
|
| + HValue* xored_instance_types = AddUncasted<HBitwise>(
|
| + Token::BIT_XOR, 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.
|
| + IfBuilder if_onebyte(this);
|
| + STATIC_ASSERT(kOneByteStringTag != 0);
|
| + STATIC_ASSERT(kOneByteDataHintMask != 0);
|
| + if_onebyte.If<HCompareNumericAndBranch>(
|
| + AddUncasted<HBitwise>(
|
| + Token::BIT_AND, anded_instance_types,
|
| + Add<HConstant>(static_cast<int32_t>(
|
| + kStringEncodingMask | kOneByteDataHintMask))),
|
| + graph()->GetConstant0(), Token::NE);
|
| + if_onebyte.Or();
|
| + STATIC_ASSERT(kOneByteStringTag != 0 &&
|
| + kOneByteDataHintTag != 0 &&
|
| + kOneByteDataHintTag != kOneByteStringTag);
|
| + if_onebyte.If<HCompareNumericAndBranch>(
|
| + AddUncasted<HBitwise>(
|
| + Token::BIT_AND, xored_instance_types,
|
| + Add<HConstant>(static_cast<int32_t>(
|
| + kOneByteStringTag | kOneByteDataHintTag))),
|
| + Add<HConstant>(static_cast<int32_t>(
|
| + kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
|
| + if_onebyte.Then();
|
| + {
|
| + // We can safely skip the write barrier for storing the map here.
|
| + Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
|
| + AddStoreMapConstantNoWriteBarrier(result, map);
|
| + }
|
| + if_onebyte.Else();
|
| + {
|
| + // We can safely skip the write barrier for storing the map here.
|
| + Handle<Map> map = isolate()->factory()->cons_string_map();
|
| + AddStoreMapConstantNoWriteBarrier(result, map);
|
| + }
|
| + if_onebyte.End();
|
| +
|
| + // Initialize the cons string fields.
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
|
| + Add<HConstant>(String::kEmptyHashField));
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
|
| +
|
| + // Count the native string addition.
|
| + AddIncrementCounter(isolate()->counters()->string_add_native());
|
| +
|
| + return result;
|
| }
|
|
|
|
|
| @@ -1734,40 +1843,33 @@ void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
|
| }
|
|
|
|
|
| -HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
|
| - HValue* right,
|
| - PretenureFlag pretenure_flag) {
|
| +HValue* HGraphBuilder::BuildUncheckedStringAdd(
|
| + HValue* left,
|
| + HValue* right,
|
| + HAllocationMode allocation_mode) {
|
| // Determine the string lengths.
|
| - HValue* left_length = Add<HLoadNamedField>(
|
| - left, HObjectAccess::ForStringLength());
|
| - HValue* right_length = Add<HLoadNamedField>(
|
| - right, HObjectAccess::ForStringLength());
|
| + HValue* left_length = AddLoadStringLength(left);
|
| + HValue* right_length = AddLoadStringLength(right);
|
|
|
| - // Compute the combined string length. If the result is larger than the max
|
| - // supported string length, we bailout to the runtime. This is done implicitly
|
| - // when converting the result back to a smi in case the max string length
|
| - // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do
|
| - HValue* length = AddUncasted<HAdd>(left_length, right_length);
|
| - STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
|
| - if (String::kMaxLength != Smi::kMaxValue) {
|
| - IfBuilder if_nooverflow(this);
|
| - if_nooverflow.If<HCompareNumericAndBranch>(
|
| - length, Add<HConstant>(String::kMaxLength), Token::LTE);
|
| - if_nooverflow.Then();
|
| - if_nooverflow.ElseDeopt("String length exceeds limit");
|
| - }
|
| -
|
| - // Determine the string instance types.
|
| - HLoadNamedField* left_instance_type = Add<HLoadNamedField>(
|
| - Add<HLoadNamedField>(left, HObjectAccess::ForMap()),
|
| - HObjectAccess::ForMapInstanceType());
|
| - HLoadNamedField* right_instance_type = Add<HLoadNamedField>(
|
| - Add<HLoadNamedField>(right, HObjectAccess::ForMap()),
|
| - HObjectAccess::ForMapInstanceType());
|
| + // Compute the combined string length.
|
| + HValue* length = BuildAddStringLengths(left_length, right_length);
|
|
|
| - // Compute difference of instance types.
|
| - HValue* xored_instance_types = AddUncasted<HBitwise>(
|
| - Token::BIT_XOR, left_instance_type, right_instance_type);
|
| + // Do some manual constant folding here.
|
| + if (left_length->IsConstant()) {
|
| + HConstant* c_left_length = HConstant::cast(left_length);
|
| + ASSERT_NE(0, c_left_length->Integer32Value());
|
| + if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
|
| + // The right string contains at least one character.
|
| + return BuildCreateConsString(length, left, right, allocation_mode);
|
| + }
|
| + } else if (right_length->IsConstant()) {
|
| + HConstant* c_right_length = HConstant::cast(right_length);
|
| + ASSERT_NE(0, c_right_length->Integer32Value());
|
| + if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
|
| + // The left string contains at least one character.
|
| + return BuildCreateConsString(length, left, right, allocation_mode);
|
| + }
|
| + }
|
|
|
| // Check if we should create a cons string.
|
| IfBuilder if_createcons(this);
|
| @@ -1775,82 +1877,20 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
|
| length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
|
| if_createcons.Then();
|
| {
|
| - // Allocate the cons string object. HAllocate does not care whether we
|
| - // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
|
| - // CONS_STRING_TYPE here. Below we decide whether the cons string is
|
| - // one-byte or two-byte and set the appropriate map.
|
| - ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
|
| - CONS_ASCII_STRING_TYPE));
|
| - HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize),
|
| - HType::String(), pretenure_flag,
|
| - CONS_STRING_TYPE);
|
| -
|
| - // Compute the intersection of instance types.
|
| - HValue* anded_instance_types = AddUncasted<HBitwise>(
|
| - Token::BIT_AND, 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.
|
| - IfBuilder if_onebyte(this);
|
| - STATIC_ASSERT(kOneByteStringTag != 0);
|
| - STATIC_ASSERT(kOneByteDataHintMask != 0);
|
| - if_onebyte.If<HCompareNumericAndBranch>(
|
| - AddUncasted<HBitwise>(
|
| - Token::BIT_AND, anded_instance_types,
|
| - Add<HConstant>(static_cast<int32_t>(
|
| - kStringEncodingMask | kOneByteDataHintMask))),
|
| - graph()->GetConstant0(), Token::NE);
|
| - if_onebyte.Or();
|
| - STATIC_ASSERT(kOneByteStringTag != 0 &&
|
| - kOneByteDataHintTag != 0 &&
|
| - kOneByteDataHintTag != kOneByteStringTag);
|
| - if_onebyte.If<HCompareNumericAndBranch>(
|
| - AddUncasted<HBitwise>(
|
| - Token::BIT_AND, xored_instance_types,
|
| - Add<HConstant>(static_cast<int32_t>(
|
| - kOneByteStringTag | kOneByteDataHintTag))),
|
| - Add<HConstant>(static_cast<int32_t>(
|
| - kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
|
| - if_onebyte.Then();
|
| - {
|
| - // We can safely skip the write barrier for storing the map here.
|
| - Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
|
| - AddStoreMapConstantNoWriteBarrier(string, map);
|
| - }
|
| - if_onebyte.Else();
|
| - {
|
| - // We can safely skip the write barrier for storing the map here.
|
| - Handle<Map> map = isolate()->factory()->cons_string_map();
|
| - AddStoreMapConstantNoWriteBarrier(string, map);
|
| - }
|
| - if_onebyte.End();
|
| -
|
| - // Initialize the cons string fields.
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
|
| - Add<HConstant>(String::kEmptyHashField));
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length);
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left);
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(),
|
| - right);
|
| -
|
| - // Count the native string addition.
|
| - AddIncrementCounter(isolate()->counters()->string_add_native());
|
| -
|
| - // Cons string is result.
|
| - Push(string);
|
| + // Create a cons string.
|
| + Push(BuildCreateConsString(length, left, right, allocation_mode));
|
| }
|
| if_createcons.Else();
|
| {
|
| - // Compute union of instance types.
|
| + // Determine the string instance types.
|
| + HValue* left_instance_type = AddLoadStringInstanceType(left);
|
| + HValue* right_instance_type = AddLoadStringInstanceType(right);
|
| +
|
| + // Compute union and difference of instance types.
|
| HValue* ored_instance_types = AddUncasted<HBitwise>(
|
| Token::BIT_OR, left_instance_type, right_instance_type);
|
| + HValue* xored_instance_types = AddUncasted<HBitwise>(
|
| + Token::BIT_XOR, left_instance_type, right_instance_type);
|
|
|
| // Check if both strings have the same encoding and both are
|
| // sequential.
|
| @@ -1869,7 +1909,12 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
|
| graph()->GetConstant0(), Token::EQ);
|
| if_sameencodingandsequential.Then();
|
| {
|
| - // Check if the result is a one-byte string.
|
| + HConstant* string_map =
|
| + Add<HConstant>(isolate()->factory()->string_map());
|
| + HConstant* ascii_string_map =
|
| + Add<HConstant>(isolate()->factory()->ascii_string_map());
|
| +
|
| + // Determine map and size depending on whether result is one-byte string.
|
| IfBuilder if_onebyte(this);
|
| STATIC_ASSERT(kOneByteStringTag != 0);
|
| if_onebyte.If<HCompareNumericAndBranch>(
|
| @@ -1879,90 +1924,84 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
|
| graph()->GetConstant0(), Token::NE);
|
| if_onebyte.Then();
|
| {
|
| - // Calculate the number of bytes needed for the characters in the
|
| - // string while observing object alignment.
|
| - HValue* size = BuildSeqStringSizeFor(
|
| - length, String::ONE_BYTE_ENCODING);
|
| -
|
| - // Allocate the ASCII string object.
|
| - Handle<Map> map = isolate()->factory()->ascii_string_map();
|
| - HAllocate* string = Add<HAllocate>(size, HType::String(),
|
| - pretenure_flag, ASCII_STRING_TYPE);
|
| - string->set_known_initial_map(map);
|
| -
|
| - // We can safely skip the write barrier for storing map here.
|
| - AddStoreMapConstantNoWriteBarrier(string, map);
|
| -
|
| - // Length must be stored into the string before we copy characters to
|
| - // make debug verification code happy.
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
|
| - length);
|
| -
|
| - // Copy bytes from the left string.
|
| + // Allocate sequential one-byte string object.
|
| + Push(length);
|
| + Push(ascii_string_map);
|
| + }
|
| + if_onebyte.Else();
|
| + {
|
| + // Allocate sequential two-byte string object.
|
| + HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
|
| + size->ClearFlag(HValue::kCanOverflow);
|
| + size->SetFlag(HValue::kUint32);
|
| + Push(size);
|
| + Push(string_map);
|
| + }
|
| + if_onebyte.End();
|
| + HValue* map = Pop();
|
| +
|
| + // Calculate the number of bytes needed for the characters in the
|
| + // string while observing object alignment.
|
| + STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
|
| + HValue* size = Pop();
|
| + size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
|
| + SeqString::kHeaderSize + kObjectAlignmentMask)));
|
| + size->ClearFlag(HValue::kCanOverflow);
|
| + size = AddUncasted<HBitwise>(
|
| + Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
|
| + ~kObjectAlignmentMask)));
|
| +
|
| + // Allocate the string object. HAllocate does not care whether we pass
|
| + // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here.
|
| + HAllocate* result = BuildAllocate(
|
| + size, HType::String(), STRING_TYPE, allocation_mode);
|
| +
|
| + // We can safely skip the write barrier for storing map here.
|
| + AddStoreMapNoWriteBarrier(result, map);
|
| +
|
| + // Initialize the string fields.
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
|
| + Add<HConstant>(String::kEmptyHashField));
|
| + Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
|
| +
|
| + // Copy characters to the result string.
|
| + IfBuilder if_twobyte(this);
|
| + if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
|
| + if_twobyte.Then();
|
| + {
|
| + // Copy characters from the left string.
|
| BuildCopySeqStringChars(
|
| - left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| - string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| + left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| + result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| left_length);
|
|
|
| - // Copy bytes from the right string.
|
| + // Copy characters from the right string.
|
| BuildCopySeqStringChars(
|
| - right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| - string, left_length, String::ONE_BYTE_ENCODING,
|
| + right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| + result, left_length, String::TWO_BYTE_ENCODING,
|
| right_length);
|
| -
|
| - // Count the native string addition.
|
| - AddIncrementCounter(isolate()->counters()->string_add_native());
|
| -
|
| - // Return the string.
|
| - Push(string);
|
| }
|
| - if_onebyte.Else();
|
| + if_twobyte.Else();
|
| {
|
| - // Calculate the number of bytes needed for the characters in the
|
| - // string while observing object alignment.
|
| - HValue* size = BuildSeqStringSizeFor(
|
| - length, String::TWO_BYTE_ENCODING);
|
| -
|
| - // Allocate the two-byte string object.
|
| - Handle<Map> map = isolate()->factory()->string_map();
|
| - HAllocate* string = Add<HAllocate>(size, HType::String(),
|
| - pretenure_flag, STRING_TYPE);
|
| - string->set_known_initial_map(map);
|
| -
|
| - // We can safely skip the write barrier for storing map here.
|
| - AddStoreMapConstantNoWriteBarrier(string, map);
|
| -
|
| - // Length must be stored into the string before we copy characters to
|
| - // make debug verification code happy.
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
|
| - length);
|
| -
|
| - // Copy bytes from the left string.
|
| + // Copy characters from the left string.
|
| BuildCopySeqStringChars(
|
| - left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| - string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| + left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| + result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| left_length);
|
|
|
| - // Copy bytes from the right string.
|
| + // Copy characters from the right string.
|
| BuildCopySeqStringChars(
|
| - right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
|
| - string, left_length, String::TWO_BYTE_ENCODING,
|
| + right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
|
| + result, left_length, String::ONE_BYTE_ENCODING,
|
| right_length);
|
| -
|
| - // Return the string.
|
| - Push(string);
|
| }
|
| - if_onebyte.End();
|
| -
|
| - // Initialize the (common) string fields.
|
| - HValue* string = Pop();
|
| - Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
|
| - Add<HConstant>(String::kEmptyHashField));
|
| + if_twobyte.End();
|
|
|
| // Count the native string addition.
|
| AddIncrementCounter(isolate()->counters()->string_add_native());
|
|
|
| - Push(string);
|
| + // Return the sequential string.
|
| + Push(result);
|
| }
|
| if_sameencodingandsequential.Else();
|
| {
|
| @@ -1981,20 +2020,21 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
|
| }
|
|
|
|
|
| -HValue* HGraphBuilder::BuildStringAdd(HValue* left,
|
| - HValue* right,
|
| - PretenureFlag pretenure_flag) {
|
| - // Determine the string lengths.
|
| - HValue* left_length = Add<HLoadNamedField>(
|
| - left, HObjectAccess::ForStringLength());
|
| - HValue* right_length = Add<HLoadNamedField>(
|
| - right, HObjectAccess::ForStringLength());
|
| +HValue* HGraphBuilder::BuildStringAdd(
|
| + HValue* left,
|
| + HValue* right,
|
| + HAllocationMode allocation_mode) {
|
| + NoObservableSideEffectsScope no_effects(this);
|
| +
|
| + // Determine string lengths.
|
| + HValue* left_length = AddLoadStringLength(left);
|
| + HValue* right_length = AddLoadStringLength(right);
|
|
|
| // Check if left string is empty.
|
| - IfBuilder if_leftisempty(this);
|
| - if_leftisempty.If<HCompareNumericAndBranch>(
|
| + IfBuilder if_leftempty(this);
|
| + if_leftempty.If<HCompareNumericAndBranch>(
|
| left_length, graph()->GetConstant0(), Token::EQ);
|
| - if_leftisempty.Then();
|
| + if_leftempty.Then();
|
| {
|
| // Count the native string addition.
|
| AddIncrementCounter(isolate()->counters()->string_add_native());
|
| @@ -2002,13 +2042,13 @@ HValue* HGraphBuilder::BuildStringAdd(HValue* left,
|
| // Just return the right string.
|
| Push(right);
|
| }
|
| - if_leftisempty.Else();
|
| + if_leftempty.Else();
|
| {
|
| // Check if right string is empty.
|
| - IfBuilder if_rightisempty(this);
|
| - if_rightisempty.If<HCompareNumericAndBranch>(
|
| + IfBuilder if_rightempty(this);
|
| + if_rightempty.If<HCompareNumericAndBranch>(
|
| right_length, graph()->GetConstant0(), Token::EQ);
|
| - if_rightisempty.Then();
|
| + if_rightempty.Then();
|
| {
|
| // Count the native string addition.
|
| AddIncrementCounter(isolate()->counters()->string_add_native());
|
| @@ -2016,14 +2056,14 @@ HValue* HGraphBuilder::BuildStringAdd(HValue* left,
|
| // Just return the left string.
|
| Push(left);
|
| }
|
| - if_rightisempty.Else();
|
| + if_rightempty.Else();
|
| {
|
| - // Concatenate the two non-empty strings.
|
| - Push(BuildUncheckedStringAdd(left, right, pretenure_flag));
|
| + // Add the two non-empty strings.
|
| + Push(BuildUncheckedStringAdd(left, right, allocation_mode));
|
| }
|
| - if_rightisempty.End();
|
| + if_rightempty.End();
|
| }
|
| - if_leftisempty.End();
|
| + if_leftempty.End();
|
|
|
| return Pop();
|
| }
|
| @@ -6100,15 +6140,27 @@ HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object,
|
| }
|
|
|
|
|
| -HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object,
|
| - HValue* checked_string) {
|
| - if (FLAG_fold_constants && object->IsConstant()) {
|
| - HConstant* constant = HConstant::cast(object);
|
| - if (constant->HasStringValue()) {
|
| - return New<HConstant>(constant->StringValue()->length());
|
| +HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
|
| + if (string->IsConstant()) {
|
| + HConstant* c_string = HConstant::cast(string);
|
| + if (c_string->HasStringValue()) {
|
| + return Add<HConstant>(c_string->StringValue()->map()->instance_type());
|
| }
|
| }
|
| - return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength());
|
| + return AddLoadNamedField(
|
| + AddLoadNamedField(string, HObjectAccess::ForMap()),
|
| + HObjectAccess::ForMapInstanceType());
|
| +}
|
| +
|
| +
|
| +HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
|
| + if (string->IsConstant()) {
|
| + HConstant* c_string = HConstant::cast(string);
|
| + if (c_string->HasStringValue()) {
|
| + return Add<HConstant>(c_string->StringValue()->length());
|
| + }
|
| + }
|
| + return AddLoadNamedField(string, HObjectAccess::ForStringLength());
|
| }
|
|
|
|
|
| @@ -8556,13 +8608,9 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
|
| return New<HConstant>(s->Get(i));
|
| }
|
| }
|
| - BuildCheckHeapObject(string);
|
| - HValue* checkstring =
|
| - Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
|
| - HInstruction* length = BuildLoadStringLength(string, checkstring);
|
| - AddInstruction(length);
|
| - HInstruction* checked_index = Add<HBoundsCheck>(index, length);
|
| - return New<HStringCharCodeAt>(string, checked_index);
|
| + string = BuildCheckString(string);
|
| + index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
|
| + return New<HStringCharCodeAt>(string, index);
|
| }
|
|
|
|
|
| @@ -8693,10 +8741,18 @@ HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
|
| Handle<Type> right_type = expr->right()->bounds().lower;
|
| Handle<Type> result_type = expr->bounds().lower;
|
| Maybe<int> fixed_right_arg = expr->fixed_right_arg();
|
| + Handle<AllocationSite> allocation_site = expr->allocation_site();
|
| +
|
| + HAllocationMode allocation_mode =
|
| + FLAG_allocation_site_pretenuring
|
| + ? (allocation_site.is_null()
|
| + ? HAllocationMode(NOT_TENURED)
|
| + : HAllocationMode(allocation_site))
|
| + : HAllocationMode(isolate()->heap()->GetPretenureMode());
|
|
|
| HValue* result = HGraphBuilder::BuildBinaryOperation(
|
| - expr->op(), left, right, left_type, right_type,
|
| - result_type, fixed_right_arg);
|
| + expr->op(), left, right, left_type, right_type, result_type,
|
| + fixed_right_arg, allocation_mode);
|
| // Add a simulate after instructions with observable side effects, and
|
| // after phis, which are the result of BuildBinaryOperation when we
|
| // inlined some complex subgraph.
|
| @@ -8716,7 +8772,8 @@ HValue* HGraphBuilder::BuildBinaryOperation(
|
| Handle<Type> left_type,
|
| Handle<Type> right_type,
|
| Handle<Type> result_type,
|
| - Maybe<int> fixed_right_arg) {
|
| + Maybe<int> fixed_right_arg,
|
| + HAllocationMode allocation_mode) {
|
|
|
| Representation left_rep = Representation::FromType(left_type);
|
| Representation right_rep = Representation::FromType(right_type);
|
| @@ -8782,7 +8839,48 @@ HValue* HGraphBuilder::BuildBinaryOperation(
|
| return AddUncasted<HInvokeFunction>(function, 2);
|
| }
|
|
|
| - return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
|
| + // Inline the string addition into the stub when creating allocation
|
| + // mementos to gather allocation site feedback.
|
| + if (graph()->info()->IsStub() &&
|
| + allocation_mode.CreateAllocationMementos()) {
|
| + return BuildStringAdd(left, right, allocation_mode);
|
| + }
|
| +
|
| + // Register the dependent code with the allocation site.
|
| + if (!allocation_mode.feedback_site().is_null()) {
|
| + ASSERT(!graph()->info()->IsStub());
|
| + allocation_mode.feedback_site()->AddDependentCompilationInfo(
|
| + AllocationSite::TENURING, top_info());
|
| + }
|
| +
|
| + // Inline string addition if we know that we'll create a cons string.
|
| + if (left->IsConstant()) {
|
| + HConstant* c_left = HConstant::cast(left);
|
| + if (c_left->HasStringValue()) {
|
| + int c_left_length = c_left->StringValue()->length();
|
| + if (c_left_length == 0) {
|
| + return right;
|
| + } else if (c_left_length + 1 >= ConsString::kMinLength) {
|
| + return BuildStringAdd(left, right, allocation_mode);
|
| + }
|
| + }
|
| + }
|
| + if (right->IsConstant()) {
|
| + HConstant* c_right = HConstant::cast(right);
|
| + if (c_right->HasStringValue()) {
|
| + int c_right_length = c_right->StringValue()->length();
|
| + if (c_right_length == 0) {
|
| + return left;
|
| + } else if (c_right_length + 1 >= ConsString::kMinLength) {
|
| + return BuildStringAdd(left, right, allocation_mode);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Fallback to using the string add stub.
|
| + return AddUncasted<HStringAdd>(
|
| + left, right, allocation_mode.GetPretenureMode(),
|
| + STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
|
| }
|
|
|
| if (graph()->info()->IsStub()) {
|
| @@ -10011,8 +10109,7 @@ void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
|
| CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - HInstruction* result =
|
| - NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH);
|
| + HInstruction* result = NewUncasted<HStringAdd>(left, right);
|
| return ast_context()->ReturnInstruction(result, call->id());
|
| }
|
|
|
|
|