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 1385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1396 case MethodRecognizer::kByteArrayBaseSetFloat32x4: | 1396 case MethodRecognizer::kByteArrayBaseSetFloat32x4: |
| 1397 if (!ShouldInlineSimd()) return false; | 1397 if (!ShouldInlineSimd()) return false; |
| 1398 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, | 1398 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1399 kTypedDataFloat32x4ArrayCid, | 1399 kTypedDataFloat32x4ArrayCid, |
| 1400 ic_data, entry, last); | 1400 ic_data, entry, last); |
| 1401 case MethodRecognizer::kByteArrayBaseSetInt32x4: | 1401 case MethodRecognizer::kByteArrayBaseSetInt32x4: |
| 1402 if (!ShouldInlineSimd()) return false; | 1402 if (!ShouldInlineSimd()) return false; |
| 1403 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, | 1403 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1404 kTypedDataInt32x4ArrayCid, | 1404 kTypedDataInt32x4ArrayCid, |
| 1405 ic_data, entry, last); | 1405 ic_data, entry, last); |
| 1406 case MethodRecognizer::kStringBaseCodeUnitAt: | |
| 1407 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); | |
| 1408 case MethodRecognizer::kStringBaseCharAt: | |
| 1409 return InlineStringBaseCharAt(call, receiver_cid, entry, last); | |
| 1406 default: | 1410 default: |
| 1407 return false; | 1411 return false; |
| 1408 } | 1412 } |
| 1409 } | 1413 } |
| 1410 | 1414 |
| 1411 | 1415 |
| 1412 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, | 1416 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, |
| 1413 intptr_t array_cid, | 1417 intptr_t array_cid, |
| 1414 Definition** array, | 1418 Definition** array, |
| 1415 Definition* index, | 1419 Definition* index, |
| (...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2404 if (target.kind() != RawFunction::kImplicitGetter) { | 2408 if (target.kind() != RawFunction::kImplicitGetter) { |
| 2405 // Non-implicit getters are inlined like normal methods by conventional | 2409 // Non-implicit getters are inlined like normal methods by conventional |
| 2406 // inlining in FlowGraphInliner. | 2410 // inlining in FlowGraphInliner. |
| 2407 return false; | 2411 return false; |
| 2408 } | 2412 } |
| 2409 InlineImplicitInstanceGetter(call); | 2413 InlineImplicitInstanceGetter(call); |
| 2410 return true; | 2414 return true; |
| 2411 } | 2415 } |
| 2412 | 2416 |
| 2413 | 2417 |
| 2414 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCodeUnitAt( | 2418 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( |
| 2415 InstanceCallInstr* call, | 2419 InstanceCallInstr* call) { |
| 2416 intptr_t cid) { | 2420 ASSERT(call->HasICData()); |
| 2417 Definition* str = call->ArgumentAt(0); | 2421 Function& target = Function::Handle(); |
| 2418 Definition* index = call->ArgumentAt(1); | 2422 GrowableArray<intptr_t> class_ids; |
| 2423 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 2424 const intptr_t receiver_cid = class_ids[0]; | |
| 2425 | |
| 2426 TargetEntryInstr* entry; | |
| 2427 Definition* last; | |
| 2428 if (!TryInlineRecognizedMethod(receiver_cid, | |
| 2429 target, | |
| 2430 call, | |
| 2431 call->ArgumentAt(0), | |
| 2432 call->token_pos(), | |
| 2433 *call->ic_data(), | |
| 2434 &entry, &last)) { | |
| 2435 return false; | |
| 2436 } | |
| 2437 | |
| 2438 // Insert receiver class check. | |
| 2419 AddReceiverCheck(call); | 2439 AddReceiverCheck(call); |
| 2420 InsertBefore(call, | 2440 // Remove the original push arguments. |
| 2421 new CheckSmiInstr(new Value(index), call->deopt_id()), | 2441 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2422 call->env(), | 2442 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2423 Definition::kEffect); | 2443 push->ReplaceUsesWith(push->value()->definition()); |
| 2424 // If both index and string are constants, then do a compile-time check. | 2444 push->RemoveFromGraph(); |
| 2425 // TODO(srdjan): Remove once constant propagation handles bounds checks. | |
| 2426 bool skip_check = false; | |
| 2427 if (str->IsConstant() && index->IsConstant()) { | |
| 2428 const String& constant_string = | |
| 2429 String::Cast(str->AsConstant()->value()); | |
| 2430 const Object& constant_index = index->AsConstant()->value(); | |
| 2431 skip_check = constant_index.IsSmi() && | |
| 2432 (Smi::Cast(constant_index).Value() < constant_string.Length()); | |
| 2433 } | 2445 } |
| 2434 if (!skip_check) { | 2446 // Replace all uses of this definition with the result. |
| 2435 // Insert bounds check. | 2447 call->ReplaceUsesWith(last); |
| 2436 LoadFieldInstr* length = BuildLoadStringLength(str); | 2448 // Finally insert the sequence other definition in place of this one in the |
| 2437 InsertBefore(call, length, NULL, Definition::kValue); | 2449 // graph. |
| 2438 InsertBefore(call, | 2450 call->previous()->LinkTo(entry->next()); |
| 2439 new CheckArrayBoundInstr(new Value(length), | 2451 entry->UnuseAllInputs(); // Entry block is not in the graph. |
| 2440 new Value(index), | 2452 last->LinkTo(call); |
| 2441 call->deopt_id()), | 2453 // Remove through the iterator. |
| 2442 call->env(), | 2454 ASSERT(current_iterator()->Current() == call); |
| 2443 Definition::kEffect); | 2455 current_iterator()->RemoveCurrentFromGraph(); |
| 2444 } | 2456 call->set_previous(NULL); |
| 2445 return new LoadIndexedInstr(new Value(str), | 2457 call->set_next(NULL); |
| 2446 new Value(index), | 2458 return true; |
| 2447 FlowGraphCompiler::ElementSizeFor(cid), | |
| 2448 cid, | |
| 2449 Isolate::kNoDeoptId); // Can't deoptimize. | |
| 2450 } | 2459 } |
| 2451 | 2460 |
| 2452 | 2461 |
| 2462 // Returns the LoadIndexedInstr. | |
| 2463 Definition* FlowGraphOptimizer::PrepareInlineStringIndexOp( | |
| 2464 Instruction* call, | |
| 2465 intptr_t cid, | |
| 2466 Definition* str, | |
| 2467 Definition* index, | |
| 2468 Instruction* cursor) { | |
| 2469 | |
| 2470 cursor = flow_graph()->AppendTo(cursor, | |
| 2471 new CheckSmiInstr(new Value(index), | |
| 2472 call->deopt_id()), | |
| 2473 call->env(), | |
| 2474 Definition::kEffect); | |
| 2475 | |
| 2476 // Load the length of the string. | |
| 2477 LoadFieldInstr* length = BuildLoadStringLength(str); | |
| 2478 cursor = flow_graph()->AppendTo(cursor, length, NULL, Definition::kValue); | |
| 2479 // Bounds check. | |
| 2480 cursor = flow_graph()->AppendTo(cursor, | |
| 2481 new CheckArrayBoundInstr(new Value(length), | |
| 2482 new Value(index), | |
| 2483 call->deopt_id()), | |
| 2484 call->env(), | |
| 2485 Definition::kEffect); | |
| 2486 | |
| 2487 LoadIndexedInstr* load_indexed = new LoadIndexedInstr( | |
| 2488 new Value(str), | |
| 2489 new Value(index), | |
| 2490 FlowGraphCompiler::ElementSizeFor(cid), | |
| 2491 cid, | |
| 2492 Isolate::kNoDeoptId); | |
| 2493 | |
| 2494 cursor = flow_graph()->AppendTo(cursor, | |
| 2495 load_indexed, | |
| 2496 NULL, | |
| 2497 Definition::kValue); | |
| 2498 ASSERT(cursor == load_indexed); | |
| 2499 return load_indexed; | |
| 2500 } | |
| 2501 | |
| 2502 | |
| 2503 bool FlowGraphOptimizer::InlineStringCodeUnitAt( | |
| 2504 Instruction* call, | |
| 2505 intptr_t cid, | |
| 2506 TargetEntryInstr** entry, | |
| 2507 Definition** last) { | |
| 2508 if (RawObject::IsExternalStringClassId(cid)) { | |
|
Florian Schneider
2014/02/17 11:56:12
Add a TODO for handling external strings in the sa
Cutch
2014/02/18 17:00:30
Done.
| |
| 2509 return false; | |
| 2510 } | |
| 2511 | |
| 2512 Definition* str = call->ArgumentAt(0); | |
| 2513 Definition* index = call->ArgumentAt(1); | |
| 2514 | |
| 2515 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 2516 call->GetBlock()->try_index()); | |
| 2517 (*entry)->InheritDeoptTarget(call); | |
| 2518 | |
| 2519 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); | |
| 2520 | |
| 2521 return true; | |
| 2522 } | |
| 2523 | |
| 2524 | |
| 2525 bool FlowGraphOptimizer::InlineStringBaseCharAt( | |
| 2526 Instruction* call, | |
| 2527 intptr_t cid, | |
| 2528 TargetEntryInstr** entry, | |
| 2529 Definition** last) { | |
| 2530 if (RawObject::IsExternalStringClassId(cid) || cid != kOneByteStringCid) { | |
|
Florian Schneider
2014/02/17 11:56:12
Add a TODO for handling external strings in the sa
Cutch
2014/02/18 17:00:30
Done.
| |
| 2531 return false; | |
| 2532 } | |
| 2533 Definition* str = call->ArgumentAt(0); | |
| 2534 Definition* index = call->ArgumentAt(1); | |
| 2535 | |
| 2536 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 2537 call->GetBlock()->try_index()); | |
| 2538 (*entry)->InheritDeoptTarget(call); | |
| 2539 | |
| 2540 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); | |
| 2541 | |
| 2542 StringFromCharCodeInstr* char_at = | |
| 2543 new StringFromCharCodeInstr(new Value(*last), cid); | |
| 2544 | |
| 2545 flow_graph()->AppendTo(*last, char_at, NULL, Definition::kValue); | |
| 2546 *last = char_at; | |
| 2547 | |
| 2548 return true; | |
| 2549 } | |
| 2550 | |
| 2551 | |
| 2453 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 2552 void FlowGraphOptimizer::ReplaceWithMathCFunction( |
| 2454 InstanceCallInstr* call, | 2553 InstanceCallInstr* call, |
| 2455 MethodRecognizer::Kind recognized_kind) { | 2554 MethodRecognizer::Kind recognized_kind) { |
| 2456 AddReceiverCheck(call); | 2555 AddReceiverCheck(call); |
| 2457 ZoneGrowableArray<Value*>* args = | 2556 ZoneGrowableArray<Value*>* args = |
| 2458 new ZoneGrowableArray<Value*>(call->ArgumentCount()); | 2557 new ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 2459 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 2558 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 2460 args->Add(new Value(call->ArgumentAt(i))); | 2559 args->Add(new Value(call->ArgumentAt(i))); |
| 2461 } | 2560 } |
| 2462 InvokeMathCFunctionInstr* invoke = | 2561 InvokeMathCFunctionInstr* invoke = |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2526 Definition* value = call->ArgumentAt(1); | 2625 Definition* value = call->ArgumentAt(1); |
| 2527 StoreVMFieldInstr* store = new StoreVMFieldInstr( | 2626 StoreVMFieldInstr* store = new StoreVMFieldInstr( |
| 2528 new Value(array), | 2627 new Value(array), |
| 2529 GrowableObjectArray::length_offset(), | 2628 GrowableObjectArray::length_offset(), |
| 2530 new Value(value), | 2629 new Value(value), |
| 2531 Type::ZoneHandle()); | 2630 Type::ZoneHandle()); |
| 2532 ReplaceCall(call, store); | 2631 ReplaceCall(call, store); |
| 2533 return true; | 2632 return true; |
| 2534 } | 2633 } |
| 2535 | 2634 |
| 2536 if ((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) && | 2635 if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) || |
| 2636 (recognized_kind == MethodRecognizer::kStringBaseCharAt)) && | |
| 2537 (ic_data.NumberOfChecks() == 1) && | 2637 (ic_data.NumberOfChecks() == 1) && |
| 2538 ((class_ids[0] == kOneByteStringCid) || | 2638 ((class_ids[0] == kOneByteStringCid) || |
| 2539 (class_ids[0] == kTwoByteStringCid))) { | 2639 (class_ids[0] == kTwoByteStringCid))) { |
| 2540 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); | 2640 return TryReplaceInstanceCallWithInline(call); |
| 2541 ReplaceCall(call, instr); | |
| 2542 return true; | |
| 2543 } | 2641 } |
| 2642 | |
| 2544 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | 2643 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { |
| 2545 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { | |
| 2546 // TODO(fschneider): Handle TwoByteString. | |
| 2547 LoadIndexedInstr* load_char_code = | |
| 2548 BuildStringCodeUnitAt(call, class_ids[0]); | |
| 2549 InsertBefore(call, load_char_code, NULL, Definition::kValue); | |
| 2550 StringFromCharCodeInstr* char_at = | |
| 2551 new StringFromCharCodeInstr(new Value(load_char_code), | |
| 2552 kOneByteStringCid); | |
| 2553 ReplaceCall(call, char_at); | |
| 2554 return true; | |
| 2555 } | |
| 2556 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | 2644 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { |
| 2557 // This is an internal method, no need to check argument types nor | 2645 // This is an internal method, no need to check argument types nor |
| 2558 // range. | 2646 // range. |
| 2559 Definition* str = call->ArgumentAt(0); | 2647 Definition* str = call->ArgumentAt(0); |
| 2560 Definition* index = call->ArgumentAt(1); | 2648 Definition* index = call->ArgumentAt(1); |
| 2561 Definition* value = call->ArgumentAt(2); | 2649 Definition* value = call->ArgumentAt(2); |
| 2562 StoreIndexedInstr* store_op = new StoreIndexedInstr( | 2650 StoreIndexedInstr* store_op = new StoreIndexedInstr( |
| 2563 new Value(str), | 2651 new Value(str), |
| 2564 new Value(index), | 2652 new Value(index), |
| 2565 new Value(value), | 2653 new Value(value), |
| (...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3289 } | 3377 } |
| 3290 | 3378 |
| 3291 | 3379 |
| 3292 bool FlowGraphOptimizer::BuildByteArrayViewLoad(InstanceCallInstr* call, | 3380 bool FlowGraphOptimizer::BuildByteArrayViewLoad(InstanceCallInstr* call, |
| 3293 intptr_t view_cid) { | 3381 intptr_t view_cid) { |
| 3294 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || | 3382 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || |
| 3295 (view_cid == kTypedDataInt32x4ArrayCid); | 3383 (view_cid == kTypedDataInt32x4ArrayCid); |
| 3296 if (simd_view && !ShouldInlineSimd()) { | 3384 if (simd_view && !ShouldInlineSimd()) { |
| 3297 return false; | 3385 return false; |
| 3298 } | 3386 } |
| 3299 | 3387 return TryReplaceInstanceCallWithInline(call); |
| 3300 ASSERT(call->HasICData()); | |
| 3301 Function& target = Function::Handle(); | |
| 3302 GrowableArray<intptr_t> class_ids; | |
| 3303 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 3304 const intptr_t receiver_cid = class_ids[0]; | |
| 3305 | |
| 3306 TargetEntryInstr* entry; | |
| 3307 Definition* last; | |
| 3308 if (!TryInlineRecognizedMethod(receiver_cid, | |
| 3309 target, | |
| 3310 call, | |
| 3311 call->ArgumentAt(0), | |
| 3312 call->token_pos(), | |
| 3313 *call->ic_data(), | |
| 3314 &entry, &last)) { | |
| 3315 return false; | |
| 3316 } | |
| 3317 | |
| 3318 // Insert receiver class check. | |
| 3319 AddReceiverCheck(call); | |
| 3320 // Remove the original push arguments. | |
| 3321 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 3322 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 3323 push->ReplaceUsesWith(push->value()->definition()); | |
| 3324 push->RemoveFromGraph(); | |
| 3325 } | |
| 3326 // Replace all uses of this definition with the result. | |
| 3327 call->ReplaceUsesWith(last); | |
| 3328 // Finally insert the sequence other definition in place of this one in the | |
| 3329 // graph. | |
| 3330 call->previous()->LinkTo(entry->next()); | |
| 3331 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 3332 last->LinkTo(call); | |
| 3333 // Remove through the iterator. | |
| 3334 ASSERT(current_iterator()->Current() == call); | |
| 3335 current_iterator()->RemoveCurrentFromGraph(); | |
| 3336 call->set_previous(NULL); | |
| 3337 call->set_next(NULL); | |
| 3338 return true; | |
| 3339 } | 3388 } |
| 3340 | 3389 |
| 3341 | 3390 |
| 3342 bool FlowGraphOptimizer::BuildByteArrayViewStore(InstanceCallInstr* call, | 3391 bool FlowGraphOptimizer::BuildByteArrayViewStore(InstanceCallInstr* call, |
| 3343 intptr_t view_cid) { | 3392 intptr_t view_cid) { |
| 3344 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || | 3393 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || |
| 3345 (view_cid == kTypedDataInt32x4ArrayCid); | 3394 (view_cid == kTypedDataInt32x4ArrayCid); |
| 3346 if (simd_view && !ShouldInlineSimd()) { | 3395 if (simd_view && !ShouldInlineSimd()) { |
| 3347 return false; | 3396 return false; |
| 3348 } | 3397 } |
| 3349 ASSERT(call->HasICData()); | 3398 return TryReplaceInstanceCallWithInline(call); |
| 3350 Function& target = Function::Handle(); | |
| 3351 GrowableArray<intptr_t> class_ids; | |
| 3352 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 3353 const intptr_t receiver_cid = class_ids[0]; | |
| 3354 | |
| 3355 TargetEntryInstr* entry; | |
| 3356 Definition* last; | |
| 3357 if (!TryInlineRecognizedMethod(receiver_cid, | |
| 3358 target, | |
| 3359 call, | |
| 3360 call->ArgumentAt(0), | |
| 3361 call->token_pos(), | |
| 3362 *call->ic_data(), | |
| 3363 &entry, &last)) { | |
| 3364 return false; | |
| 3365 } | |
| 3366 | |
| 3367 // Insert receiver class check. | |
| 3368 AddReceiverCheck(call); | |
| 3369 // Remove the original push arguments. | |
| 3370 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 3371 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 3372 push->ReplaceUsesWith(push->value()->definition()); | |
| 3373 push->RemoveFromGraph(); | |
| 3374 } | |
| 3375 // Replace all uses of this definition with the result. | |
| 3376 call->ReplaceUsesWith(last); | |
| 3377 // Finally insert the sequence other definition in place of this one in the | |
| 3378 // graph. | |
| 3379 call->previous()->LinkTo(entry->next()); | |
| 3380 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 3381 last->LinkTo(call); | |
| 3382 // Remove through the iterator. | |
| 3383 ASSERT(current_iterator()->Current() == call); | |
| 3384 current_iterator()->RemoveCurrentFromGraph(); | |
| 3385 call->set_previous(NULL); | |
| 3386 call->set_next(NULL); | |
| 3387 return true; | |
| 3388 } | 3399 } |
| 3389 | 3400 |
| 3390 | 3401 |
| 3391 void FlowGraphOptimizer::PrepareByteArrayViewOp( | |
| 3392 InstanceCallInstr* call, | |
| 3393 intptr_t receiver_cid, | |
| 3394 intptr_t view_cid, | |
| 3395 Definition** array) { | |
| 3396 Definition* byte_index = call->ArgumentAt(1); | |
| 3397 | |
| 3398 AddReceiverCheck(call); | |
| 3399 const bool is_immutable = true; | |
| 3400 LoadFieldInstr* length = new LoadFieldInstr( | |
| 3401 new Value(*array), | |
| 3402 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), | |
| 3403 Type::ZoneHandle(Type::SmiType()), | |
| 3404 is_immutable); | |
| 3405 length->set_result_cid(kSmiCid); | |
| 3406 length->set_recognized_kind( | |
| 3407 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | |
| 3408 InsertBefore(call, length, NULL, Definition::kValue); | |
| 3409 | |
| 3410 // len_in_bytes = length * kBytesPerElement(receiver) | |
| 3411 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | |
| 3412 ConstantInstr* bytes_per_element = | |
| 3413 flow_graph()->GetConstant(Smi::Handle(Smi::New(element_size))); | |
| 3414 BinarySmiOpInstr* len_in_bytes = | |
| 3415 new BinarySmiOpInstr(Token::kMUL, | |
| 3416 new Value(length), | |
| 3417 new Value(bytes_per_element), | |
| 3418 call->deopt_id()); | |
| 3419 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | |
| 3420 | |
| 3421 ConstantInstr* length_adjustment = | |
| 3422 flow_graph()->GetConstant(Smi::Handle(Smi::New( | |
| 3423 FlowGraphCompiler::ElementSizeFor(view_cid) - 1))); | |
| 3424 // adjusted_length = len_in_bytes - (element_size - 1). | |
| 3425 BinarySmiOpInstr* adjusted_length = | |
| 3426 new BinarySmiOpInstr(Token::kSUB, | |
| 3427 new Value(len_in_bytes), | |
| 3428 new Value(length_adjustment), | |
| 3429 call->deopt_id()); | |
| 3430 InsertBefore(call, adjusted_length, call->env(), Definition::kValue); | |
| 3431 // Check adjusted_length > 0. | |
| 3432 ConstantInstr* zero = flow_graph()->GetConstant(Smi::Handle(Smi::New(0))); | |
| 3433 InsertBefore(call, | |
| 3434 new CheckArrayBoundInstr(new Value(adjusted_length), | |
| 3435 new Value(zero), | |
| 3436 call->deopt_id()), | |
| 3437 call->env(), | |
| 3438 Definition::kEffect); | |
| 3439 // Check 0 <= byte_index < adjusted_length. | |
| 3440 InsertBefore(call, | |
| 3441 new CheckArrayBoundInstr(new Value(adjusted_length), | |
| 3442 new Value(byte_index), | |
| 3443 call->deopt_id()), | |
| 3444 call->env(), | |
| 3445 Definition::kEffect); | |
| 3446 | |
| 3447 // Insert load of elements for external typed arrays. | |
| 3448 if (RawObject::IsExternalTypedDataClassId(receiver_cid)) { | |
| 3449 LoadUntaggedInstr* elements = | |
| 3450 new LoadUntaggedInstr(new Value(*array), | |
| 3451 ExternalTypedData::data_offset()); | |
| 3452 InsertBefore(call, elements, NULL, Definition::kValue); | |
| 3453 *array = elements; | |
| 3454 } | |
| 3455 } | |
| 3456 | |
| 3457 | |
| 3458 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 3402 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 3459 // result and the type tests do not depend on type arguments. Otherwise return | 3403 // result and the type tests do not depend on type arguments. Otherwise return |
| 3460 // Bool::null(). | 3404 // Bool::null(). |
| 3461 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 3405 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 3462 const AbstractType& type) const { | 3406 const AbstractType& type) const { |
| 3463 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 3407 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 3464 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 3408 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
| 3465 return Bool::null(); | 3409 return Bool::null(); |
| 3466 } | 3410 } |
| 3467 const Class& type_class = Class::Handle(type.type_class()); | 3411 const Class& type_class = Class::Handle(type.type_class()); |
| (...skipping 5142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8610 } | 8554 } |
| 8611 | 8555 |
| 8612 // Insert materializations at environment uses. | 8556 // Insert materializations at environment uses. |
| 8613 for (intptr_t i = 0; i < exits.length(); i++) { | 8557 for (intptr_t i = 0; i < exits.length(); i++) { |
| 8614 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8558 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 8615 } | 8559 } |
| 8616 } | 8560 } |
| 8617 | 8561 |
| 8618 | 8562 |
| 8619 } // namespace dart | 8563 } // namespace dart |
| OLD | NEW |