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