Chromium Code Reviews| 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 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 797 : last_true_block_; | 797 : last_true_block_; |
| 798 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) | 798 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) |
| 799 ? builder_->current_block() | 799 ? builder_->current_block() |
| 800 : first_false_block_; | 800 : first_false_block_; |
| 801 continuation->Capture(true_block, false_block, position_); | 801 continuation->Capture(true_block, false_block, position_); |
| 802 captured_ = true; | 802 captured_ = true; |
| 803 End(); | 803 End(); |
| 804 } | 804 } |
| 805 | 805 |
| 806 | 806 |
| 807 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { | |
| 808 ASSERT(!finished_); | |
| 809 ASSERT(!captured_); | |
| 810 HBasicBlock* true_block = last_true_block_ == NULL | |
| 811 ? first_true_block_ | |
| 812 : last_true_block_; | |
| 813 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) | |
| 814 ? builder_->current_block() | |
| 815 : first_false_block_; | |
| 816 if (true_block != NULL && !true_block->IsFinished()) { | |
| 817 ASSERT(continuation->IsTrueReachable()); | |
| 818 true_block->GotoNoSimulate(continuation->true_branch()); | |
| 819 } | |
| 820 if (false_block != NULL && !false_block->IsFinished()) { | |
| 821 ASSERT(continuation->IsFalseReachable()); | |
| 822 false_block->GotoNoSimulate(continuation->false_branch()); | |
| 823 } | |
| 824 captured_ = true; | |
| 825 End(); | |
| 826 } | |
| 827 | |
| 828 | |
| 807 void HGraphBuilder::IfBuilder::Then() { | 829 void HGraphBuilder::IfBuilder::Then() { |
| 808 ASSERT(!captured_); | 830 ASSERT(!captured_); |
| 809 ASSERT(!finished_); | 831 ASSERT(!finished_); |
| 810 did_then_ = true; | 832 did_then_ = true; |
| 811 if (needs_compare_) { | 833 if (needs_compare_) { |
| 812 // Handle if's without any expressions, they jump directly to the "else" | 834 // Handle if's without any expressions, they jump directly to the "else" |
| 813 // branch. However, we must pretend that the "then" branch is reachable, | 835 // branch. However, we must pretend that the "then" branch is reachable, |
| 814 // so that the graph builder visits it and sees any live range extending | 836 // so that the graph builder visits it and sees any live range extending |
| 815 // constructs within it. | 837 // constructs within it. |
| 816 HConstant* constant_false = builder_->graph()->GetConstantFalse(); | 838 HConstant* constant_false = builder_->graph()->GetConstantFalse(); |
| (...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1242 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1264 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
| 1243 array_length, elements_length); | 1265 array_length, elements_length); |
| 1244 | 1266 |
| 1245 if_builder.End(); | 1267 if_builder.End(); |
| 1246 } | 1268 } |
| 1247 | 1269 |
| 1248 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1270 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
| 1249 } | 1271 } |
| 1250 | 1272 |
| 1251 | 1273 |
| 1274 HValue* HGraphBuilder::BuildLookupNumberStringCache( | |
| 1275 HValue* object, | |
| 1276 HIfContinuation* continuation) { | |
| 1277 // Create a joinable continuation. | |
| 1278 HIfContinuation found(graph()->CreateBasicBlock(), | |
| 1279 graph()->CreateBasicBlock()); | |
| 1280 | |
| 1281 // Load the number string cache. | |
| 1282 HValue* number_string_cache = | |
| 1283 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); | |
| 1284 | |
| 1285 // Make the hash maks from the length of the number string cache. It | |
| 1286 // contains two elements (number and string) for each cache entry. | |
| 1287 HValue* mask = AddLoadFixedArrayLength(number_string_cache); | |
| 1288 mask->set_type(HType::Smi()); | |
| 1289 mask = Add<HSar>(mask, graph()->GetConstant1()); | |
| 1290 mask = Add<HSub>(mask, graph()->GetConstant1()); | |
| 1291 | |
| 1292 // Check whether object is a smi. | |
| 1293 IfBuilder if_objectissmi(this); | |
| 1294 if_objectissmi.If<HIsSmiAndBranch>(object); | |
| 1295 if_objectissmi.Then(); | |
| 1296 { | |
| 1297 // Compute hash for smi similar to smi_get_hash(). | |
| 1298 HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask); | |
| 1299 | |
| 1300 // Load the key. | |
| 1301 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); | |
| 1302 HValue* key = AddFastElementAccess(number_string_cache, key_index, | |
| 1303 NULL, NULL, FAST_ELEMENTS, false, | |
| 1304 ALLOW_RETURN_HOLE, STANDARD_STORE); | |
| 1305 | |
| 1306 // Check if object == key. | |
| 1307 IfBuilder if_objectiskey(this); | |
| 1308 if_objectiskey.If<HCompareObjectEqAndBranch>(key, object); | |
| 1309 if_objectiskey.Then(); | |
| 1310 { | |
| 1311 // Make the key_index available. | |
| 1312 Push(key_index); | |
| 1313 } | |
| 1314 if_objectiskey.JoinContinuation(&found); | |
| 1315 } | |
| 1316 if_objectissmi.Else(); | |
|
mvstanton
2013/09/23 09:32:34
All this is really nice that you can use the IfBui
| |
| 1317 { | |
| 1318 // Check if object is a heap number. | |
| 1319 IfBuilder if_objectisnumber(this); | |
| 1320 if_objectisnumber.If<HCompareMap>( | |
| 1321 object, isolate()->factory()->heap_number_map()); | |
| 1322 if_objectisnumber.Then(); | |
| 1323 { | |
| 1324 // Compute hash for heap number similar to double_get_hash(). | |
| 1325 HValue* low = Add<HLoadNamedField>( | |
| 1326 object, HObjectAccess::ForHeapNumberValueLowestBits()); | |
| 1327 HValue* high = Add<HLoadNamedField>( | |
| 1328 object, HObjectAccess::ForHeapNumberValueHighestBits()); | |
| 1329 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high); | |
| 1330 hash = Add<HBitwise>(Token::BIT_AND, hash, mask); | |
| 1331 | |
| 1332 // Load the key. | |
| 1333 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); | |
| 1334 HValue* key = AddFastElementAccess(number_string_cache, key_index, | |
| 1335 NULL, NULL, FAST_ELEMENTS, false, | |
| 1336 ALLOW_RETURN_HOLE, STANDARD_STORE); | |
| 1337 | |
| 1338 // Check if key is a heap number. | |
| 1339 IfBuilder if_keyisnumber(this); | |
| 1340 if_keyisnumber.IfNot<HIsSmiAndBranch>(key); | |
| 1341 if_keyisnumber.AndIf<HCompareMap>( | |
| 1342 key, isolate()->factory()->heap_number_map()); | |
| 1343 if_keyisnumber.Then(); | |
| 1344 { | |
| 1345 // Check if values of key and object match. | |
| 1346 IfBuilder if_keyeqobject(this); | |
| 1347 if_keyeqobject.If<HCompareNumericAndBranch>( | |
| 1348 Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()), | |
| 1349 Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()), | |
| 1350 Token::EQ); | |
| 1351 if_keyeqobject.Then(); | |
| 1352 { | |
| 1353 // Make the key_index available. | |
| 1354 Push(key_index); | |
| 1355 } | |
| 1356 if_keyeqobject.JoinContinuation(&found); | |
| 1357 } | |
| 1358 if_keyisnumber.JoinContinuation(&found); | |
| 1359 } | |
| 1360 if_objectisnumber.JoinContinuation(&found); | |
| 1361 } | |
| 1362 if_objectissmi.End(); | |
| 1363 | |
| 1364 // Check for cache hit. | |
| 1365 IfBuilder if_found(this, &found); | |
| 1366 if_found.Then(); | |
| 1367 | |
| 1368 // Load the value in case of cache hit. | |
| 1369 HValue* key_index = Pop(); | |
| 1370 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1()); | |
| 1371 HValue* value = AddFastElementAccess(number_string_cache, value_index, | |
| 1372 NULL, NULL, FAST_ELEMENTS, false, | |
| 1373 ALLOW_RETURN_HOLE, STANDARD_STORE); | |
| 1374 AddIncrementCounter(isolate()->counters()->number_to_string_native()); | |
| 1375 | |
| 1376 if_found.CaptureContinuation(continuation); | |
| 1377 | |
| 1378 // The value is only available in true branch of continuation. | |
| 1379 return value; | |
| 1380 } | |
| 1381 | |
| 1382 | |
| 1383 HValue* HGraphBuilder::BuildNumberToString(HValue* number) { | |
| 1384 NoObservableSideEffectsScope scope(this); | |
| 1385 | |
| 1386 // Lookup the number in the number string cache. | |
| 1387 HIfContinuation continuation; | |
| 1388 HValue* value = BuildLookupNumberStringCache(number, &continuation); | |
| 1389 IfBuilder if_found(this, &continuation); | |
| 1390 if_found.Then(); | |
| 1391 | |
| 1392 // Cache hit. | |
| 1393 Push(value); | |
| 1394 | |
| 1395 if_found.Else(); | |
| 1396 | |
| 1397 // Cache miss, fallback to runtime. | |
| 1398 Add<HPushArgument>(number); | |
| 1399 Push(Add<HCallRuntime>( | |
| 1400 isolate()->factory()->empty_string(), | |
| 1401 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | |
| 1402 1)); | |
| 1403 | |
| 1404 if_found.End(); | |
| 1405 | |
| 1406 return Pop(); | |
| 1407 } | |
| 1408 | |
| 1409 | |
| 1252 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 1410 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 1253 HValue* checked_object, | 1411 HValue* checked_object, |
| 1254 HValue* key, | 1412 HValue* key, |
| 1255 HValue* val, | 1413 HValue* val, |
| 1256 bool is_js_array, | 1414 bool is_js_array, |
| 1257 ElementsKind elements_kind, | 1415 ElementsKind elements_kind, |
| 1258 bool is_store, | 1416 bool is_store, |
| 1259 LoadKeyedHoleMode load_mode, | 1417 LoadKeyedHoleMode load_mode, |
| 1260 KeyedAccessStoreMode store_mode) { | 1418 KeyedAccessStoreMode store_mode) { |
| 1261 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); | 1419 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); |
| (...skipping 7599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8861 | 9019 |
| 8862 // Support for fast native caches. | 9020 // Support for fast native caches. |
| 8863 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { | 9021 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 8864 return Bailout(kInlinedRuntimeFunctionGetFromCache); | 9022 return Bailout(kInlinedRuntimeFunctionGetFromCache); |
| 8865 } | 9023 } |
| 8866 | 9024 |
| 8867 | 9025 |
| 8868 // Fast support for number to string. | 9026 // Fast support for number to string. |
| 8869 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { | 9027 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 8870 ASSERT_EQ(1, call->arguments()->length()); | 9028 ASSERT_EQ(1, call->arguments()->length()); |
| 8871 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 9029 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8872 HValue* context = environment()->context(); | 9030 return ast_context()->ReturnValue(BuildNumberToString(Pop())); |
|
mvstanton
2013/09/23 09:32:34
Paranoia: This code reminds me of the problem that
Benedikt Meurer
2013/09/23 10:53:31
Done.
| |
| 8873 HCallStub* result = | |
| 8874 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); | |
| 8875 Drop(1); | |
| 8876 return ast_context()->ReturnInstruction(result, call->id()); | |
| 8877 } | 9031 } |
| 8878 | 9032 |
| 8879 | 9033 |
| 8880 // Fast call for custom callbacks. | 9034 // Fast call for custom callbacks. |
| 8881 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { | 9035 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 8882 // 1 ~ The function to call is not itself an argument to the call. | 9036 // 1 ~ The function to call is not itself an argument to the call. |
| 8883 int arg_count = call->arguments()->length() - 1; | 9037 int arg_count = call->arguments()->length() - 1; |
| 8884 ASSERT(arg_count >= 1); // There's always at least a receiver. | 9038 ASSERT(arg_count >= 1); // There's always at least a receiver. |
| 8885 | 9039 |
| 8886 for (int i = 0; i < arg_count; ++i) { | 9040 for (int i = 0; i < arg_count; ++i) { |
| (...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9633 if (ShouldProduceTraceOutput()) { | 9787 if (ShouldProduceTraceOutput()) { |
| 9634 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9788 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9635 } | 9789 } |
| 9636 | 9790 |
| 9637 #ifdef DEBUG | 9791 #ifdef DEBUG |
| 9638 graph_->Verify(false); // No full verify. | 9792 graph_->Verify(false); // No full verify. |
| 9639 #endif | 9793 #endif |
| 9640 } | 9794 } |
| 9641 | 9795 |
| 9642 } } // namespace v8::internal | 9796 } } // namespace v8::internal |
| OLD | NEW |