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

Unified Diff: src/hydrogen.cc

Issue 27674002: Inline number to string conversion for string addition into BinaryOp(Stub). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Improve string-check in BuildBinaryOperation. Created 7 years, 2 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/ia32/code-stubs-ia32.cc » ('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 14ac329575680c20e6cbac81e6298a9f6ef914da..fbca58f0c6444161ca524c891ce0693eca1e236c 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1283,9 +1283,10 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
}
-HValue* HGraphBuilder::BuildLookupNumberStringCache(
- HValue* object,
- HIfContinuation* continuation) {
+HValue* HGraphBuilder::BuildNumberToString(HValue* object,
+ Handle<Type> type) {
+ NoObservableSideEffectsScope scope(this);
+
// Create a joinable continuation.
HIfContinuation found(graph()->CreateBasicBlock(),
graph()->CreateBasicBlock());
@@ -1294,7 +1295,7 @@ HValue* HGraphBuilder::BuildLookupNumberStringCache(
HValue* number_string_cache =
Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
- // Make the hash maks from the length of the number string cache. It
+ // Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
HValue* mask = AddLoadFixedArrayLength(number_string_cache);
mask->set_type(HType::Smi());
@@ -1317,7 +1318,7 @@ HValue* HGraphBuilder::BuildLookupNumberStringCache(
// Check if object == key.
IfBuilder if_objectiskey(this);
- if_objectiskey.If<HCompareObjectEqAndBranch>(key, object);
+ if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
if_objectiskey.Then();
{
// Make the key_index available.
@@ -1327,92 +1328,84 @@ HValue* HGraphBuilder::BuildLookupNumberStringCache(
}
if_objectissmi.Else();
{
- // Check if object is a heap number.
- IfBuilder if_objectisnumber(this);
- if_objectisnumber.If<HCompareMap>(
- object, isolate()->factory()->heap_number_map());
- if_objectisnumber.Then();
- {
- // Compute hash for heap number similar to double_get_hash().
- HValue* low = Add<HLoadNamedField>(
- object, HObjectAccess::ForHeapNumberValueLowestBits());
- HValue* high = Add<HLoadNamedField>(
- object, HObjectAccess::ForHeapNumberValueHighestBits());
- HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
- hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
-
- // Load the key.
- HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
- HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
- static_cast<HValue*>(NULL),
- FAST_ELEMENTS, ALLOW_RETURN_HOLE);
-
- // Check if key is a heap number.
- IfBuilder if_keyisnumber(this);
- if_keyisnumber.IfNot<HIsSmiAndBranch>(key);
- if_keyisnumber.AndIf<HCompareMap>(
- key, isolate()->factory()->heap_number_map());
- if_keyisnumber.Then();
+ if (type->Is(Type::Smi())) {
+ if_objectissmi.Deopt("Excepted smi");
+ } else {
+ // Check if the object is a heap number.
+ IfBuilder if_objectisnumber(this);
+ if_objectisnumber.If<HCompareMap>(
+ object, isolate()->factory()->heap_number_map());
+ if_objectisnumber.Then();
{
- // Check if values of key and object match.
- IfBuilder if_keyeqobject(this);
- if_keyeqobject.If<HCompareNumericAndBranch>(
- Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
- Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
- Token::EQ);
- if_keyeqobject.Then();
+ // Compute hash for heap number similar to double_get_hash().
+ HValue* low = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueLowestBits());
+ HValue* high = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueHighestBits());
+ HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
+ hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
+
+ // Load the key.
+ HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
+ HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+
+ // Check if key is a heap number (the number string cache contains only
+ // SMIs and heap number, so it is sufficient to do a SMI check here).
+ IfBuilder if_keyisnotsmi(this);
+ if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
+ if_keyisnotsmi.Then();
{
- // Make the key_index available.
- Push(key_index);
+ // Check if values of key and object match.
+ IfBuilder if_keyeqobject(this);
+ if_keyeqobject.If<HCompareNumericAndBranch>(
+ Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
+ Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
+ Token::EQ);
+ if_keyeqobject.Then();
+ {
+ // Make the key_index available.
+ Push(key_index);
+ }
+ if_keyeqobject.JoinContinuation(&found);
+ }
+ if_keyisnotsmi.JoinContinuation(&found);
+ }
+ if_objectisnumber.Else();
+ {
+ if (type->Is(Type::Number())) {
+ if_objectisnumber.Deopt("Expected heap number");
}
- if_keyeqobject.JoinContinuation(&found);
}
- if_keyisnumber.JoinContinuation(&found);
+ if_objectisnumber.JoinContinuation(&found);
}
- if_objectisnumber.JoinContinuation(&found);
}
- if_objectissmi.End();
+ if_objectissmi.JoinContinuation(&found);
// Check for cache hit.
IfBuilder if_found(this, &found);
if_found.Then();
+ {
+ // Count number to string operation in native code.
+ AddIncrementCounter(isolate()->counters()->number_to_string_native());
- // Load the value in case of cache hit.
- HValue* key_index = Pop();
- HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
- HValue* value = Add<HLoadKeyed>(number_string_cache, value_index,
- static_cast<HValue*>(NULL),
- FAST_ELEMENTS, ALLOW_RETURN_HOLE);
- AddIncrementCounter(isolate()->counters()->number_to_string_native());
-
- if_found.CaptureContinuation(continuation);
-
- // The value is only available in true branch of continuation.
- return value;
-}
-
-
-HValue* HGraphBuilder::BuildNumberToString(HValue* number) {
- NoObservableSideEffectsScope scope(this);
-
- // Lookup the number in the number string cache.
- HIfContinuation continuation;
- HValue* value = BuildLookupNumberStringCache(number, &continuation);
- IfBuilder if_found(this, &continuation);
- if_found.Then();
-
- // Cache hit.
- Push(value);
-
+ // Load the value in case of cache hit.
+ HValue* key_index = Pop();
+ HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
+ Push(Add<HLoadKeyed>(number_string_cache, value_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE));
+ }
if_found.Else();
-
- // Cache miss, fallback to runtime.
- Add<HPushArgument>(number);
- Push(Add<HCallRuntime>(
- isolate()->factory()->empty_string(),
- Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
- 1));
-
+ {
+ // Cache miss, fallback to runtime.
+ Add<HPushArgument>(object);
+ Push(Add<HCallRuntime>(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
+ 1));
+ }
if_found.End();
return Pop();
@@ -7850,6 +7843,42 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(
right_rep = Representation::FromType(right_type);
}
+ // Special case for string addition here.
+ if (op == Token::ADD &&
+ (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
+ if (left_type->Is(Type::String())) {
+ IfBuilder if_isstring(this);
+ if_isstring.If<HIsStringAndBranch>(left);
+ if_isstring.Then();
+ if_isstring.ElseDeopt("Expected string for LHS of binary operation");
+ } else if (left_type->Is(Type::Number())) {
+ left = BuildNumberToString(left, left_type);
+ } else {
+ ASSERT(right_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return NewUncasted<HInvokeFunction>(function, 2);
+ }
+
+ if (right_type->Is(Type::String())) {
+ IfBuilder if_isstring(this);
+ if_isstring.If<HIsStringAndBranch>(right);
+ if_isstring.Then();
+ if_isstring.ElseDeopt("Expected string for RHS of binary operation");
+ } else if (right_type->Is(Type::Number())) {
+ right = BuildNumberToString(right, right_type);
+ } else {
+ ASSERT(left_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return NewUncasted<HInvokeFunction>(function, 2);
+ }
+
+ return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
+ }
+
if (binop_stub) {
left = EnforceNumberType(left, left_type);
right = EnforceNumberType(right, right_type);
@@ -7859,15 +7888,12 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(
bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
(right_rep.IsTagged() && !right_rep.IsSmi());
- bool is_string_add = op == Token::ADD &&
- (left_type->Is(Type::String()) ||
- right_type->Is(Type::String()));
HInstruction* instr = NULL;
// Only the stub is allowed to call into the runtime, since otherwise we would
// inline several instructions (including the two pushes) for every tagged
// operation in optimized code, which is more expensive, than a stub call.
- if (binop_stub && is_non_primitive && !is_string_add) {
+ if (binop_stub && is_non_primitive) {
HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
Add<HPushArgument>(left);
Add<HPushArgument>(right);
@@ -7875,23 +7901,7 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(
} else {
switch (op) {
case Token::ADD:
- if (is_string_add) {
- StringAddFlags flags = STRING_ADD_CHECK_BOTH;
- if (left_type->Is(Type::String())) {
- BuildCheckHeapObject(left);
- AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
- flags = STRING_ADD_CHECK_RIGHT;
- }
- if (right_type->Is(Type::String())) {
- BuildCheckHeapObject(right);
- AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
- flags = (flags == STRING_ADD_CHECK_BOTH)
- ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE;
- }
- instr = NewUncasted<HStringAdd>(left, right, flags);
- } else {
- instr = NewUncasted<HAdd>(left, right);
- }
+ instr = NewUncasted<HAdd>(left, right);
break;
case Token::SUB:
instr = NewUncasted<HSub>(left, right);
@@ -9090,7 +9100,8 @@ void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* number = Pop();
- HValue* result = BuildNumberToString(number);
+ HValue* result = BuildNumberToString(
+ number, handle(Type::Number(), isolate()));
return ast_context()->ReturnValue(result);
}
« no previous file with comments | « src/hydrogen.h ('k') | src/ia32/code-stubs-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698