OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |