| 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/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 // Generate runtime call. | 592 // Generate runtime call. |
| 593 // Load instantiator (R2) and its type arguments (R1). | 593 // Load instantiator (R2) and its type arguments (R1). |
| 594 __ ldm(IA, SP, (1 << R1) | (1 << R2)); | 594 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 595 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 595 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 596 __ Push(R0); // Push the instance. | 596 __ Push(R0); // Push the instance. |
| 597 __ PushObject(type); // Push the type. | 597 __ PushObject(type); // Push the type. |
| 598 // Push instantiator (R2) and its type arguments (R1). | 598 // Push instantiator (R2) and its type arguments (R1). |
| 599 __ PushList((1 << R1) | (1 << R2)); | 599 __ PushList((1 << R1) | (1 << R2)); |
| 600 __ LoadObject(R0, test_cache); | 600 __ LoadObject(R0, test_cache); |
| 601 __ Push(R0); | 601 __ Push(R0); |
| 602 GenerateCallRuntime(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); | 602 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
| 603 // Pop the parameters supplied to the runtime entry. The result of the | 603 // Pop the parameters supplied to the runtime entry. The result of the |
| 604 // instanceof runtime call will be left as the result of the operation. | 604 // instanceof runtime call will be left as the result of the operation. |
| 605 __ Drop(5); | 605 __ Drop(5); |
| 606 if (negate_result) { | 606 if (negate_result) { |
| 607 __ Pop(R1); | 607 __ Pop(R1); |
| 608 __ LoadObject(R0, Bool::True()); | 608 __ LoadObject(R0, Bool::True()); |
| 609 __ cmp(R1, ShifterOperand(R0)); | 609 __ cmp(R1, ShifterOperand(R0)); |
| 610 __ b(&done, NE); | 610 __ b(&done, NE); |
| 611 __ LoadObject(R0, Bool::False()); | 611 __ LoadObject(R0, Bool::False()); |
| 612 } else { | 612 } else { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 } else { | 671 } else { |
| 672 const bool is_malbounded = dst_type.IsMalboundedWithError(&error); | 672 const bool is_malbounded = dst_type.IsMalboundedWithError(&error); |
| 673 ASSERT(is_malbounded); | 673 ASSERT(is_malbounded); |
| 674 } | 674 } |
| 675 const String& error_message = String::ZoneHandle( | 675 const String& error_message = String::ZoneHandle( |
| 676 Symbols::New(error.ToErrorCString())); | 676 Symbols::New(error.ToErrorCString())); |
| 677 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 677 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 678 __ Push(R0); // Push the source object. | 678 __ Push(R0); // Push the source object. |
| 679 __ PushObject(dst_name); // Push the name of the destination. | 679 __ PushObject(dst_name); // Push the name of the destination. |
| 680 __ PushObject(error_message); | 680 __ PushObject(error_message); |
| 681 GenerateCallRuntime(token_pos, | 681 GenerateRuntimeCall(token_pos, |
| 682 deopt_id, | 682 deopt_id, |
| 683 kMalformedTypeErrorRuntimeEntry, | 683 kMalformedTypeErrorRuntimeEntry, |
| 684 3, | 684 3, |
| 685 locs); | 685 locs); |
| 686 // We should never return here. | 686 // We should never return here. |
| 687 __ bkpt(0); | 687 __ bkpt(0); |
| 688 | 688 |
| 689 __ Bind(&is_assignable); // For a null object. | 689 __ Bind(&is_assignable); // For a null object. |
| 690 // Restore instantiator (R2) and its type arguments (R1). | 690 // Restore instantiator (R2) and its type arguments (R1). |
| 691 __ PopList((1 << R1) | (1 << R2)); | 691 __ PopList((1 << R1) | (1 << R2)); |
| 692 return; | 692 return; |
| 693 } | 693 } |
| 694 | 694 |
| 695 // Generate inline type check, linking to runtime call if not assignable. | 695 // Generate inline type check, linking to runtime call if not assignable. |
| 696 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 696 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 697 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 697 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 698 &is_assignable, &runtime_call); | 698 &is_assignable, &runtime_call); |
| 699 | 699 |
| 700 __ Bind(&runtime_call); | 700 __ Bind(&runtime_call); |
| 701 // Load instantiator (R2) and its type arguments (R1). | 701 // Load instantiator (R2) and its type arguments (R1). |
| 702 __ ldm(IA, SP, (1 << R1) | (1 << R2)); | 702 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 703 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 703 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 704 __ Push(R0); // Push the source object. | 704 __ Push(R0); // Push the source object. |
| 705 __ PushObject(dst_type); // Push the type of the destination. | 705 __ PushObject(dst_type); // Push the type of the destination. |
| 706 // Push instantiator (R2) and its type arguments (R1). | 706 // Push instantiator (R2) and its type arguments (R1). |
| 707 __ PushList((1 << R1) | (1 << R2)); | 707 __ PushList((1 << R1) | (1 << R2)); |
| 708 __ PushObject(dst_name); // Push the name of the destination. | 708 __ PushObject(dst_name); // Push the name of the destination. |
| 709 __ LoadObject(R0, test_cache); | 709 __ LoadObject(R0, test_cache); |
| 710 __ Push(R0); | 710 __ Push(R0); |
| 711 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 711 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| 712 // Pop the parameters supplied to the runtime entry. The result of the | 712 // Pop the parameters supplied to the runtime entry. The result of the |
| 713 // type check runtime call is the checked value. | 713 // type check runtime call is the checked value. |
| 714 __ Drop(6); | 714 __ Drop(6); |
| 715 __ Pop(R0); | 715 __ Pop(R0); |
| 716 | 716 |
| 717 __ Bind(&is_assignable); | 717 __ Bind(&is_assignable); |
| 718 // Restore instantiator (R2) and its type arguments (R1). | 718 // Restore instantiator (R2) and its type arguments (R1). |
| 719 __ PopList((1 << R1) | (1 << R2)); | 719 __ PopList((1 << R1) | (1 << R2)); |
| 720 } | 720 } |
| 721 | 721 |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 if (is_optimizing()) { | 1221 if (is_optimizing()) { |
| 1222 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1222 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 1223 } else { | 1223 } else { |
| 1224 // Add deoptimization continuation point after the call and before the | 1224 // Add deoptimization continuation point after the call and before the |
| 1225 // arguments are removed. | 1225 // arguments are removed. |
| 1226 AddCurrentDescriptor(PcDescriptors::kDeopt, deopt_id_after, token_pos); | 1226 AddCurrentDescriptor(PcDescriptors::kDeopt, deopt_id_after, token_pos); |
| 1227 } | 1227 } |
| 1228 } | 1228 } |
| 1229 | 1229 |
| 1230 | 1230 |
| 1231 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, | 1231 void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos, |
| 1232 intptr_t deopt_id, | 1232 intptr_t deopt_id, |
| 1233 const RuntimeEntry& entry, | 1233 const RuntimeEntry& entry, |
| 1234 intptr_t argument_count, | 1234 intptr_t argument_count, |
| 1235 LocationSummary* locs) { | 1235 LocationSummary* locs) { |
| 1236 __ CallRuntime(entry, argument_count); | 1236 __ CallRuntime(entry, argument_count); |
| 1237 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | 1237 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); |
| 1238 RecordSafepoint(locs); | 1238 RecordSafepoint(locs); |
| 1239 if (deopt_id != Isolate::kNoDeoptId) { | 1239 if (deopt_id != Isolate::kNoDeoptId) { |
| 1240 // Marks either the continuation point in unoptimized code or the | 1240 // Marks either the continuation point in unoptimized code or the |
| 1241 // deoptimization point in optimized code, after call. | 1241 // deoptimization point in optimized code, after call. |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1488 token_pos); | 1488 token_pos); |
| 1489 // Stub returns result in flags (result of a cmpl, we need ZF computed). | 1489 // Stub returns result in flags (result of a cmpl, we need ZF computed). |
| 1490 __ Pop(right); | 1490 __ Pop(right); |
| 1491 __ Pop(left); | 1491 __ Pop(left); |
| 1492 } else { | 1492 } else { |
| 1493 __ cmp(left, ShifterOperand(right)); | 1493 __ cmp(left, ShifterOperand(right)); |
| 1494 } | 1494 } |
| 1495 } | 1495 } |
| 1496 | 1496 |
| 1497 | 1497 |
| 1498 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and |
| 1499 // FlowGraphCompiler::SlowPathEnvironmentFor. |
| 1498 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1500 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 1499 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1501 // TODO(vegorov): consider saving only caller save (volatile) registers. |
| 1500 const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count(); | 1502 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); |
| 1501 if (fpu_regs_count > 0) { | 1503 if (fpu_regs_count > 0) { |
| 1502 __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize)); | 1504 __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize)); |
| 1503 // Store fpu registers with the lowest register number at the lowest | 1505 // Store fpu registers with the lowest register number at the lowest |
| 1504 // address. | 1506 // address. |
| 1505 intptr_t offset = 0; | 1507 intptr_t offset = 0; |
| 1506 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { | 1508 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { |
| 1507 QRegister fpu_reg = static_cast<QRegister>(reg_idx); | 1509 QRegister fpu_reg = static_cast<QRegister>(reg_idx); |
| 1508 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { | 1510 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { |
| 1509 DRegister d1 = EvenDRegisterOf(fpu_reg); | 1511 DRegister d1 = EvenDRegisterOf(fpu_reg); |
| 1510 DRegister d2 = OddDRegisterOf(fpu_reg); | 1512 DRegister d2 = OddDRegisterOf(fpu_reg); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1529 | 1531 |
| 1530 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { | 1532 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { |
| 1531 // General purpose registers have the lowest register number at the | 1533 // General purpose registers have the lowest register number at the |
| 1532 // lowest address. | 1534 // lowest address. |
| 1533 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); | 1535 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); |
| 1534 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); | 1536 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); |
| 1535 if (cpu_registers != 0) { | 1537 if (cpu_registers != 0) { |
| 1536 __ PopList(cpu_registers); | 1538 __ PopList(cpu_registers); |
| 1537 } | 1539 } |
| 1538 | 1540 |
| 1539 const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count(); | 1541 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); |
| 1540 if (fpu_regs_count > 0) { | 1542 if (fpu_regs_count > 0) { |
| 1541 // Fpu registers have the lowest register number at the lowest address. | 1543 // Fpu registers have the lowest register number at the lowest address. |
| 1542 intptr_t offset = 0; | 1544 intptr_t offset = 0; |
| 1543 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { | 1545 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { |
| 1544 QRegister fpu_reg = static_cast<QRegister>(reg_idx); | 1546 QRegister fpu_reg = static_cast<QRegister>(reg_idx); |
| 1545 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { | 1547 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { |
| 1546 DRegister d1 = EvenDRegisterOf(fpu_reg); | 1548 DRegister d1 = EvenDRegisterOf(fpu_reg); |
| 1547 DRegister d2 = OddDRegisterOf(fpu_reg); | 1549 DRegister d2 = OddDRegisterOf(fpu_reg); |
| 1548 // TOOD(regis): merge loads using vldmd instruction. | 1550 // TOOD(regis): merge loads using vldmd instruction. |
| 1549 __ vldrd(d1, Address(SP, offset)); | 1551 __ vldrd(d1, Address(SP, offset)); |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1911 DRegister dreg = EvenDRegisterOf(reg); | 1913 DRegister dreg = EvenDRegisterOf(reg); |
| 1912 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1914 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1913 } | 1915 } |
| 1914 | 1916 |
| 1915 | 1917 |
| 1916 #undef __ | 1918 #undef __ |
| 1917 | 1919 |
| 1918 } // namespace dart | 1920 } // namespace dart |
| 1919 | 1921 |
| 1920 #endif // defined TARGET_ARCH_ARM | 1922 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |