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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/ia32/code-stubs-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1265 matching lines...) Expand 10 before | Expand all | Expand 10 after
1276 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, 1276 BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
1277 array_length, elements_length); 1277 array_length, elements_length);
1278 1278
1279 if_builder.End(); 1279 if_builder.End();
1280 } 1280 }
1281 1281
1282 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); 1282 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
1283 } 1283 }
1284 1284
1285 1285
1286 HValue* HGraphBuilder::BuildLookupNumberStringCache( 1286 HValue* HGraphBuilder::BuildNumberToString(HValue* object,
1287 HValue* object, 1287 Handle<Type> type) {
1288 HIfContinuation* continuation) { 1288 NoObservableSideEffectsScope scope(this);
1289
1289 // Create a joinable continuation. 1290 // Create a joinable continuation.
1290 HIfContinuation found(graph()->CreateBasicBlock(), 1291 HIfContinuation found(graph()->CreateBasicBlock(),
1291 graph()->CreateBasicBlock()); 1292 graph()->CreateBasicBlock());
1292 1293
1293 // Load the number string cache. 1294 // Load the number string cache.
1294 HValue* number_string_cache = 1295 HValue* number_string_cache =
1295 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); 1296 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1296 1297
1297 // Make the hash maks from the length of the number string cache. It 1298 // Make the hash mask from the length of the number string cache. It
1298 // contains two elements (number and string) for each cache entry. 1299 // contains two elements (number and string) for each cache entry.
1299 HValue* mask = AddLoadFixedArrayLength(number_string_cache); 1300 HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1300 mask->set_type(HType::Smi()); 1301 mask->set_type(HType::Smi());
1301 mask = Add<HSar>(mask, graph()->GetConstant1()); 1302 mask = Add<HSar>(mask, graph()->GetConstant1());
1302 mask = Add<HSub>(mask, graph()->GetConstant1()); 1303 mask = Add<HSub>(mask, graph()->GetConstant1());
1303 1304
1304 // Check whether object is a smi. 1305 // Check whether object is a smi.
1305 IfBuilder if_objectissmi(this); 1306 IfBuilder if_objectissmi(this);
1306 if_objectissmi.If<HIsSmiAndBranch>(object); 1307 if_objectissmi.If<HIsSmiAndBranch>(object);
1307 if_objectissmi.Then(); 1308 if_objectissmi.Then();
1308 { 1309 {
1309 // Compute hash for smi similar to smi_get_hash(). 1310 // Compute hash for smi similar to smi_get_hash().
1310 HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask); 1311 HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask);
1311 1312
1312 // Load the key. 1313 // Load the key.
1313 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); 1314 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1314 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, 1315 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1315 static_cast<HValue*>(NULL), 1316 static_cast<HValue*>(NULL),
1316 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1317 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1317 1318
1318 // Check if object == key. 1319 // Check if object == key.
1319 IfBuilder if_objectiskey(this); 1320 IfBuilder if_objectiskey(this);
1320 if_objectiskey.If<HCompareObjectEqAndBranch>(key, object); 1321 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1321 if_objectiskey.Then(); 1322 if_objectiskey.Then();
1322 { 1323 {
1323 // Make the key_index available. 1324 // Make the key_index available.
1324 Push(key_index); 1325 Push(key_index);
1325 } 1326 }
1326 if_objectiskey.JoinContinuation(&found); 1327 if_objectiskey.JoinContinuation(&found);
1327 } 1328 }
1328 if_objectissmi.Else(); 1329 if_objectissmi.Else();
1329 { 1330 {
1330 // Check if object is a heap number. 1331 if (type->Is(Type::Smi())) {
1331 IfBuilder if_objectisnumber(this); 1332 if_objectissmi.Deopt("Excepted smi");
1332 if_objectisnumber.If<HCompareMap>( 1333 } else {
1333 object, isolate()->factory()->heap_number_map()); 1334 // Check if the object is a heap number.
1334 if_objectisnumber.Then(); 1335 IfBuilder if_objectisnumber(this);
1335 { 1336 if_objectisnumber.If<HCompareMap>(
1336 // Compute hash for heap number similar to double_get_hash(). 1337 object, isolate()->factory()->heap_number_map());
1337 HValue* low = Add<HLoadNamedField>( 1338 if_objectisnumber.Then();
1338 object, HObjectAccess::ForHeapNumberValueLowestBits()); 1339 {
1339 HValue* high = Add<HLoadNamedField>( 1340 // Compute hash for heap number similar to double_get_hash().
1340 object, HObjectAccess::ForHeapNumberValueHighestBits()); 1341 HValue* low = Add<HLoadNamedField>(
1341 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high); 1342 object, HObjectAccess::ForHeapNumberValueLowestBits());
1342 hash = Add<HBitwise>(Token::BIT_AND, hash, mask); 1343 HValue* high = Add<HLoadNamedField>(
1344 object, HObjectAccess::ForHeapNumberValueHighestBits());
1345 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
1346 hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
1343 1347
1344 // Load the key. 1348 // Load the key.
1345 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); 1349 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1346 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, 1350 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1347 static_cast<HValue*>(NULL), 1351 static_cast<HValue*>(NULL),
1348 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1352 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1349 1353
1350 // Check if key is a heap number. 1354 // Check if key is a heap number (the number string cache contains only
1351 IfBuilder if_keyisnumber(this); 1355 // SMIs and heap number, so it is sufficient to do a SMI check here).
1352 if_keyisnumber.IfNot<HIsSmiAndBranch>(key); 1356 IfBuilder if_keyisnotsmi(this);
1353 if_keyisnumber.AndIf<HCompareMap>( 1357 if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1354 key, isolate()->factory()->heap_number_map()); 1358 if_keyisnotsmi.Then();
1355 if_keyisnumber.Then(); 1359 {
1360 // Check if values of key and object match.
1361 IfBuilder if_keyeqobject(this);
1362 if_keyeqobject.If<HCompareNumericAndBranch>(
1363 Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
1364 Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
1365 Token::EQ);
1366 if_keyeqobject.Then();
1367 {
1368 // Make the key_index available.
1369 Push(key_index);
1370 }
1371 if_keyeqobject.JoinContinuation(&found);
1372 }
1373 if_keyisnotsmi.JoinContinuation(&found);
1374 }
1375 if_objectisnumber.Else();
1356 { 1376 {
1357 // Check if values of key and object match. 1377 if (type->Is(Type::Number())) {
1358 IfBuilder if_keyeqobject(this); 1378 if_objectisnumber.Deopt("Expected heap number");
1359 if_keyeqobject.If<HCompareNumericAndBranch>(
1360 Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
1361 Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
1362 Token::EQ);
1363 if_keyeqobject.Then();
1364 {
1365 // Make the key_index available.
1366 Push(key_index);
1367 } 1379 }
1368 if_keyeqobject.JoinContinuation(&found);
1369 } 1380 }
1370 if_keyisnumber.JoinContinuation(&found); 1381 if_objectisnumber.JoinContinuation(&found);
1371 } 1382 }
1372 if_objectisnumber.JoinContinuation(&found);
1373 } 1383 }
1374 if_objectissmi.End(); 1384 if_objectissmi.JoinContinuation(&found);
1375 1385
1376 // Check for cache hit. 1386 // Check for cache hit.
1377 IfBuilder if_found(this, &found); 1387 IfBuilder if_found(this, &found);
1378 if_found.Then(); 1388 if_found.Then();
1389 {
1390 // Count number to string operation in native code.
1391 AddIncrementCounter(isolate()->counters()->number_to_string_native());
1379 1392
1380 // Load the value in case of cache hit. 1393 // Load the value in case of cache hit.
1381 HValue* key_index = Pop(); 1394 HValue* key_index = Pop();
1382 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1()); 1395 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
1383 HValue* value = Add<HLoadKeyed>(number_string_cache, value_index, 1396 Push(Add<HLoadKeyed>(number_string_cache, value_index,
1384 static_cast<HValue*>(NULL), 1397 static_cast<HValue*>(NULL),
1385 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1398 FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1386 AddIncrementCounter(isolate()->counters()->number_to_string_native()); 1399 }
1387
1388 if_found.CaptureContinuation(continuation);
1389
1390 // The value is only available in true branch of continuation.
1391 return value;
1392 }
1393
1394
1395 HValue* HGraphBuilder::BuildNumberToString(HValue* number) {
1396 NoObservableSideEffectsScope scope(this);
1397
1398 // Lookup the number in the number string cache.
1399 HIfContinuation continuation;
1400 HValue* value = BuildLookupNumberStringCache(number, &continuation);
1401 IfBuilder if_found(this, &continuation);
1402 if_found.Then();
1403
1404 // Cache hit.
1405 Push(value);
1406
1407 if_found.Else(); 1400 if_found.Else();
1408 1401 {
1409 // Cache miss, fallback to runtime. 1402 // Cache miss, fallback to runtime.
1410 Add<HPushArgument>(number); 1403 Add<HPushArgument>(object);
1411 Push(Add<HCallRuntime>( 1404 Push(Add<HCallRuntime>(
1412 isolate()->factory()->empty_string(), 1405 isolate()->factory()->empty_string(),
1413 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), 1406 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1414 1)); 1407 1));
1415 1408 }
1416 if_found.End(); 1409 if_found.End();
1417 1410
1418 return Pop(); 1411 return Pop();
1419 } 1412 }
1420 1413
1421 1414
1422 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 1415 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
1423 HValue* checked_object, 1416 HValue* checked_object,
1424 HValue* key, 1417 HValue* key,
1425 HValue* val, 1418 HValue* val,
(...skipping 6417 matching lines...) Expand 10 before | Expand all | Expand 10 after
7843 7836
7844 if (right_type->Is(Type::None())) { 7837 if (right_type->Is(Type::None())) {
7845 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", 7838 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
7846 Deoptimizer::SOFT); 7839 Deoptimizer::SOFT);
7847 right_type = handle(Type::Any(), isolate()); 7840 right_type = handle(Type::Any(), isolate());
7848 } else { 7841 } else {
7849 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); 7842 if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
7850 right_rep = Representation::FromType(right_type); 7843 right_rep = Representation::FromType(right_type);
7851 } 7844 }
7852 7845
7846 // Special case for string addition here.
7847 if (op == Token::ADD &&
7848 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
7849 if (left_type->Is(Type::String())) {
7850 IfBuilder if_isstring(this);
7851 if_isstring.If<HIsStringAndBranch>(left);
7852 if_isstring.Then();
7853 if_isstring.ElseDeopt("Expected string for LHS of binary operation");
7854 } else if (left_type->Is(Type::Number())) {
7855 left = BuildNumberToString(left, left_type);
7856 } else {
7857 ASSERT(right_type->Is(Type::String()));
7858 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
7859 Add<HPushArgument>(left);
7860 Add<HPushArgument>(right);
7861 return NewUncasted<HInvokeFunction>(function, 2);
7862 }
7863
7864 if (right_type->Is(Type::String())) {
7865 IfBuilder if_isstring(this);
7866 if_isstring.If<HIsStringAndBranch>(right);
7867 if_isstring.Then();
7868 if_isstring.ElseDeopt("Expected string for RHS of binary operation");
7869 } else if (right_type->Is(Type::Number())) {
7870 right = BuildNumberToString(right, right_type);
7871 } else {
7872 ASSERT(left_type->Is(Type::String()));
7873 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
7874 Add<HPushArgument>(left);
7875 Add<HPushArgument>(right);
7876 return NewUncasted<HInvokeFunction>(function, 2);
7877 }
7878
7879 return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
7880 }
7881
7853 if (binop_stub) { 7882 if (binop_stub) {
7854 left = EnforceNumberType(left, left_type); 7883 left = EnforceNumberType(left, left_type);
7855 right = EnforceNumberType(right, right_type); 7884 right = EnforceNumberType(right, right_type);
7856 } 7885 }
7857 7886
7858 Representation result_rep = Representation::FromType(result_type); 7887 Representation result_rep = Representation::FromType(result_type);
7859 7888
7860 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || 7889 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
7861 (right_rep.IsTagged() && !right_rep.IsSmi()); 7890 (right_rep.IsTagged() && !right_rep.IsSmi());
7862 bool is_string_add = op == Token::ADD &&
7863 (left_type->Is(Type::String()) ||
7864 right_type->Is(Type::String()));
7865 7891
7866 HInstruction* instr = NULL; 7892 HInstruction* instr = NULL;
7867 // Only the stub is allowed to call into the runtime, since otherwise we would 7893 // Only the stub is allowed to call into the runtime, since otherwise we would
7868 // inline several instructions (including the two pushes) for every tagged 7894 // inline several instructions (including the two pushes) for every tagged
7869 // operation in optimized code, which is more expensive, than a stub call. 7895 // operation in optimized code, which is more expensive, than a stub call.
7870 if (binop_stub && is_non_primitive && !is_string_add) { 7896 if (binop_stub && is_non_primitive) {
7871 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); 7897 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
7872 Add<HPushArgument>(left); 7898 Add<HPushArgument>(left);
7873 Add<HPushArgument>(right); 7899 Add<HPushArgument>(right);
7874 instr = NewUncasted<HInvokeFunction>(function, 2); 7900 instr = NewUncasted<HInvokeFunction>(function, 2);
7875 } else { 7901 } else {
7876 switch (op) { 7902 switch (op) {
7877 case Token::ADD: 7903 case Token::ADD:
7878 if (is_string_add) { 7904 instr = NewUncasted<HAdd>(left, right);
7879 StringAddFlags flags = STRING_ADD_CHECK_BOTH;
7880 if (left_type->Is(Type::String())) {
7881 BuildCheckHeapObject(left);
7882 AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
7883 flags = STRING_ADD_CHECK_RIGHT;
7884 }
7885 if (right_type->Is(Type::String())) {
7886 BuildCheckHeapObject(right);
7887 AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
7888 flags = (flags == STRING_ADD_CHECK_BOTH)
7889 ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE;
7890 }
7891 instr = NewUncasted<HStringAdd>(left, right, flags);
7892 } else {
7893 instr = NewUncasted<HAdd>(left, right);
7894 }
7895 break; 7905 break;
7896 case Token::SUB: 7906 case Token::SUB:
7897 instr = NewUncasted<HSub>(left, right); 7907 instr = NewUncasted<HSub>(left, right);
7898 break; 7908 break;
7899 case Token::MUL: 7909 case Token::MUL:
7900 instr = NewUncasted<HMul>(left, right); 7910 instr = NewUncasted<HMul>(left, right);
7901 break; 7911 break;
7902 case Token::MOD: 7912 case Token::MOD:
7903 instr = NewUncasted<HMod>(left, right, fixed_right_arg); 7913 instr = NewUncasted<HMod>(left, right, fixed_right_arg);
7904 break; 7914 break;
(...skipping 1178 matching lines...) Expand 10 before | Expand all | Expand 10 after
9083 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { 9093 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
9084 return Bailout(kInlinedRuntimeFunctionGetFromCache); 9094 return Bailout(kInlinedRuntimeFunctionGetFromCache);
9085 } 9095 }
9086 9096
9087 9097
9088 // Fast support for number to string. 9098 // Fast support for number to string.
9089 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { 9099 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
9090 ASSERT_EQ(1, call->arguments()->length()); 9100 ASSERT_EQ(1, call->arguments()->length());
9091 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 9101 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9092 HValue* number = Pop(); 9102 HValue* number = Pop();
9093 HValue* result = BuildNumberToString(number); 9103 HValue* result = BuildNumberToString(
9104 number, handle(Type::Number(), isolate()));
9094 return ast_context()->ReturnValue(result); 9105 return ast_context()->ReturnValue(result);
9095 } 9106 }
9096 9107
9097 9108
9098 // Fast call for custom callbacks. 9109 // Fast call for custom callbacks.
9099 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { 9110 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
9100 // 1 ~ The function to call is not itself an argument to the call. 9111 // 1 ~ The function to call is not itself an argument to the call.
9101 int arg_count = call->arguments()->length() - 1; 9112 int arg_count = call->arguments()->length() - 1;
9102 ASSERT(arg_count >= 1); // There's always at least a receiver. 9113 ASSERT(arg_count >= 1); // There's always at least a receiver.
9103 9114
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after
9841 if (ShouldProduceTraceOutput()) { 9852 if (ShouldProduceTraceOutput()) {
9842 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 9853 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
9843 } 9854 }
9844 9855
9845 #ifdef DEBUG 9856 #ifdef DEBUG
9846 graph_->Verify(false); // No full verify. 9857 graph_->Verify(false); // No full verify.
9847 #endif 9858 #endif
9848 } 9859 }
9849 9860
9850 } } // namespace v8::internal 9861 } } // namespace v8::internal
OLDNEW
« 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