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

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: 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::BuildSmiToString(HValue* number) {
1287 HValue* object, 1287 // Everything in here is safe wrt. observable side effects.
rossberg 2013/10/17 11:02:19 Nit: this comment seems redundant, the next line s
Benedikt Meurer 2013/10/18 06:53:05 Done.
1288 HIfContinuation* continuation) { 1288 NoObservableSideEffectsScope scope(this);
1289
1290 // Load the number string cache.
1291 HValue* number_string_cache =
1292 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1293
1294 // Make the hash maks from the length of the number string cache. It
rossberg 2013/10/17 11:02:19 Typo: mask
Benedikt Meurer 2013/10/18 06:53:05 Done.
1295 // contains two elements (number and string) for each cache entry.
1296 HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1297 mask->set_type(HType::Smi());
1298 mask = Add<HSar>(mask, graph()->GetConstant1());
1299 mask = Add<HSub>(mask, graph()->GetConstant1());
1300
1301 // Compute hash for smi similar to smi_get_hash().
1302 HValue* hash = Add<HBitwise>(Token::BIT_AND, number, mask);
1303
1304 // Load the key.
1305 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1306 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1307 static_cast<HValue*>(NULL),
1308 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1309
1310 // Check if number == key.
1311 IfBuilder if_numberiskey(this);
1312 if_numberiskey.If<HCompareObjectEqAndBranch>(number, key);
1313 if_numberiskey.Then();
1314 {
1315 // Count number to string operation in native code.
1316 AddIncrementCounter(isolate()->counters()->number_to_string_native());
1317
1318 // Load the value in case of cache hit.
1319 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
1320 Push(Add<HLoadKeyed>(number_string_cache, value_index,
1321 static_cast<HValue*>(NULL),
1322 FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1323 }
1324 if_numberiskey.Else();
1325 {
1326 // Cache miss, fallback to runtime.
1327 Add<HPushArgument>(number);
1328 Push(Add<HCallRuntime>(
1329 isolate()->factory()->empty_string(),
1330 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1331 1));
1332 }
1333 if_numberiskey.End();
1334
1335 return Pop();
1336 }
1337
1338
1339 HValue* HGraphBuilder::BuildNumberToString(HValue* number) {
1340 // Everything in here is safe wrt. observable side effects.
rossberg 2013/10/17 11:02:19 Nit: as above
Benedikt Meurer 2013/10/18 06:53:05 Done.
1341 NoObservableSideEffectsScope scope(this);
1342
1289 // Create a joinable continuation. 1343 // Create a joinable continuation.
1290 HIfContinuation found(graph()->CreateBasicBlock(), 1344 HIfContinuation found(graph()->CreateBasicBlock(),
1291 graph()->CreateBasicBlock()); 1345 graph()->CreateBasicBlock());
1292 1346
1293 // Load the number string cache. 1347 // Load the number string cache.
1294 HValue* number_string_cache = 1348 HValue* number_string_cache =
1295 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); 1349 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1296 1350
1297 // Make the hash maks from the length of the number string cache. It 1351 // Make the hash maks from the length of the number string cache. It
rossberg 2013/10/17 11:02:19 Same typo
Benedikt Meurer 2013/10/18 06:53:05 Done.
1298 // contains two elements (number and string) for each cache entry. 1352 // contains two elements (number and string) for each cache entry.
1299 HValue* mask = AddLoadFixedArrayLength(number_string_cache); 1353 HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1300 mask->set_type(HType::Smi()); 1354 mask->set_type(HType::Smi());
1301 mask = Add<HSar>(mask, graph()->GetConstant1()); 1355 mask = Add<HSar>(mask, graph()->GetConstant1());
1302 mask = Add<HSub>(mask, graph()->GetConstant1()); 1356 mask = Add<HSub>(mask, graph()->GetConstant1());
1303 1357
1304 // Check whether object is a smi. 1358 // Check whether number is a smi.
1305 IfBuilder if_objectissmi(this); 1359 IfBuilder if_numberissmi(this);
1306 if_objectissmi.If<HIsSmiAndBranch>(object); 1360 if_numberissmi.If<HIsSmiAndBranch>(number);
1307 if_objectissmi.Then(); 1361 if_numberissmi.Then();
1308 { 1362 {
oliv 2013/10/17 10:56:30 Please find a way to share the code with BuildSmiT
Benedikt Meurer 2013/10/18 06:53:05 Done.
1309 // Compute hash for smi similar to smi_get_hash(). 1363 // Compute hash for smi similar to smi_get_hash().
1310 HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask); 1364 HValue* hash = Add<HBitwise>(Token::BIT_AND, number, mask);
1311 1365
1312 // Load the key. 1366 // Load the key.
1313 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); 1367 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1314 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, 1368 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1315 static_cast<HValue*>(NULL), 1369 static_cast<HValue*>(NULL),
1316 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1370 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1317 1371
1318 // Check if object == key. 1372 // Check if number == key.
1319 IfBuilder if_objectiskey(this); 1373 IfBuilder if_numberiskey(this);
1320 if_objectiskey.If<HCompareObjectEqAndBranch>(key, object); 1374 if_numberiskey.If<HCompareObjectEqAndBranch>(number, key);
1321 if_objectiskey.Then(); 1375 if_numberiskey.Then();
1322 { 1376 {
1323 // Make the key_index available. 1377 // Make the key_index available.
1324 Push(key_index); 1378 Push(key_index);
1325 } 1379 }
1326 if_objectiskey.JoinContinuation(&found); 1380 if_numberiskey.JoinContinuation(&found);
1327 } 1381 }
1328 if_objectissmi.Else(); 1382 if_numberissmi.Else();
1329 { 1383 {
1330 // Check if object is a heap number. 1384 // Check that the number is actually a heap number.
1331 IfBuilder if_objectisnumber(this); 1385 BuildCheckMap(number, isolate()->factory()->heap_number_map());
1332 if_objectisnumber.If<HCompareMap>( 1386
1333 object, isolate()->factory()->heap_number_map()); 1387 // Compute hash for heap number similar to double_get_hash().
1334 if_objectisnumber.Then(); 1388 HValue* low = Add<HLoadNamedField>(
1389 number, HObjectAccess::ForHeapNumberValueLowestBits());
1390 HValue* high = Add<HLoadNamedField>(
1391 number, HObjectAccess::ForHeapNumberValueHighestBits());
1392 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
1393 hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
1394
1395 // Load the key.
1396 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1397 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1398 static_cast<HValue*>(NULL),
1399 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1400
1401 // Check if key is a heap number (the number string cache contains only
1402 // SMIs and heap number, so it is sufficient to do a SMI check here).
1403 IfBuilder if_keyisnotsmi(this);
1404 if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1405 if_keyisnotsmi.Then();
1335 { 1406 {
1336 // Compute hash for heap number similar to double_get_hash(). 1407 // Check if values of key and object match.
1337 HValue* low = Add<HLoadNamedField>( 1408 IfBuilder if_keyeqnumber(this);
1338 object, HObjectAccess::ForHeapNumberValueLowestBits()); 1409 if_keyeqnumber.If<HCompareNumericAndBranch>(
1339 HValue* high = Add<HLoadNamedField>( 1410 Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
1340 object, HObjectAccess::ForHeapNumberValueHighestBits()); 1411 Add<HLoadNamedField>(number, HObjectAccess::ForHeapNumberValue()),
1341 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high); 1412 Token::EQ);
1342 hash = Add<HBitwise>(Token::BIT_AND, hash, mask); 1413 if_keyeqnumber.Then();
1343
1344 // Load the key.
1345 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
1346 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1347 static_cast<HValue*>(NULL),
1348 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1349
1350 // Check if key is a heap number.
1351 IfBuilder if_keyisnumber(this);
1352 if_keyisnumber.IfNot<HIsSmiAndBranch>(key);
1353 if_keyisnumber.AndIf<HCompareMap>(
1354 key, isolate()->factory()->heap_number_map());
1355 if_keyisnumber.Then();
1356 { 1414 {
1357 // Check if values of key and object match. 1415 // Make the key_index available.
1358 IfBuilder if_keyeqobject(this); 1416 Push(key_index);
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 }
1368 if_keyeqobject.JoinContinuation(&found);
1369 } 1417 }
1370 if_keyisnumber.JoinContinuation(&found); 1418 if_keyeqnumber.JoinContinuation(&found);
1371 } 1419 }
1372 if_objectisnumber.JoinContinuation(&found); 1420 if_keyisnotsmi.JoinContinuation(&found);
1373 } 1421 }
1374 if_objectissmi.End(); 1422 if_numberissmi.End();
1375 1423
1376 // Check for cache hit. 1424 // Check for cache hit.
1377 IfBuilder if_found(this, &found); 1425 IfBuilder if_found(this, &found);
1378 if_found.Then(); 1426 if_found.Then();
1427 {
1428 // Count number to string operation in native code.
1429 AddIncrementCounter(isolate()->counters()->number_to_string_native());
1379 1430
1380 // Load the value in case of cache hit. 1431 // Load the value in case of cache hit.
1381 HValue* key_index = Pop(); 1432 HValue* key_index = Pop();
1382 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1()); 1433 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
1383 HValue* value = Add<HLoadKeyed>(number_string_cache, value_index, 1434 Push(Add<HLoadKeyed>(number_string_cache, value_index,
1384 static_cast<HValue*>(NULL), 1435 static_cast<HValue*>(NULL),
1385 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1436 FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1386 AddIncrementCounter(isolate()->counters()->number_to_string_native()); 1437 }
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(); 1438 if_found.Else();
1408 1439 {
1409 // Cache miss, fallback to runtime. 1440 // Cache miss, fallback to runtime.
1410 Add<HPushArgument>(number); 1441 Add<HPushArgument>(number);
1411 Push(Add<HCallRuntime>( 1442 Push(Add<HCallRuntime>(
1412 isolate()->factory()->empty_string(), 1443 isolate()->factory()->empty_string(),
1413 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), 1444 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1414 1)); 1445 1));
1415 1446 }
1416 if_found.End(); 1447 if_found.End();
1417 1448
1418 return Pop(); 1449 return Pop();
1419 } 1450 }
1420 1451
1421 1452
1422 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 1453 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
1423 HValue* checked_object, 1454 HValue* checked_object,
1424 HValue* key, 1455 HValue* key,
1425 HValue* val, 1456 HValue* val,
(...skipping 6417 matching lines...) Expand 10 before | Expand all | Expand 10 after
7843 7874
7844 if (right_type->Is(Type::None())) { 7875 if (right_type->Is(Type::None())) {
7845 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", 7876 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
7846 Deoptimizer::SOFT); 7877 Deoptimizer::SOFT);
7847 right_type = handle(Type::Any(), isolate()); 7878 right_type = handle(Type::Any(), isolate());
7848 } else { 7879 } else {
7849 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); 7880 if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
7850 right_rep = Representation::FromType(right_type); 7881 right_rep = Representation::FromType(right_type);
7851 } 7882 }
7852 7883
7884 // Special case for string addition here.
7885 if (op == Token::ADD &&
7886 (left_type->Is(Type::String()) ||
7887 right_type->Is(Type::String()))) {
7888 StringAddFlags flags = STRING_ADD_CHECK_NONE;
7889
7890 if (left_type->Is(Type::String())) {
7891 BuildCheckHeapObject(left);
7892 AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
7893 } else if (left_type->Is(Type::Smi())) {
7894 left = BuildSmiToString(EnforceNumberType(left, left_type));
7895 } else if (left_type->Is(Type::Number())) {
7896 left = BuildNumberToString(left);
7897 } else {
7898 ASSERT_EQ(STRING_ADD_CHECK_NONE, flags);
7899 flags = STRING_ADD_CHECK_LEFT;
7900 }
7901
7902 if (right_type->Is(Type::String())) {
7903 BuildCheckHeapObject(right);
7904 AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
7905 } else if (right_type->Is(Type::Smi())) {
7906 right = BuildSmiToString(EnforceNumberType(right, right_type));
7907 } else if (right_type->Is(Type::Number())) {
7908 right = BuildNumberToString(right);
7909 } else {
7910 ASSERT_EQ(STRING_ADD_CHECK_NONE, flags);
7911 flags = STRING_ADD_CHECK_RIGHT;
7912 }
7913
7914 return NewUncasted<HStringAdd>(left, right, flags);
7915 }
7916
7853 if (binop_stub) { 7917 if (binop_stub) {
7854 left = EnforceNumberType(left, left_type); 7918 left = EnforceNumberType(left, left_type);
7855 right = EnforceNumberType(right, right_type); 7919 right = EnforceNumberType(right, right_type);
7856 } 7920 }
7857 7921
7858 Representation result_rep = Representation::FromType(result_type); 7922 Representation result_rep = Representation::FromType(result_type);
7859 7923
7860 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || 7924 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
7861 (right_rep.IsTagged() && !right_rep.IsSmi()); 7925 (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 7926
7866 HInstruction* instr = NULL; 7927 HInstruction* instr = NULL;
7867 // Only the stub is allowed to call into the runtime, since otherwise we would 7928 // 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 7929 // inline several instructions (including the two pushes) for every tagged
7869 // operation in optimized code, which is more expensive, than a stub call. 7930 // operation in optimized code, which is more expensive, than a stub call.
7870 if (binop_stub && is_non_primitive && !is_string_add) { 7931 if (binop_stub && is_non_primitive) {
7871 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); 7932 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
7872 Add<HPushArgument>(left); 7933 Add<HPushArgument>(left);
7873 Add<HPushArgument>(right); 7934 Add<HPushArgument>(right);
7874 instr = NewUncasted<HInvokeFunction>(function, 2); 7935 instr = NewUncasted<HInvokeFunction>(function, 2);
7875 } else { 7936 } else {
7876 switch (op) { 7937 switch (op) {
7877 case Token::ADD: 7938 case Token::ADD:
7878 if (is_string_add) { 7939 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; 7940 break;
7896 case Token::SUB: 7941 case Token::SUB:
7897 instr = NewUncasted<HSub>(left, right); 7942 instr = NewUncasted<HSub>(left, right);
7898 break; 7943 break;
7899 case Token::MUL: 7944 case Token::MUL:
7900 instr = NewUncasted<HMul>(left, right); 7945 instr = NewUncasted<HMul>(left, right);
7901 break; 7946 break;
7902 case Token::MOD: 7947 case Token::MOD:
7903 instr = NewUncasted<HMod>(left, right, fixed_right_arg); 7948 instr = NewUncasted<HMod>(left, right, fixed_right_arg);
7904 break; 7949 break;
(...skipping 1936 matching lines...) Expand 10 before | Expand all | Expand 10 after
9841 if (ShouldProduceTraceOutput()) { 9886 if (ShouldProduceTraceOutput()) {
9842 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 9887 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
9843 } 9888 }
9844 9889
9845 #ifdef DEBUG 9890 #ifdef DEBUG
9846 graph_->Verify(false); // No full verify. 9891 graph_->Verify(false); // No full verify.
9847 #endif 9892 #endif
9848 } 9893 }
9849 9894
9850 } } // namespace v8::internal 9895 } } // 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