OLD | NEW |
1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
2 // All Rights Reserved. | 2 // All Rights Reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
6 // are met: | 6 // are met: |
7 // | 7 // |
8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
10 // | 10 // |
(...skipping 21 matching lines...) Expand all Loading... |
32 | 32 |
33 // The original source code covered by the above license above has been | 33 // The original source code covered by the above license above has been |
34 // modified significantly by Google Inc. | 34 // modified significantly by Google Inc. |
35 // Copyright 2012 the V8 project authors. All rights reserved. | 35 // Copyright 2012 the V8 project authors. All rights reserved. |
36 | 36 |
37 #include "v8.h" | 37 #include "v8.h" |
38 | 38 |
39 #if V8_TARGET_ARCH_ARM | 39 #if V8_TARGET_ARCH_ARM |
40 | 40 |
41 #include "arm/assembler-arm-inl.h" | 41 #include "arm/assembler-arm-inl.h" |
| 42 #include "macro-assembler.h" |
42 #include "serialize.h" | 43 #include "serialize.h" |
43 | 44 |
44 namespace v8 { | 45 namespace v8 { |
45 namespace internal { | 46 namespace internal { |
46 | 47 |
47 #ifdef DEBUG | 48 #ifdef DEBUG |
48 bool CpuFeatures::initialized_ = false; | 49 bool CpuFeatures::initialized_ = false; |
49 #endif | 50 #endif |
50 unsigned CpuFeatures::supported_ = 0; | 51 unsigned CpuFeatures::supported_ = 0; |
51 unsigned CpuFeatures::found_by_runtime_probing_only_ = 0; | 52 unsigned CpuFeatures::found_by_runtime_probing_only_ = 0; |
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 // The linked labels form a link chain by making the branch offset | 772 // The linked labels form a link chain by making the branch offset |
772 // in the instruction steam to point to the previous branch | 773 // in the instruction steam to point to the previous branch |
773 // instruction using the same label. | 774 // instruction using the same label. |
774 // | 775 // |
775 // The link chain is terminated by a branch offset pointing to the | 776 // The link chain is terminated by a branch offset pointing to the |
776 // same position. | 777 // same position. |
777 | 778 |
778 | 779 |
779 int Assembler::target_at(int pos) { | 780 int Assembler::target_at(int pos) { |
780 Instr instr = instr_at(pos); | 781 Instr instr = instr_at(pos); |
781 if ((instr & ~kImm24Mask) == 0) { | 782 if (is_uint24(instr)) { |
782 // Emitted label constant, not part of a branch. | 783 // Emitted link to a label, not part of a branch. |
783 return instr - (Code::kHeaderSize - kHeapObjectTag); | 784 return instr; |
784 } | 785 } |
785 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 | 786 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 |
786 int imm26 = ((instr & kImm24Mask) << 8) >> 6; | 787 int imm26 = ((instr & kImm24Mask) << 8) >> 6; |
787 if ((Instruction::ConditionField(instr) == kSpecialCondition) && | 788 if ((Instruction::ConditionField(instr) == kSpecialCondition) && |
788 ((instr & B24) != 0)) { | 789 ((instr & B24) != 0)) { |
789 // blx uses bit 24 to encode bit 2 of imm26 | 790 // blx uses bit 24 to encode bit 2 of imm26 |
790 imm26 += 2; | 791 imm26 += 2; |
791 } | 792 } |
792 return pos + kPcLoadDelta + imm26; | 793 return pos + kPcLoadDelta + imm26; |
793 } | 794 } |
794 | 795 |
795 | 796 |
796 void Assembler::target_at_put(int pos, int target_pos) { | 797 void Assembler::target_at_put(int pos, int target_pos) { |
797 Instr instr = instr_at(pos); | 798 Instr instr = instr_at(pos); |
798 if ((instr & ~kImm24Mask) == 0) { | 799 if (is_uint24(instr)) { |
799 ASSERT(target_pos == pos || target_pos >= 0); | 800 ASSERT(target_pos == pos || target_pos >= 0); |
800 // Emitted label constant, not part of a branch. | 801 // Emitted link to a label, not part of a branch. |
801 // Make label relative to Code* of generated Code object. | 802 // Load the position of the label relative to the generated code object |
802 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); | 803 // pointer in a register. |
| 804 |
| 805 // Here are the instructions we need to emit: |
| 806 // For ARMv7: target24 => target16_1:target16_0 |
| 807 // movw dst, #target16_0 |
| 808 // movt dst, #target16_1 |
| 809 // For ARMv6: target24 => target8_2:target8_1:target8_0 |
| 810 // mov dst, #target8_0 |
| 811 // orr dst, dst, #target8_1 << 8 |
| 812 // orr dst, dst, #target8_2 << 16 |
| 813 |
| 814 // We extract the destination register from the emitted nop instruction. |
| 815 Register dst = Register::from_code( |
| 816 Instruction::RmValue(instr_at(pos + kInstrSize))); |
| 817 ASSERT(IsNop(instr_at(pos + kInstrSize), dst.code())); |
| 818 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag); |
| 819 ASSERT(is_uint24(target24)); |
| 820 if (is_uint8(target24)) { |
| 821 // If the target fits in a byte then only patch with a mov |
| 822 // instruction. |
| 823 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
| 824 1, |
| 825 CodePatcher::DONT_FLUSH); |
| 826 patcher.masm()->mov(dst, Operand(target24)); |
| 827 } else { |
| 828 uint16_t target16_0 = target24 & kImm16Mask; |
| 829 uint16_t target16_1 = target24 >> 16; |
| 830 if (CpuFeatures::IsSupported(ARMv7)) { |
| 831 // Patch with movw/movt. |
| 832 if (target16_1 == 0) { |
| 833 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
| 834 1, |
| 835 CodePatcher::DONT_FLUSH); |
| 836 patcher.masm()->movw(dst, target16_0); |
| 837 } else { |
| 838 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
| 839 2, |
| 840 CodePatcher::DONT_FLUSH); |
| 841 patcher.masm()->movw(dst, target16_0); |
| 842 patcher.masm()->movt(dst, target16_1); |
| 843 } |
| 844 } else { |
| 845 // Patch with a sequence of mov/orr/orr instructions. |
| 846 uint8_t target8_0 = target16_0 & kImm8Mask; |
| 847 uint8_t target8_1 = target16_0 >> 8; |
| 848 uint8_t target8_2 = target16_1 & kImm8Mask; |
| 849 if (target8_2 == 0) { |
| 850 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
| 851 2, |
| 852 CodePatcher::DONT_FLUSH); |
| 853 patcher.masm()->mov(dst, Operand(target8_0)); |
| 854 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); |
| 855 } else { |
| 856 CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
| 857 3, |
| 858 CodePatcher::DONT_FLUSH); |
| 859 patcher.masm()->mov(dst, Operand(target8_0)); |
| 860 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); |
| 861 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16)); |
| 862 } |
| 863 } |
| 864 } |
803 return; | 865 return; |
804 } | 866 } |
805 int imm26 = target_pos - (pos + kPcLoadDelta); | 867 int imm26 = target_pos - (pos + kPcLoadDelta); |
806 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 | 868 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 |
807 if (Instruction::ConditionField(instr) == kSpecialCondition) { | 869 if (Instruction::ConditionField(instr) == kSpecialCondition) { |
808 // blx uses bit 24 to encode bit 2 of imm26 | 870 // blx uses bit 24 to encode bit 2 of imm26 |
809 ASSERT((imm26 & 1) == 0); | 871 ASSERT((imm26 & 1) == 0); |
810 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24; | 872 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24; |
811 } else { | 873 } else { |
812 ASSERT((imm26 & 3) == 0); | 874 ASSERT((imm26 & 3) == 0); |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1225 L->link_to(pc_offset()); | 1287 L->link_to(pc_offset()); |
1226 } | 1288 } |
1227 | 1289 |
1228 // Block the emission of the constant pool, since the branch instruction must | 1290 // Block the emission of the constant pool, since the branch instruction must |
1229 // be emitted at the pc offset recorded by the label. | 1291 // be emitted at the pc offset recorded by the label. |
1230 BlockConstPoolFor(1); | 1292 BlockConstPoolFor(1); |
1231 return target_pos - (pc_offset() + kPcLoadDelta); | 1293 return target_pos - (pc_offset() + kPcLoadDelta); |
1232 } | 1294 } |
1233 | 1295 |
1234 | 1296 |
1235 void Assembler::label_at_put(Label* L, int at_offset) { | |
1236 int target_pos; | |
1237 ASSERT(!L->is_bound()); | |
1238 if (L->is_linked()) { | |
1239 // Point to previous instruction that uses the link. | |
1240 target_pos = L->pos(); | |
1241 } else { | |
1242 // First entry of the link chain points to itself. | |
1243 target_pos = at_offset; | |
1244 } | |
1245 L->link_to(at_offset); | |
1246 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); | |
1247 } | |
1248 | |
1249 | |
1250 // Branch instructions. | 1297 // Branch instructions. |
1251 void Assembler::b(int branch_offset, Condition cond) { | 1298 void Assembler::b(int branch_offset, Condition cond) { |
1252 ASSERT((branch_offset & 3) == 0); | 1299 ASSERT((branch_offset & 3) == 0); |
1253 int imm24 = branch_offset >> 2; | 1300 int imm24 = branch_offset >> 2; |
1254 ASSERT(is_int24(imm24)); | 1301 ASSERT(is_int24(imm24)); |
1255 emit(cond | B27 | B25 | (imm24 & kImm24Mask)); | 1302 emit(cond | B27 | B25 | (imm24 & kImm24Mask)); |
1256 | 1303 |
1257 if (cond == al) { | 1304 if (cond == al) { |
1258 // Dead code is a good location to emit the constant pool. | 1305 // Dead code is a good location to emit the constant pool. |
1259 CheckConstPool(false, false); | 1306 CheckConstPool(false, false); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 positions_recorder()->WriteRecordedPositions(); | 1429 positions_recorder()->WriteRecordedPositions(); |
1383 } | 1430 } |
1384 // Don't allow nop instructions in the form mov rn, rn to be generated using | 1431 // Don't allow nop instructions in the form mov rn, rn to be generated using |
1385 // the mov instruction. They must be generated using nop(int/NopMarkerTypes) | 1432 // the mov instruction. They must be generated using nop(int/NopMarkerTypes) |
1386 // or MarkCode(int/NopMarkerTypes) pseudo instructions. | 1433 // or MarkCode(int/NopMarkerTypes) pseudo instructions. |
1387 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); | 1434 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al)); |
1388 addrmod1(cond | MOV | s, r0, dst, src); | 1435 addrmod1(cond | MOV | s, r0, dst, src); |
1389 } | 1436 } |
1390 | 1437 |
1391 | 1438 |
| 1439 void Assembler::mov_label_offset(Register dst, Label* label) { |
| 1440 if (label->is_bound()) { |
| 1441 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag))); |
| 1442 } else { |
| 1443 // Emit the link to the label in the code stream followed by extra nop |
| 1444 // instructions. |
| 1445 // If the label is not linked, then start a new link chain by linking it to |
| 1446 // itself, emitting pc_offset(). |
| 1447 int link = label->is_linked() ? label->pos() : pc_offset(); |
| 1448 label->link_to(pc_offset()); |
| 1449 |
| 1450 // When the label is bound, these instructions will be patched with a |
| 1451 // sequence of movw/movt or mov/orr/orr instructions. They will load the |
| 1452 // destination register with the position of the label from the beginning |
| 1453 // of the code. |
| 1454 // |
| 1455 // The link will be extracted from the first instruction and the destination |
| 1456 // register from the second. |
| 1457 // For ARMv7: |
| 1458 // link |
| 1459 // mov dst, dst |
| 1460 // For ARMv6: |
| 1461 // link |
| 1462 // mov dst, dst |
| 1463 // mov dst, dst |
| 1464 // |
| 1465 // When the label gets bound: target_at extracts the link and target_at_put |
| 1466 // patches the instructions. |
| 1467 ASSERT(is_uint24(link)); |
| 1468 BlockConstPoolScope block_const_pool(this); |
| 1469 emit(link); |
| 1470 nop(dst.code()); |
| 1471 if (!CpuFeatures::IsSupported(ARMv7)) { |
| 1472 nop(dst.code()); |
| 1473 } |
| 1474 } |
| 1475 } |
| 1476 |
| 1477 |
1392 void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { | 1478 void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { |
1393 ASSERT(immediate < 0x10000); | 1479 ASSERT(immediate < 0x10000); |
1394 // May use movw if supported, but on unsupported platforms will try to use | 1480 // May use movw if supported, but on unsupported platforms will try to use |
1395 // equivalent rotated immed_8 value and other tricks before falling back to a | 1481 // equivalent rotated immed_8 value and other tricks before falling back to a |
1396 // constant pool load. | 1482 // constant pool load. |
1397 mov(reg, Operand(immediate), LeaveCC, cond); | 1483 mov(reg, Operand(immediate), LeaveCC, cond); |
1398 } | 1484 } |
1399 | 1485 |
1400 | 1486 |
1401 void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { | 1487 void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { |
(...skipping 1952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3354 | 3440 |
3355 // Since a constant pool was just emitted, move the check offset forward by | 3441 // Since a constant pool was just emitted, move the check offset forward by |
3356 // the standard interval. | 3442 // the standard interval. |
3357 next_buffer_check_ = pc_offset() + kCheckPoolInterval; | 3443 next_buffer_check_ = pc_offset() + kCheckPoolInterval; |
3358 } | 3444 } |
3359 | 3445 |
3360 | 3446 |
3361 } } // namespace v8::internal | 3447 } } // namespace v8::internal |
3362 | 3448 |
3363 #endif // V8_TARGET_ARCH_ARM | 3449 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |