Revision: 18005
Author: [email protected]
Date: Fri Nov 22 12:03:01 2013 UTC
Log: Fix combined string length computation.
For 31-bit smis, we don't need to explicitly check whether the
combined string length exceeds the max supported string length,
since the value must be converted to a smi at some point (i.e.
when it is stored into the string length field of the resulting
string), which will emit an overflow check.
For 32-bit smis, we insert an explicit check that the combined
string length does not exceed String::kMaxLength.
This also enables to get rid of the JoinContinuation() usage in
BuildUncheckedStringAdd().
BUG=v8:2990
LOG=n
[email protected]
Review URL: https://codereview.chromium.org/82733003
http://code.google.com/p/v8/source/detail?r=18005
Modified:
/branches/bleeding_edge/src/hydrogen.cc
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Nov 22 11:49:04 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Nov 22 12:03:01 2013 UTC
@@ -1733,248 +1733,237 @@
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());
+ // 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");
+ }
- // 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());
+ // 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 = AddUncasted<HBitwise>(
- Token::BIT_XOR, left_instance_type, right_instance_type);
+ // Compute difference of instance types.
+ HValue* xored_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_XOR, left_instance_type, right_instance_type);
- // Compute the length of the resulting string.
- HValue* length = AddUncasted<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);
- // 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();
+ // 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();
{
- // 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);
+ // 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();
- // Compute the intersection of instance types.
- HValue* anded_instance_types = AddUncasted<HBitwise>(
- Token::BIT_AND, left_instance_type, right_instance_type);
+ // 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);
- // 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.
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Cons string is result.
+ Push(string);
+ }
+ if_createcons.Else();
+ {
+ // Compute union of instance types.
+ HValue* ored_instance_types = AddUncasted<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>(
+ AddUncasted<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>(
+ AddUncasted<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);
- STATIC_ASSERT(kOneByteDataHintMask != 0);
if_onebyte.If<HCompareNumericAndBranch>(
AddUncasted<HBitwise>(
- Token::BIT_AND, anded_instance_types,
- Add<HConstant>(static_cast<int32_t>(
- kStringEncodingMask | kOneByteDataHintMask))),
+ Token::BIT_AND, ored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
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();
+ // Calculate the number of bytes needed for the characters in the
+ // string while observing object alignment.
+ HValue* size = BuildSeqStringSizeFor(
+ length, String::ONE_BYTE_ENCODING);
- // 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);
+ // 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);
- // Cons string is result.
- Push(string);
- }
- if_createcons.Else();
- {
- // Compute union of instance types.
- HValue* ored_instance_types = AddUncasted<HBitwise>(
- Token::BIT_OR, left_instance_type, right_instance_type);
+ // We can safely skip the write barrier for storing map here.
+ AddStoreMapConstantNoWriteBarrier(string, map);
- // Check if both strings have the same encoding and both are
- // sequential.
- IfBuilder if_sameencodingandsequential(this);
- if_sameencodingandsequential.If<HCompareNumericAndBranch>(
- AddUncasted<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>(
- AddUncasted<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>(
- AddUncasted<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);
+ // Length must be stored into the string before we copy characters
to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
- // 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);
+ // Copy bytes from the left string.
+ BuildCopySeqStringChars(
+ left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ left_length);
- // We can safely skip the write barrier for storing map here.
- AddStoreMapConstantNoWriteBarrier(string, map);
+ // Copy bytes from the right string.
+ BuildCopySeqStringChars(
+ right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, left_length, String::ONE_BYTE_ENCODING,
+ right_length);
- // Length must be stored into the string before we copy
characters to
- // make debug verification code happy.
- Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
- length);
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
- // Copy bytes from the left string.
- BuildCopySeqStringChars(
- left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
- string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
- left_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);
- // Copy bytes from the right string.
- BuildCopySeqStringChars(
- right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
- string, left_length, String::ONE_BYTE_ENCODING,
- right_length);
+ // 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);
- // 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);
+ // We can safely skip the write barrier for storing map here.
+ AddStoreMapConstantNoWriteBarrier(string, map);
- // 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);
+ // Length must be stored into the string before we copy characters
to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
- // 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);
- // 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 right string.
+ BuildCopySeqStringChars(
+ right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ string, left_length, String::TWO_BYTE_ENCODING,
+ right_length);
- // Copy bytes from the left string.
- BuildCopySeqStringChars(
- left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
- string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
- left_length);
+ // Return the string.
+ Push(string);
+ }
+ if_onebyte.End();
- // Copy bytes from the right string.
- BuildCopySeqStringChars(
- right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
- string, left_length, String::TWO_BYTE_ENCODING,
- right_length);
+ // Initialize the (common) string fields.
+ HValue* string = Pop();
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+ Add<HConstant>(String::kEmptyHashField));
- // Return the string.
- Push(string);
- }
- if_onebyte.End();
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
- // Initialize the (common) string fields.
- HValue* string = Pop();
- Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
- Add<HConstant>(String::kEmptyHashField));
- Push(string);
- }
- if_sameencodingandsequential.JoinContinuation(&handled);
+ Push(string);
}
- if_createcons.JoinContinuation(&handled);
+ if_sameencodingandsequential.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_sameencodingandsequential.End();
}
- 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();
+ if_createcons.End();
return Pop();
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.