Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 147563e90104c7d094c93b937bb91c0f34534fc6..c09cd6df762b0f9cd50027b19fe63749f4692714 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -1469,6 +1469,342 @@ 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 = Add<HShl>(length, graph()->GetConstant1()); |
+ size->ClearFlag(HValue::kCanOverflow); |
+ size->SetFlag(HValue::kUint32); |
+ } |
+ size = Add<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
+ SeqString::kHeaderSize + kObjectAlignmentMask))); |
+ size->ClearFlag(HValue::kCanOverflow); |
+ size = Add<HBitwise>( |
+ Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( |
+ ~kObjectAlignmentMask))); |
+ return size; |
+} |
+ |
+ |
+void HGraphBuilder::BuildCopySeqStringChars(HValue* src, |
+ HValue* src_offset, |
+ String::Encoding src_encoding, |
+ HValue* dst, |
+ HValue* dst_offset, |
+ String::Encoding dst_encoding, |
+ HValue* length) { |
+ ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || |
+ src_encoding == String::ONE_BYTE_ENCODING); |
+ LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
+ HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
+ { |
+ HValue* src_index = Add<HAdd>(src_offset, index); |
+ HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index); |
+ HValue* dst_index = Add<HAdd>(dst_offset, index); |
+ Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); |
+ } |
+ loop.EndBody(); |
+} |
+ |
+ |
+HValue* HGraphBuilder::BuildUncheckedStringAdd(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()); |
+ |
+ // Check if we concatenated the strings here, or if we have to resort to the |
+ // runtime function. |
+ HIfContinuation handled(graph()->CreateBasicBlock(), |
+ graph()->CreateBasicBlock()); |
+ |
+ // Check if both parameters do not exceed half the max string length, because |
+ // exceptionally long strings should be handled in the runtime. Unfortunately |
+ // we cannot actually check whether the combined length of both strings |
+ // exceeds String::kMaxLength (because of unclear results from the |
+ // representation inference phase), so we use a pessimistic approach here |
+ // instead, checking that the length of either substring does not exceed half |
+ // of String::kMaxLength. |
+ HConstant* max_length = Add<HConstant>(String::kMaxLength / 2); |
+ IfBuilder if_nooverflow(this); |
+ if_nooverflow.If<HCompareNumericAndBranch>( |
+ left_length, max_length, Token::LTE); |
+ if_nooverflow.AndIf<HCompareNumericAndBranch>( |
+ right_length, max_length, Token::LTE); |
+ if_nooverflow.Then(); |
+ { |
+ // 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 difference of instance types. |
+ HValue* xored_instance_types = Add<HBitwise>( |
+ Token::BIT_XOR, left_instance_type, right_instance_type); |
+ |
+ // Compute the length of the resulting string. |
+ HValue* length = Add<HAdd>(left_length, right_length); |
+ |
+ // Check if we should create a cons string. |
+ IfBuilder if_createcons(this); |
+ if_createcons.If<HCompareNumericAndBranch>( |
+ 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. |
+ 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 = Add<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>( |
+ Add<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>( |
+ Add<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); |
+ |
+ // Cons string is result. |
+ Push(string); |
+ } |
+ if_createcons.Else(); |
+ { |
+ // Compute union of instance types. |
+ HValue* ored_instance_types = Add<HBitwise>( |
+ Token::BIT_OR, left_instance_type, right_instance_type); |
+ |
+ // Check if both strings have the same encoding and both are |
+ // sequential. |
+ IfBuilder if_sameencodingandsequential(this); |
+ if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
+ Add<HBitwise>( |
+ Token::BIT_AND, xored_instance_types, |
+ Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
+ graph()->GetConstant0(), Token::EQ); |
+ if_sameencodingandsequential.And(); |
+ STATIC_ASSERT(kSeqStringTag == 0); |
+ if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
+ Add<HBitwise>( |
+ Token::BIT_AND, ored_instance_types, |
+ Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
+ graph()->GetConstant0(), Token::EQ); |
+ if_sameencodingandsequential.Then(); |
+ { |
+ // Check if the result is a one-byte string. |
+ IfBuilder if_onebyte(this); |
+ STATIC_ASSERT(kOneByteStringTag != 0); |
+ if_onebyte.If<HCompareNumericAndBranch>( |
+ Add<HBitwise>( |
+ Token::BIT_AND, ored_instance_types, |
+ Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
+ 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); |
+ |
+ // Copy bytes from the left string. |
+ BuildCopySeqStringChars( |
+ left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
+ string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
+ left_length); |
+ |
+ // Copy bytes from the right string. |
+ BuildCopySeqStringChars( |
+ right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
+ string, left_length, String::ONE_BYTE_ENCODING, |
+ right_length); |
+ |
+ // Return the string. |
+ Push(string); |
+ } |
+ if_onebyte.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); |
+ |
+ // Copy bytes from the left string. |
+ BuildCopySeqStringChars( |
+ left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
+ string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
+ left_length); |
+ |
+ // Copy bytes from the right string. |
+ BuildCopySeqStringChars( |
+ right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
+ string, left_length, String::TWO_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)); |
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
+ length); |
+ Push(string); |
+ } |
+ if_sameencodingandsequential.JoinContinuation(&handled); |
+ } |
+ if_createcons.JoinContinuation(&handled); |
+ } |
+ if_nooverflow.JoinContinuation(&handled); |
+ |
+ // Check if the strings were concatenated successfully, otherwise fallback to |
+ // add the strings in the runtime. |
+ IfBuilder if_handled(this, &handled); |
+ if_handled.Then(); |
+ { |
+ // Count the native string addition. |
+ AddIncrementCounter(isolate()->counters()->string_add_native()); |
+ } |
+ if_handled.Else(); |
+ { |
+ // Fallback to the runtime to add the two strings. |
+ Add<HPushArgument>(left); |
+ Add<HPushArgument>(right); |
+ Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
+ Runtime::FunctionForId(Runtime::kStringAdd), |
+ 2)); |
+ } |
+ if_handled.End(); |
+ |
+ return Pop(); |
+} |
+ |
+ |
+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()); |
+ |
+ // Check if left string is empty. |
+ IfBuilder if_leftisempty(this); |
+ if_leftisempty.If<HCompareNumericAndBranch>( |
+ left_length, graph()->GetConstant0(), Token::EQ); |
+ if_leftisempty.Then(); |
+ { |
+ // Count the native string addition. |
+ AddIncrementCounter(isolate()->counters()->string_add_native()); |
+ |
+ // Just return the right string. |
+ Push(right); |
+ } |
+ if_leftisempty.Else(); |
+ { |
+ // Check if right string is empty. |
+ IfBuilder if_rightisempty(this); |
+ if_rightisempty.If<HCompareNumericAndBranch>( |
+ right_length, graph()->GetConstant0(), Token::EQ); |
+ if_rightisempty.Then(); |
+ { |
+ // Count the native string addition. |
+ AddIncrementCounter(isolate()->counters()->string_add_native()); |
+ |
+ // Just return the left string. |
+ Push(left); |
+ } |
+ if_rightisempty.Else(); |
+ { |
+ // Concatenate the two non-empty strings. |
+ Push(BuildUncheckedStringAdd(left, right, pretenure_flag)); |
+ } |
+ if_rightisempty.End(); |
+ } |
+ if_leftisempty.End(); |
+ |
+ return Pop(); |
+} |
+ |
+ |
HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
HValue* checked_object, |
HValue* key, |