Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1354 case MethodRecognizer::kByteArrayBaseGetFloat32x4: | 1354 case MethodRecognizer::kByteArrayBaseGetFloat32x4: |
| 1355 if (!ShouldInlineSimd()) return false; | 1355 if (!ShouldInlineSimd()) return false; |
| 1356 return InlineByteArrayViewLoad(call, receiver, receiver_cid, | 1356 return InlineByteArrayViewLoad(call, receiver, receiver_cid, |
| 1357 kTypedDataFloat32x4ArrayCid, | 1357 kTypedDataFloat32x4ArrayCid, |
| 1358 ic_data, entry, last); | 1358 ic_data, entry, last); |
| 1359 case MethodRecognizer::kByteArrayBaseGetInt32x4: | 1359 case MethodRecognizer::kByteArrayBaseGetInt32x4: |
| 1360 if (!ShouldInlineSimd()) return false; | 1360 if (!ShouldInlineSimd()) return false; |
| 1361 return InlineByteArrayViewLoad(call, receiver, receiver_cid, | 1361 return InlineByteArrayViewLoad(call, receiver, receiver_cid, |
| 1362 kTypedDataInt32x4ArrayCid, | 1362 kTypedDataInt32x4ArrayCid, |
| 1363 ic_data, entry, last); | 1363 ic_data, entry, last); |
| 1364 case MethodRecognizer::kStringBaseCodeUnitAt: | |
| 1365 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); | |
| 1366 case MethodRecognizer::kStringBaseCharAt: | |
| 1367 return InlineStringBaseCharAt(call, receiver_cid, entry, last); | |
| 1364 default: | 1368 default: |
| 1365 return false; | 1369 return false; |
| 1366 } | 1370 } |
| 1367 } | 1371 } |
| 1368 | 1372 |
| 1369 | 1373 |
| 1370 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, | 1374 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, |
| 1371 intptr_t array_cid, | 1375 intptr_t array_cid, |
| 1372 Definition** array, | 1376 Definition** array, |
| 1373 Definition* index, | 1377 Definition* index, |
| (...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2362 if (target.kind() != RawFunction::kImplicitGetter) { | 2366 if (target.kind() != RawFunction::kImplicitGetter) { |
| 2363 // Non-implicit getters are inlined like normal methods by conventional | 2367 // Non-implicit getters are inlined like normal methods by conventional |
| 2364 // inlining in FlowGraphInliner. | 2368 // inlining in FlowGraphInliner. |
| 2365 return false; | 2369 return false; |
| 2366 } | 2370 } |
| 2367 InlineImplicitInstanceGetter(call); | 2371 InlineImplicitInstanceGetter(call); |
| 2368 return true; | 2372 return true; |
| 2369 } | 2373 } |
| 2370 | 2374 |
| 2371 | 2375 |
| 2376 // Returns the LoadIndexedInstr. | |
| 2377 Definition* FlowGraphOptimizer::PrepareInlineStringIndexOp( | |
| 2378 Instruction* call, | |
| 2379 intptr_t cid, | |
| 2380 Definition* str, | |
| 2381 Definition* index, | |
| 2382 Instruction* cursor) { | |
| 2383 | |
| 2384 cursor = flow_graph()->AppendTo(cursor, | |
| 2385 new CheckSmiInstr(new Value(index), | |
| 2386 call->deopt_id()), | |
| 2387 call->env(), | |
| 2388 Definition::kEffect); | |
| 2389 | |
| 2390 // If both index and string are constants, then do a compile-time check. | |
| 2391 // TODO(srdjan): Remove once constant propagation handles bounds checks. | |
| 2392 bool skip_check = false; | |
|
Florian Schneider
2014/02/13 11:57:46
I'm pretty sure that constant propagation handles
| |
| 2393 if (str->IsConstant() && index->IsConstant()) { | |
| 2394 const String& constant_string = | |
| 2395 String::Cast(str->AsConstant()->value()); | |
| 2396 const Object& constant_index = index->AsConstant()->value(); | |
| 2397 skip_check = constant_index.IsSmi() && | |
| 2398 (Smi::Cast(constant_index).Value() < constant_string.Length()); | |
| 2399 } | |
| 2400 | |
| 2401 if (!skip_check) { | |
| 2402 // Load the length of the string. | |
| 2403 LoadFieldInstr* length = BuildLoadStringLength(str); | |
| 2404 cursor = flow_graph()->AppendTo(cursor, length, NULL, Definition::kValue); | |
| 2405 // Bounds check. | |
| 2406 cursor = flow_graph()->AppendTo(cursor, | |
| 2407 new CheckArrayBoundInstr(new Value(length), | |
| 2408 new Value(index), | |
| 2409 call->deopt_id()), | |
| 2410 call->env(), | |
| 2411 Definition::kEffect); | |
| 2412 } | |
| 2413 LoadIndexedInstr* load_indexed = new LoadIndexedInstr( | |
| 2414 new Value(str), | |
| 2415 new Value(index), | |
| 2416 FlowGraphCompiler::ElementSizeFor(cid), | |
| 2417 cid, | |
| 2418 Isolate::kNoDeoptId); | |
| 2419 | |
| 2420 cursor = flow_graph()->AppendTo(cursor, | |
| 2421 load_indexed, | |
| 2422 NULL, | |
| 2423 Definition::kValue); | |
| 2424 ASSERT(cursor == load_indexed); | |
| 2425 return load_indexed; | |
| 2426 } | |
| 2427 | |
| 2428 | |
| 2429 bool FlowGraphOptimizer::InlineStringCodeUnitAt( | |
| 2430 Instruction* call, | |
| 2431 intptr_t cid, | |
| 2432 TargetEntryInstr** entry, | |
| 2433 Definition** last) { | |
| 2434 | |
| 2435 Definition* str = call->ArgumentAt(0); | |
| 2436 Definition* index = call->ArgumentAt(1); | |
| 2437 | |
| 2438 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 2439 call->GetBlock()->try_index()); | |
| 2440 (*entry)->InheritDeoptTarget(call); | |
| 2441 | |
| 2442 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); | |
| 2443 | |
| 2444 return true; | |
| 2445 } | |
| 2446 | |
| 2447 | |
| 2448 bool FlowGraphOptimizer::InlineStringBaseCharAt( | |
| 2449 Instruction* call, | |
| 2450 intptr_t cid, | |
| 2451 TargetEntryInstr** entry, | |
| 2452 Definition** last) { | |
| 2453 | |
| 2454 Definition* str = call->ArgumentAt(0); | |
| 2455 Definition* index = call->ArgumentAt(1); | |
| 2456 | |
| 2457 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 2458 call->GetBlock()->try_index()); | |
| 2459 (*entry)->InheritDeoptTarget(call); | |
| 2460 | |
| 2461 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); | |
| 2462 | |
| 2463 StringFromCharCodeInstr* char_at = | |
| 2464 new StringFromCharCodeInstr(new Value(*last), cid); | |
| 2465 | |
| 2466 flow_graph()->AppendTo(*last, char_at, NULL, Definition::kValue); | |
| 2467 *last = char_at; | |
| 2468 | |
| 2469 return true; | |
| 2470 } | |
| 2471 | |
| 2472 | |
| 2372 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCodeUnitAt( | 2473 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCodeUnitAt( |
|
Florian Schneider
2014/02/13 11:57:46
I think you should be able to use your newly intro
| |
| 2373 InstanceCallInstr* call, | 2474 InstanceCallInstr* call, |
| 2374 intptr_t cid) { | 2475 intptr_t cid) { |
| 2375 Definition* str = call->ArgumentAt(0); | 2476 Definition* str = call->ArgumentAt(0); |
| 2376 Definition* index = call->ArgumentAt(1); | 2477 Definition* index = call->ArgumentAt(1); |
| 2377 AddReceiverCheck(call); | 2478 AddReceiverCheck(call); |
| 2378 InsertBefore(call, | 2479 InsertBefore(call, |
| 2379 new CheckSmiInstr(new Value(index), call->deopt_id()), | 2480 new CheckSmiInstr(new Value(index), call->deopt_id()), |
| 2380 call->env(), | 2481 call->env(), |
| 2381 Definition::kEffect); | 2482 Definition::kEffect); |
| 2382 // If both index and string are constants, then do a compile-time check. | 2483 // If both index and string are constants, then do a compile-time check. |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2492 } | 2593 } |
| 2493 | 2594 |
| 2494 if ((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) && | 2595 if ((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) && |
| 2495 (ic_data.NumberOfChecks() == 1) && | 2596 (ic_data.NumberOfChecks() == 1) && |
| 2496 ((class_ids[0] == kOneByteStringCid) || | 2597 ((class_ids[0] == kOneByteStringCid) || |
| 2497 (class_ids[0] == kTwoByteStringCid))) { | 2598 (class_ids[0] == kTwoByteStringCid))) { |
| 2498 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); | 2599 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); |
| 2499 ReplaceCall(call, instr); | 2600 ReplaceCall(call, instr); |
| 2500 return true; | 2601 return true; |
| 2501 } | 2602 } |
| 2502 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | 2603 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { |
|
Florian Schneider
2014/02/13 11:57:46
Here you should use the newly added builder functi
| |
| 2503 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { | 2604 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { |
| 2504 // TODO(fschneider): Handle TwoByteString. | 2605 // TODO(fschneider): Handle TwoByteString. |
| 2505 LoadIndexedInstr* load_char_code = | 2606 LoadIndexedInstr* load_char_code = |
| 2506 BuildStringCodeUnitAt(call, class_ids[0]); | 2607 BuildStringCodeUnitAt(call, class_ids[0]); |
| 2507 InsertBefore(call, load_char_code, NULL, Definition::kValue); | 2608 InsertBefore(call, load_char_code, NULL, Definition::kValue); |
| 2508 StringFromCharCodeInstr* char_at = | 2609 StringFromCharCodeInstr* char_at = |
| 2509 new StringFromCharCodeInstr(new Value(load_char_code), | 2610 new StringFromCharCodeInstr(new Value(load_char_code), |
| 2510 kOneByteStringCid); | 2611 kOneByteStringCid); |
| 2511 ReplaceCall(call, char_at); | 2612 ReplaceCall(call, char_at); |
| 2512 return true; | 2613 return true; |
| (...skipping 5983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8496 } | 8597 } |
| 8497 | 8598 |
| 8498 // Insert materializations at environment uses. | 8599 // Insert materializations at environment uses. |
| 8499 for (intptr_t i = 0; i < exits.length(); i++) { | 8600 for (intptr_t i = 0; i < exits.length(); i++) { |
| 8500 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8601 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 8501 } | 8602 } |
| 8502 } | 8603 } |
| 8503 | 8604 |
| 8504 | 8605 |
| 8505 } // namespace dart | 8606 } // namespace dart |
| OLD | NEW |