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

Unified Diff: src/hydrogen.cc

Issue 106453003: Allocation site support for monomorphic StringAdds in BinaryOps. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: REBASE Created 6 years, 12 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/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
}
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698