| 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 are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 V(rsi) \ | 73 V(rsi) \ |
| 74 V(rdi) \ | 74 V(rdi) \ |
| 75 V(r8) \ | 75 V(r8) \ |
| 76 V(r9) \ | 76 V(r9) \ |
| 77 V(r11) \ | 77 V(r11) \ |
| 78 V(r12) \ | 78 V(r12) \ |
| 79 V(r14) \ | 79 V(r14) \ |
| 80 V(r15) | 80 V(r15) |
| 81 | 81 |
| 82 // The length of pushq(rbp), movp(rbp, rsp), Push(rsi) and Push(rdi). | 82 // The length of pushq(rbp), movp(rbp, rsp), Push(rsi) and Push(rdi). |
| 83 static const int kNoCodeAgeSequenceLength = kPointerSize == kInt64Size ? 6 : 17; | 83 constexpr int kNoCodeAgeSequenceLength = kPointerSize == kInt64Size ? 6 : 17; |
| 84 | 84 |
| 85 // CPU Registers. | 85 // CPU Registers. |
| 86 // | 86 // |
| 87 // 1) We would prefer to use an enum, but enum values are assignment- | 87 // 1) We would prefer to use an enum, but enum values are assignment- |
| 88 // compatible with int, which has caused code-generation bugs. | 88 // compatible with int, which has caused code-generation bugs. |
| 89 // | 89 // |
| 90 // 2) We would prefer to use a class instead of a struct but we don't like | 90 // 2) We would prefer to use a class instead of a struct but we don't like |
| 91 // the register initialization to depend on the particular initialization | 91 // the register initialization to depend on the particular initialization |
| 92 // order (which appears to be different on OS X, Linux, and Windows for the | 92 // order (which appears to be different on OS X, Linux, and Windows for the |
| 93 // installed versions of C++ we tried). Using a struct permits C-style | 93 // installed versions of C++ we tried). Using a struct permits C-style |
| (...skipping 11 matching lines...) Expand all Loading... |
| 105 // | 105 // |
| 106 struct Register { | 106 struct Register { |
| 107 enum Code { | 107 enum Code { |
| 108 #define REGISTER_CODE(R) kCode_##R, | 108 #define REGISTER_CODE(R) kCode_##R, |
| 109 GENERAL_REGISTERS(REGISTER_CODE) | 109 GENERAL_REGISTERS(REGISTER_CODE) |
| 110 #undef REGISTER_CODE | 110 #undef REGISTER_CODE |
| 111 kAfterLast, | 111 kAfterLast, |
| 112 kCode_no_reg = -1 | 112 kCode_no_reg = -1 |
| 113 }; | 113 }; |
| 114 | 114 |
| 115 static const int kNumRegisters = Code::kAfterLast; | 115 static constexpr int kNumRegisters = Code::kAfterLast; |
| 116 | 116 |
| 117 static Register from_code(int code) { | 117 static Register from_code(int code) { |
| 118 DCHECK(code >= 0); | 118 DCHECK(code >= 0); |
| 119 DCHECK(code < kNumRegisters); | 119 DCHECK(code < kNumRegisters); |
| 120 Register r = {code}; | 120 Register r = {code}; |
| 121 return r; | 121 return r; |
| 122 } | 122 } |
| 123 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; } | 123 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; } |
| 124 bool is(Register reg) const { return reg_code == reg.reg_code; } | 124 bool is(Register reg) const { return reg_code == reg.reg_code; } |
| 125 int code() const { | 125 int code() const { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 137 int high_bit() const { return reg_code >> 3; } | 137 int high_bit() const { return reg_code >> 3; } |
| 138 // Return the 3 low bits of the register code. Used when encoding registers | 138 // Return the 3 low bits of the register code. Used when encoding registers |
| 139 // in modR/M, SIB, and opcode bytes. | 139 // in modR/M, SIB, and opcode bytes. |
| 140 int low_bits() const { return reg_code & 0x7; } | 140 int low_bits() const { return reg_code & 0x7; } |
| 141 | 141 |
| 142 // Unfortunately we can't make this private in a struct when initializing | 142 // Unfortunately we can't make this private in a struct when initializing |
| 143 // by assignment. | 143 // by assignment. |
| 144 int reg_code; | 144 int reg_code; |
| 145 }; | 145 }; |
| 146 | 146 |
| 147 | 147 #define DECLARE_REGISTER(R) constexpr Register R = {Register::kCode_##R}; |
| 148 #define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R}; | |
| 149 GENERAL_REGISTERS(DECLARE_REGISTER) | 148 GENERAL_REGISTERS(DECLARE_REGISTER) |
| 150 #undef DECLARE_REGISTER | 149 #undef DECLARE_REGISTER |
| 151 const Register no_reg = {Register::kCode_no_reg}; | 150 constexpr Register no_reg = {Register::kCode_no_reg}; |
| 152 | |
| 153 | 151 |
| 154 #ifdef _WIN64 | 152 #ifdef _WIN64 |
| 155 // Windows calling convention | 153 // Windows calling convention |
| 156 const Register arg_reg_1 = {Register::kCode_rcx}; | 154 constexpr Register arg_reg_1 = {Register::kCode_rcx}; |
| 157 const Register arg_reg_2 = {Register::kCode_rdx}; | 155 constexpr Register arg_reg_2 = {Register::kCode_rdx}; |
| 158 const Register arg_reg_3 = {Register::kCode_r8}; | 156 constexpr Register arg_reg_3 = {Register::kCode_r8}; |
| 159 const Register arg_reg_4 = {Register::kCode_r9}; | 157 constexpr Register arg_reg_4 = {Register::kCode_r9}; |
| 160 #else | 158 #else |
| 161 // AMD64 calling convention | 159 // AMD64 calling convention |
| 162 const Register arg_reg_1 = {Register::kCode_rdi}; | 160 constexpr Register arg_reg_1 = {Register::kCode_rdi}; |
| 163 const Register arg_reg_2 = {Register::kCode_rsi}; | 161 constexpr Register arg_reg_2 = {Register::kCode_rsi}; |
| 164 const Register arg_reg_3 = {Register::kCode_rdx}; | 162 constexpr Register arg_reg_3 = {Register::kCode_rdx}; |
| 165 const Register arg_reg_4 = {Register::kCode_rcx}; | 163 constexpr Register arg_reg_4 = {Register::kCode_rcx}; |
| 166 #endif // _WIN64 | 164 #endif // _WIN64 |
| 167 | 165 |
| 168 | 166 |
| 169 #define DOUBLE_REGISTERS(V) \ | 167 #define DOUBLE_REGISTERS(V) \ |
| 170 V(xmm0) \ | 168 V(xmm0) \ |
| 171 V(xmm1) \ | 169 V(xmm1) \ |
| 172 V(xmm2) \ | 170 V(xmm2) \ |
| 173 V(xmm3) \ | 171 V(xmm3) \ |
| 174 V(xmm4) \ | 172 V(xmm4) \ |
| 175 V(xmm5) \ | 173 V(xmm5) \ |
| (...skipping 21 matching lines...) Expand all Loading... |
| 197 V(xmm6) \ | 195 V(xmm6) \ |
| 198 V(xmm7) \ | 196 V(xmm7) \ |
| 199 V(xmm8) \ | 197 V(xmm8) \ |
| 200 V(xmm9) \ | 198 V(xmm9) \ |
| 201 V(xmm10) \ | 199 V(xmm10) \ |
| 202 V(xmm11) \ | 200 V(xmm11) \ |
| 203 V(xmm12) \ | 201 V(xmm12) \ |
| 204 V(xmm13) \ | 202 V(xmm13) \ |
| 205 V(xmm14) | 203 V(xmm14) |
| 206 | 204 |
| 207 static const bool kSimpleFPAliasing = true; | 205 constexpr bool kSimpleFPAliasing = true; |
| 208 static const bool kSimdMaskRegisters = false; | 206 constexpr bool kSimdMaskRegisters = false; |
| 209 | 207 |
| 210 struct XMMRegister { | 208 struct XMMRegister { |
| 211 enum Code { | 209 enum Code { |
| 212 #define REGISTER_CODE(R) kCode_##R, | 210 #define REGISTER_CODE(R) kCode_##R, |
| 213 DOUBLE_REGISTERS(REGISTER_CODE) | 211 DOUBLE_REGISTERS(REGISTER_CODE) |
| 214 #undef REGISTER_CODE | 212 #undef REGISTER_CODE |
| 215 kAfterLast, | 213 kAfterLast, |
| 216 kCode_no_reg = -1 | 214 kCode_no_reg = -1 |
| 217 }; | 215 }; |
| 218 | 216 |
| 219 static const int kMaxNumRegisters = Code::kAfterLast; | 217 static constexpr int kMaxNumRegisters = Code::kAfterLast; |
| 220 | 218 |
| 221 static XMMRegister from_code(int code) { | 219 static XMMRegister from_code(int code) { |
| 222 XMMRegister result = {code}; | 220 XMMRegister result = {code}; |
| 223 return result; | 221 return result; |
| 224 } | 222 } |
| 225 | 223 |
| 226 bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; } | 224 bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; } |
| 227 bool is(XMMRegister reg) const { return reg_code == reg.reg_code; } | 225 bool is(XMMRegister reg) const { return reg_code == reg.reg_code; } |
| 228 int code() const { | 226 int code() const { |
| 229 DCHECK(is_valid()); | 227 DCHECK(is_valid()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 242 int reg_code; | 240 int reg_code; |
| 243 }; | 241 }; |
| 244 | 242 |
| 245 typedef XMMRegister FloatRegister; | 243 typedef XMMRegister FloatRegister; |
| 246 | 244 |
| 247 typedef XMMRegister DoubleRegister; | 245 typedef XMMRegister DoubleRegister; |
| 248 | 246 |
| 249 typedef XMMRegister Simd128Register; | 247 typedef XMMRegister Simd128Register; |
| 250 | 248 |
| 251 #define DECLARE_REGISTER(R) \ | 249 #define DECLARE_REGISTER(R) \ |
| 252 const DoubleRegister R = {DoubleRegister::kCode_##R}; | 250 constexpr DoubleRegister R = {DoubleRegister::kCode_##R}; |
| 253 DOUBLE_REGISTERS(DECLARE_REGISTER) | 251 DOUBLE_REGISTERS(DECLARE_REGISTER) |
| 254 #undef DECLARE_REGISTER | 252 #undef DECLARE_REGISTER |
| 255 const DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg}; | 253 constexpr DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg}; |
| 256 | 254 |
| 257 enum Condition { | 255 enum Condition { |
| 258 // any value < 0 is considered no_condition | 256 // any value < 0 is considered no_condition |
| 259 no_condition = -1, | 257 no_condition = -1, |
| 260 | 258 |
| 261 overflow = 0, | 259 overflow = 0, |
| 262 no_overflow = 1, | 260 no_overflow = 1, |
| 263 below = 2, | 261 below = 2, |
| 264 above_equal = 3, | 262 above_equal = 3, |
| 265 equal = 4, | 263 equal = 4, |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 private: | 462 private: |
| 465 // We check before assembling an instruction that there is sufficient | 463 // We check before assembling an instruction that there is sufficient |
| 466 // space to write an instruction and its relocation information. | 464 // space to write an instruction and its relocation information. |
| 467 // The relocation writer's position must be kGap bytes above the end of | 465 // The relocation writer's position must be kGap bytes above the end of |
| 468 // the generated instructions. This leaves enough space for the | 466 // the generated instructions. This leaves enough space for the |
| 469 // longest possible x64 instruction, 15 bytes, and the longest possible | 467 // longest possible x64 instruction, 15 bytes, and the longest possible |
| 470 // relocation information encoding, RelocInfoWriter::kMaxLength == 16. | 468 // relocation information encoding, RelocInfoWriter::kMaxLength == 16. |
| 471 // (There is a 15 byte limit on x64 instruction length that rules out some | 469 // (There is a 15 byte limit on x64 instruction length that rules out some |
| 472 // otherwise valid instructions.) | 470 // otherwise valid instructions.) |
| 473 // This allows for a single, fast space check per instruction. | 471 // This allows for a single, fast space check per instruction. |
| 474 static const int kGap = 32; | 472 static constexpr int kGap = 32; |
| 475 | 473 |
| 476 public: | 474 public: |
| 477 // Create an assembler. Instructions and relocation information are emitted | 475 // Create an assembler. Instructions and relocation information are emitted |
| 478 // into a buffer, with the instructions starting from the beginning and the | 476 // into a buffer, with the instructions starting from the beginning and the |
| 479 // relocation information starting from the end of the buffer. See CodeDesc | 477 // relocation information starting from the end of the buffer. See CodeDesc |
| 480 // for a detailed comment on the layout (globals.h). | 478 // for a detailed comment on the layout (globals.h). |
| 481 // | 479 // |
| 482 // If the provided buffer is NULL, the assembler allocates and grows its own | 480 // If the provided buffer is NULL, the assembler allocates and grows its own |
| 483 // buffer, and buffer_size determines the initial buffer size. The buffer is | 481 // buffer, and buffer_size determines the initial buffer size. The buffer is |
| 484 // owned by the assembler and deallocated upon destruction of the assembler. | 482 // owned by the assembler and deallocated upon destruction of the assembler. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 return RelocInfo::NONE64; | 529 return RelocInfo::NONE64; |
| 532 } else { | 530 } else { |
| 533 DCHECK(kPointerSize == kInt32Size); | 531 DCHECK(kPointerSize == kInt32Size); |
| 534 return RelocInfo::NONE32; | 532 return RelocInfo::NONE32; |
| 535 } | 533 } |
| 536 } | 534 } |
| 537 | 535 |
| 538 inline Handle<Object> code_target_object_handle_at(Address pc); | 536 inline Handle<Object> code_target_object_handle_at(Address pc); |
| 539 inline Address runtime_entry_at(Address pc); | 537 inline Address runtime_entry_at(Address pc); |
| 540 // Number of bytes taken up by the branch target in the code. | 538 // Number of bytes taken up by the branch target in the code. |
| 541 static const int kSpecialTargetSize = 4; // Use 32-bit displacement. | 539 static constexpr int kSpecialTargetSize = 4; // 32-bit displacement. |
| 542 // Distance between the address of the code target in the call instruction | 540 // Distance between the address of the code target in the call instruction |
| 543 // and the return address pushed on the stack. | 541 // and the return address pushed on the stack. |
| 544 static const int kCallTargetAddressOffset = 4; // Use 32-bit displacement. | 542 static constexpr int kCallTargetAddressOffset = 4; // 32-bit displacement. |
| 545 // The length of call(kScratchRegister). | 543 // The length of call(kScratchRegister). |
| 546 static const int kCallScratchRegisterInstructionLength = 3; | 544 static constexpr int kCallScratchRegisterInstructionLength = 3; |
| 547 // The length of call(Immediate32). | 545 // The length of call(Immediate32). |
| 548 static const int kShortCallInstructionLength = 5; | 546 static constexpr int kShortCallInstructionLength = 5; |
| 549 // The length of movq(kScratchRegister, address). | 547 // The length of movq(kScratchRegister, address). |
| 550 static const int kMoveAddressIntoScratchRegisterInstructionLength = | 548 static constexpr int kMoveAddressIntoScratchRegisterInstructionLength = |
| 551 2 + kPointerSize; | 549 2 + kPointerSize; |
| 552 // The length of movq(kScratchRegister, address) and call(kScratchRegister). | 550 // The length of movq(kScratchRegister, address) and call(kScratchRegister). |
| 553 static const int kCallSequenceLength = | 551 static constexpr int kCallSequenceLength = |
| 554 kMoveAddressIntoScratchRegisterInstructionLength + | 552 kMoveAddressIntoScratchRegisterInstructionLength + |
| 555 kCallScratchRegisterInstructionLength; | 553 kCallScratchRegisterInstructionLength; |
| 556 | 554 |
| 557 // The debug break slot must be able to contain an indirect call sequence. | 555 // The debug break slot must be able to contain an indirect call sequence. |
| 558 static const int kDebugBreakSlotLength = kCallSequenceLength; | 556 static constexpr int kDebugBreakSlotLength = kCallSequenceLength; |
| 559 // Distance between start of patched debug break slot and the emitted address | 557 // Distance between start of patched debug break slot and the emitted address |
| 560 // to jump to. | 558 // to jump to. |
| 561 static const int kPatchDebugBreakSlotAddressOffset = | 559 static constexpr int kPatchDebugBreakSlotAddressOffset = |
| 562 kMoveAddressIntoScratchRegisterInstructionLength - kPointerSize; | 560 kMoveAddressIntoScratchRegisterInstructionLength - kPointerSize; |
| 563 | 561 |
| 564 // One byte opcode for test eax,0xXXXXXXXX. | 562 // One byte opcode for test eax,0xXXXXXXXX. |
| 565 static const byte kTestEaxByte = 0xA9; | 563 static constexpr byte kTestEaxByte = 0xA9; |
| 566 // One byte opcode for test al, 0xXX. | 564 // One byte opcode for test al, 0xXX. |
| 567 static const byte kTestAlByte = 0xA8; | 565 static constexpr byte kTestAlByte = 0xA8; |
| 568 // One byte opcode for nop. | 566 // One byte opcode for nop. |
| 569 static const byte kNopByte = 0x90; | 567 static constexpr byte kNopByte = 0x90; |
| 570 | 568 |
| 571 // One byte prefix for a short conditional jump. | 569 // One byte prefix for a short conditional jump. |
| 572 static const byte kJccShortPrefix = 0x70; | 570 static constexpr byte kJccShortPrefix = 0x70; |
| 573 static const byte kJncShortOpcode = kJccShortPrefix | not_carry; | 571 static constexpr byte kJncShortOpcode = kJccShortPrefix | not_carry; |
| 574 static const byte kJcShortOpcode = kJccShortPrefix | carry; | 572 static constexpr byte kJcShortOpcode = kJccShortPrefix | carry; |
| 575 static const byte kJnzShortOpcode = kJccShortPrefix | not_zero; | 573 static constexpr byte kJnzShortOpcode = kJccShortPrefix | not_zero; |
| 576 static const byte kJzShortOpcode = kJccShortPrefix | zero; | 574 static constexpr byte kJzShortOpcode = kJccShortPrefix | zero; |
| 577 | 575 |
| 578 // VEX prefix encodings. | 576 // VEX prefix encodings. |
| 579 enum SIMDPrefix { kNone = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 }; | 577 enum SIMDPrefix { kNone = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 }; |
| 580 enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128, kLZ = kL128 }; | 578 enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128, kLZ = kL128 }; |
| 581 enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 }; | 579 enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 }; |
| 582 enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x3 }; | 580 enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x3 }; |
| 583 | 581 |
| 584 // --------------------------------------------------------------------------- | 582 // --------------------------------------------------------------------------- |
| 585 // Code generation | 583 // Code generation |
| 586 // | 584 // |
| (...skipping 1425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2012 } | 2010 } |
| 2013 | 2011 |
| 2014 // Get the number of bytes available in the buffer. | 2012 // Get the number of bytes available in the buffer. |
| 2015 inline int available_space() const { | 2013 inline int available_space() const { |
| 2016 return static_cast<int>(reloc_info_writer.pos() - pc_); | 2014 return static_cast<int>(reloc_info_writer.pos() - pc_); |
| 2017 } | 2015 } |
| 2018 | 2016 |
| 2019 static bool IsNop(Address addr); | 2017 static bool IsNop(Address addr); |
| 2020 | 2018 |
| 2021 // Avoid overflows for displacements etc. | 2019 // Avoid overflows for displacements etc. |
| 2022 static const int kMaximalBufferSize = 512*MB; | 2020 static constexpr int kMaximalBufferSize = 512 * MB; |
| 2023 | 2021 |
| 2024 byte byte_at(int pos) { return buffer_[pos]; } | 2022 byte byte_at(int pos) { return buffer_[pos]; } |
| 2025 void set_byte_at(int pos, byte value) { buffer_[pos] = value; } | 2023 void set_byte_at(int pos, byte value) { buffer_[pos] = value; } |
| 2026 | 2024 |
| 2027 Address pc() const { return pc_; } | 2025 Address pc() const { return pc_; } |
| 2028 | 2026 |
| 2029 protected: | 2027 protected: |
| 2030 // Call near indirect | 2028 // Call near indirect |
| 2031 void call(const Operand& operand); | 2029 void call(const Operand& operand); |
| 2032 | 2030 |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2519 Assembler* assembler_; | 2517 Assembler* assembler_; |
| 2520 #ifdef DEBUG | 2518 #ifdef DEBUG |
| 2521 int space_before_; | 2519 int space_before_; |
| 2522 #endif | 2520 #endif |
| 2523 }; | 2521 }; |
| 2524 | 2522 |
| 2525 } // namespace internal | 2523 } // namespace internal |
| 2526 } // namespace v8 | 2524 } // namespace v8 |
| 2527 | 2525 |
| 2528 #endif // V8_X64_ASSEMBLER_X64_H_ | 2526 #endif // V8_X64_ASSEMBLER_X64_H_ |
| OLD | NEW |