1// Copyright (c) 1994-2006 Sun Microsystems Inc. 2// All Rights Reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// - Redistributions of source code must retain the above copyright notice, 9// this list of conditions and the following disclaimer. 10// 11// - Redistribution in binary form must reproduce the above copyright 12// notice, this list of conditions and the following disclaimer in the 13// documentation and/or other materials provided with the distribution. 14// 15// - Neither the name of Sun Microsystems or the names of contributors may 16// be used to endorse or promote products derived from this software without 17// specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// The original source code covered by the above license above has been 32// modified significantly by Google Inc. 33// Copyright 2011 the V8 project authors. All rights reserved. 34 35// A light-weight IA32 Assembler. 36 37#ifndef V8_IA32_ASSEMBLER_IA32_H_ 38#define V8_IA32_ASSEMBLER_IA32_H_ 39 40#include "isolate.h" 41#include "serialize.h" 42 43namespace v8 { 44namespace internal { 45 46// CPU Registers. 47// 48// 1) We would prefer to use an enum, but enum values are assignment- 49// compatible with int, which has caused code-generation bugs. 50// 51// 2) We would prefer to use a class instead of a struct but we don't like 52// the register initialization to depend on the particular initialization 53// order (which appears to be different on OS X, Linux, and Windows for the 54// installed versions of C++ we tried). Using a struct permits C-style 55// "initialization". Also, the Register objects cannot be const as this 56// forces initialization stubs in MSVC, making us dependent on initialization 57// order. 58// 59// 3) By not using an enum, we are possibly preventing the compiler from 60// doing certain constant folds, which may significantly reduce the 61// code generated for some assembly instructions (because they boil down 62// to a few constants). If this is a problem, we could change the code 63// such that we use an enum in optimized mode, and the struct in debug 64// mode. This way we get the compile-time error checking in debug mode 65// and best performance in optimized code. 66// 67struct Register { 68 static const int kNumAllocatableRegisters = 6; 69 static const int kNumRegisters = 8; 70 71 static inline const char* AllocationIndexToString(int index); 72 73 static inline int ToAllocationIndex(Register reg); 74 75 static inline Register FromAllocationIndex(int index); 76 77 static Register from_code(int code) { 78 ASSERT(code >= 0); 79 ASSERT(code < kNumRegisters); 80 Register r = { code }; 81 return r; 82 } 83 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } 84 bool is(Register reg) const { return code_ == reg.code_; } 85 // eax, ebx, ecx and edx are byte registers, the rest are not. 86 bool is_byte_register() const { return code_ <= 3; } 87 int code() const { 88 ASSERT(is_valid()); 89 return code_; 90 } 91 int bit() const { 92 ASSERT(is_valid()); 93 return 1 << code_; 94 } 95 96 // Unfortunately we can't make this private in a struct. 97 int code_; 98}; 99 100const int kRegister_eax_Code = 0; 101const int kRegister_ecx_Code = 1; 102const int kRegister_edx_Code = 2; 103const int kRegister_ebx_Code = 3; 104const int kRegister_esp_Code = 4; 105const int kRegister_ebp_Code = 5; 106const int kRegister_esi_Code = 6; 107const int kRegister_edi_Code = 7; 108const int kRegister_no_reg_Code = -1; 109 110const Register eax = { kRegister_eax_Code }; 111const Register ecx = { kRegister_ecx_Code }; 112const Register edx = { kRegister_edx_Code }; 113const Register ebx = { kRegister_ebx_Code }; 114const Register esp = { kRegister_esp_Code }; 115const Register ebp = { kRegister_ebp_Code }; 116const Register esi = { kRegister_esi_Code }; 117const Register edi = { kRegister_edi_Code }; 118const Register no_reg = { kRegister_no_reg_Code }; 119 120 121inline const char* Register::AllocationIndexToString(int index) { 122 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 123 // This is the mapping of allocation indices to registers. 124 const char* const kNames[] = { "eax", "ecx", "edx", "ebx", "esi", "edi" }; 125 return kNames[index]; 126} 127 128 129inline int Register::ToAllocationIndex(Register reg) { 130 ASSERT(reg.is_valid() && !reg.is(esp) && !reg.is(ebp)); 131 return (reg.code() >= 6) ? reg.code() - 2 : reg.code(); 132} 133 134 135inline Register Register::FromAllocationIndex(int index) { 136 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 137 return (index >= 4) ? from_code(index + 2) : from_code(index); 138} 139 140 141struct XMMRegister { 142 static const int kNumAllocatableRegisters = 7; 143 static const int kNumRegisters = 8; 144 145 static int ToAllocationIndex(XMMRegister reg) { 146 ASSERT(reg.code() != 0); 147 return reg.code() - 1; 148 } 149 150 static XMMRegister FromAllocationIndex(int index) { 151 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 152 return from_code(index + 1); 153 } 154 155 static const char* AllocationIndexToString(int index) { 156 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 157 const char* const names[] = { 158 "xmm1", 159 "xmm2", 160 "xmm3", 161 "xmm4", 162 "xmm5", 163 "xmm6", 164 "xmm7" 165 }; 166 return names[index]; 167 } 168 169 static XMMRegister from_code(int code) { 170 XMMRegister r = { code }; 171 return r; 172 } 173 174 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } 175 bool is(XMMRegister reg) const { return code_ == reg.code_; } 176 int code() const { 177 ASSERT(is_valid()); 178 return code_; 179 } 180 181 int code_; 182}; 183 184 185const XMMRegister xmm0 = { 0 }; 186const XMMRegister xmm1 = { 1 }; 187const XMMRegister xmm2 = { 2 }; 188const XMMRegister xmm3 = { 3 }; 189const XMMRegister xmm4 = { 4 }; 190const XMMRegister xmm5 = { 5 }; 191const XMMRegister xmm6 = { 6 }; 192const XMMRegister xmm7 = { 7 }; 193 194 195typedef XMMRegister DoubleRegister; 196 197 198enum Condition { 199 // any value < 0 is considered no_condition 200 no_condition = -1, 201 202 overflow = 0, 203 no_overflow = 1, 204 below = 2, 205 above_equal = 3, 206 equal = 4, 207 not_equal = 5, 208 below_equal = 6, 209 above = 7, 210 negative = 8, 211 positive = 9, 212 parity_even = 10, 213 parity_odd = 11, 214 less = 12, 215 greater_equal = 13, 216 less_equal = 14, 217 greater = 15, 218 219 // aliases 220 carry = below, 221 not_carry = above_equal, 222 zero = equal, 223 not_zero = not_equal, 224 sign = negative, 225 not_sign = positive 226}; 227 228 229// Returns the equivalent of !cc. 230// Negation of the default no_condition (-1) results in a non-default 231// no_condition value (-2). As long as tests for no_condition check 232// for condition < 0, this will work as expected. 233inline Condition NegateCondition(Condition cc) { 234 return static_cast<Condition>(cc ^ 1); 235} 236 237 238// Corresponds to transposing the operands of a comparison. 239inline Condition ReverseCondition(Condition cc) { 240 switch (cc) { 241 case below: 242 return above; 243 case above: 244 return below; 245 case above_equal: 246 return below_equal; 247 case below_equal: 248 return above_equal; 249 case less: 250 return greater; 251 case greater: 252 return less; 253 case greater_equal: 254 return less_equal; 255 case less_equal: 256 return greater_equal; 257 default: 258 return cc; 259 }; 260} 261 262 263// ----------------------------------------------------------------------------- 264// Machine instruction Immediates 265 266class Immediate BASE_EMBEDDED { 267 public: 268 inline explicit Immediate(int x); 269 inline explicit Immediate(const ExternalReference& ext); 270 inline explicit Immediate(Handle<Object> handle); 271 inline explicit Immediate(Smi* value); 272 inline explicit Immediate(Address addr); 273 274 static Immediate CodeRelativeOffset(Label* label) { 275 return Immediate(label); 276 } 277 278 bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; } 279 bool is_int8() const { 280 return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE; 281 } 282 bool is_int16() const { 283 return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE; 284 } 285 286 private: 287 inline explicit Immediate(Label* value); 288 289 int x_; 290 RelocInfo::Mode rmode_; 291 292 friend class Assembler; 293 friend class MacroAssembler; 294}; 295 296 297// ----------------------------------------------------------------------------- 298// Machine instruction Operands 299 300enum ScaleFactor { 301 times_1 = 0, 302 times_2 = 1, 303 times_4 = 2, 304 times_8 = 3, 305 times_int_size = times_4, 306 times_half_pointer_size = times_2, 307 times_pointer_size = times_4, 308 times_twice_pointer_size = times_8 309}; 310 311 312class Operand BASE_EMBEDDED { 313 public: 314 // XMM reg 315 INLINE(explicit Operand(XMMRegister xmm_reg)); 316 317 // [disp/r] 318 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode)); 319 // disp only must always be relocated 320 321 // [base + disp/r] 322 explicit Operand(Register base, int32_t disp, 323 RelocInfo::Mode rmode = RelocInfo::NONE); 324 325 // [base + index*scale + disp/r] 326 explicit Operand(Register base, 327 Register index, 328 ScaleFactor scale, 329 int32_t disp, 330 RelocInfo::Mode rmode = RelocInfo::NONE); 331 332 // [index*scale + disp/r] 333 explicit Operand(Register index, 334 ScaleFactor scale, 335 int32_t disp, 336 RelocInfo::Mode rmode = RelocInfo::NONE); 337 338 static Operand StaticVariable(const ExternalReference& ext) { 339 return Operand(reinterpret_cast<int32_t>(ext.address()), 340 RelocInfo::EXTERNAL_REFERENCE); 341 } 342 343 static Operand StaticArray(Register index, 344 ScaleFactor scale, 345 const ExternalReference& arr) { 346 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()), 347 RelocInfo::EXTERNAL_REFERENCE); 348 } 349 350 static Operand Cell(Handle<JSGlobalPropertyCell> cell) { 351 return Operand(reinterpret_cast<int32_t>(cell.location()), 352 RelocInfo::GLOBAL_PROPERTY_CELL); 353 } 354 355 // Returns true if this Operand is a wrapper for the specified register. 356 bool is_reg(Register reg) const; 357 358 // Returns true if this Operand is a wrapper for one register. 359 bool is_reg_only() const; 360 361 // Asserts that this Operand is a wrapper for one register and returns the 362 // register. 363 Register reg() const; 364 365 private: 366 // reg 367 INLINE(explicit Operand(Register reg)); 368 369 // Set the ModRM byte without an encoded 'reg' register. The 370 // register is encoded later as part of the emit_operand operation. 371 inline void set_modrm(int mod, Register rm); 372 373 inline void set_sib(ScaleFactor scale, Register index, Register base); 374 inline void set_disp8(int8_t disp); 375 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode); 376 377 byte buf_[6]; 378 // The number of bytes in buf_. 379 unsigned int len_; 380 // Only valid if len_ > 4. 381 RelocInfo::Mode rmode_; 382 383 friend class Assembler; 384 friend class MacroAssembler; 385 friend class LCodeGen; 386}; 387 388 389// ----------------------------------------------------------------------------- 390// A Displacement describes the 32bit immediate field of an instruction which 391// may be used together with a Label in order to refer to a yet unknown code 392// position. Displacements stored in the instruction stream are used to describe 393// the instruction and to chain a list of instructions using the same Label. 394// A Displacement contains 2 different fields: 395// 396// next field: position of next displacement in the chain (0 = end of list) 397// type field: instruction type 398// 399// A next value of null (0) indicates the end of a chain (note that there can 400// be no displacement at position zero, because there is always at least one 401// instruction byte before the displacement). 402// 403// Displacement _data field layout 404// 405// |31.....2|1......0| 406// [ next | type | 407 408class Displacement BASE_EMBEDDED { 409 public: 410 enum Type { 411 UNCONDITIONAL_JUMP, 412 CODE_RELATIVE, 413 OTHER 414 }; 415 416 int data() const { return data_; } 417 Type type() const { return TypeField::decode(data_); } 418 void next(Label* L) const { 419 int n = NextField::decode(data_); 420 n > 0 ? L->link_to(n) : L->Unuse(); 421 } 422 void link_to(Label* L) { init(L, type()); } 423 424 explicit Displacement(int data) { data_ = data; } 425 426 Displacement(Label* L, Type type) { init(L, type); } 427 428 void print() { 429 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), 430 NextField::decode(data_)); 431 } 432 433 private: 434 int data_; 435 436 class TypeField: public BitField<Type, 0, 2> {}; 437 class NextField: public BitField<int, 2, 32-2> {}; 438 439 void init(Label* L, Type type); 440}; 441 442 443 444// CpuFeatures keeps track of which features are supported by the target CPU. 445// Supported features must be enabled by a Scope before use. 446// Example: 447// if (CpuFeatures::IsSupported(SSE2)) { 448// CpuFeatures::Scope fscope(SSE2); 449// // Generate SSE2 floating point code. 450// } else { 451// // Generate standard x87 floating point code. 452// } 453class CpuFeatures : public AllStatic { 454 public: 455 // Detect features of the target CPU. Set safe defaults if the serializer 456 // is enabled (snapshots must be portable). 457 static void Probe(); 458 459 // Check whether a feature is supported by the target CPU. 460 static bool IsSupported(CpuFeature f) { 461 ASSERT(initialized_); 462 if (f == SSE2 && !FLAG_enable_sse2) return false; 463 if (f == SSE3 && !FLAG_enable_sse3) return false; 464 if (f == SSE4_1 && !FLAG_enable_sse4_1) return false; 465 if (f == CMOV && !FLAG_enable_cmov) return false; 466 if (f == RDTSC && !FLAG_enable_rdtsc) return false; 467 return (supported_ & (static_cast<uint64_t>(1) << f)) != 0; 468 } 469 470#ifdef DEBUG 471 // Check whether a feature is currently enabled. 472 static bool IsEnabled(CpuFeature f) { 473 ASSERT(initialized_); 474 Isolate* isolate = Isolate::UncheckedCurrent(); 475 if (isolate == NULL) { 476 // When no isolate is available, work as if we're running in 477 // release mode. 478 return IsSupported(f); 479 } 480 uint64_t enabled = isolate->enabled_cpu_features(); 481 return (enabled & (static_cast<uint64_t>(1) << f)) != 0; 482 } 483#endif 484 485 // Enable a specified feature within a scope. 486 class Scope BASE_EMBEDDED { 487#ifdef DEBUG 488 489 public: 490 explicit Scope(CpuFeature f) { 491 uint64_t mask = static_cast<uint64_t>(1) << f; 492 ASSERT(CpuFeatures::IsSupported(f)); 493 ASSERT(!Serializer::enabled() || 494 (CpuFeatures::found_by_runtime_probing_ & mask) == 0); 495 isolate_ = Isolate::UncheckedCurrent(); 496 old_enabled_ = 0; 497 if (isolate_ != NULL) { 498 old_enabled_ = isolate_->enabled_cpu_features(); 499 isolate_->set_enabled_cpu_features(old_enabled_ | mask); 500 } 501 } 502 ~Scope() { 503 ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_); 504 if (isolate_ != NULL) { 505 isolate_->set_enabled_cpu_features(old_enabled_); 506 } 507 } 508 509 private: 510 Isolate* isolate_; 511 uint64_t old_enabled_; 512#else 513 514 public: 515 explicit Scope(CpuFeature f) {} 516#endif 517 }; 518 519 class TryForceFeatureScope BASE_EMBEDDED { 520 public: 521 explicit TryForceFeatureScope(CpuFeature f) 522 : old_supported_(CpuFeatures::supported_) { 523 if (CanForce()) { 524 CpuFeatures::supported_ |= (static_cast<uint64_t>(1) << f); 525 } 526 } 527 528 ~TryForceFeatureScope() { 529 if (CanForce()) { 530 CpuFeatures::supported_ = old_supported_; 531 } 532 } 533 534 private: 535 static bool CanForce() { 536 // It's only safe to temporarily force support of CPU features 537 // when there's only a single isolate, which is guaranteed when 538 // the serializer is enabled. 539 return Serializer::enabled(); 540 } 541 542 const uint64_t old_supported_; 543 }; 544 545 private: 546#ifdef DEBUG 547 static bool initialized_; 548#endif 549 static uint64_t supported_; 550 static uint64_t found_by_runtime_probing_; 551 552 DISALLOW_COPY_AND_ASSIGN(CpuFeatures); 553}; 554 555 556class Assembler : public AssemblerBase { 557 private: 558 // We check before assembling an instruction that there is sufficient 559 // space to write an instruction and its relocation information. 560 // The relocation writer's position must be kGap bytes above the end of 561 // the generated instructions. This leaves enough space for the 562 // longest possible ia32 instruction, 15 bytes, and the longest possible 563 // relocation information encoding, RelocInfoWriter::kMaxLength == 16. 564 // (There is a 15 byte limit on ia32 instruction length that rules out some 565 // otherwise valid instructions.) 566 // This allows for a single, fast space check per instruction. 567 static const int kGap = 32; 568 569 public: 570 // Create an assembler. Instructions and relocation information are emitted 571 // into a buffer, with the instructions starting from the beginning and the 572 // relocation information starting from the end of the buffer. See CodeDesc 573 // for a detailed comment on the layout (globals.h). 574 // 575 // If the provided buffer is NULL, the assembler allocates and grows its own 576 // buffer, and buffer_size determines the initial buffer size. The buffer is 577 // owned by the assembler and deallocated upon destruction of the assembler. 578 // 579 // If the provided buffer is not NULL, the assembler uses the provided buffer 580 // for code generation and assumes its size to be buffer_size. If the buffer 581 // is too small, a fatal error occurs. No deallocation of the buffer is done 582 // upon destruction of the assembler. 583 // TODO(vitalyr): the assembler does not need an isolate. 584 Assembler(Isolate* isolate, void* buffer, int buffer_size); 585 ~Assembler(); 586 587 // Overrides the default provided by FLAG_debug_code. 588 void set_emit_debug_code(bool value) { emit_debug_code_ = value; } 589 590 // GetCode emits any pending (non-emitted) code and fills the descriptor 591 // desc. GetCode() is idempotent; it returns the same result if no other 592 // Assembler functions are invoked in between GetCode() calls. 593 void GetCode(CodeDesc* desc); 594 595 // Read/Modify the code target in the branch/call instruction at pc. 596 inline static Address target_address_at(Address pc); 597 inline static void set_target_address_at(Address pc, Address target); 598 599 // This sets the branch destination (which is in the instruction on x86). 600 // This is for calls and branches within generated code. 601 inline static void deserialization_set_special_target_at( 602 Address instruction_payload, Address target) { 603 set_target_address_at(instruction_payload, target); 604 } 605 606 // This sets the branch destination (which is in the instruction on x86). 607 // This is for calls and branches to runtime code. 608 inline static void set_external_target_at(Address instruction_payload, 609 Address target) { 610 set_target_address_at(instruction_payload, target); 611 } 612 613 static const int kSpecialTargetSize = kPointerSize; 614 615 // Distance between the address of the code target in the call instruction 616 // and the return address 617 static const int kCallTargetAddressOffset = kPointerSize; 618 // Distance between start of patched return sequence and the emitted address 619 // to jump to. 620 static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32. 621 622 // Distance between start of patched debug break slot and the emitted address 623 // to jump to. 624 static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32. 625 626 static const int kCallInstructionLength = 5; 627 static const int kJSReturnSequenceLength = 6; 628 629 // The debug break slot must be able to contain a call instruction. 630 static const int kDebugBreakSlotLength = kCallInstructionLength; 631 632 // One byte opcode for test al, 0xXX. 633 static const byte kTestAlByte = 0xA8; 634 // One byte opcode for nop. 635 static const byte kNopByte = 0x90; 636 637 // One byte opcode for a short unconditional jump. 638 static const byte kJmpShortOpcode = 0xEB; 639 // One byte prefix for a short conditional jump. 640 static const byte kJccShortPrefix = 0x70; 641 static const byte kJncShortOpcode = kJccShortPrefix | not_carry; 642 static const byte kJcShortOpcode = kJccShortPrefix | carry; 643 644 // --------------------------------------------------------------------------- 645 // Code generation 646 // 647 // - function names correspond one-to-one to ia32 instruction mnemonics 648 // - unless specified otherwise, instructions operate on 32bit operands 649 // - instructions on 8bit (byte) operands/registers have a trailing '_b' 650 // - instructions on 16bit (word) operands/registers have a trailing '_w' 651 // - naming conflicts with C++ keywords are resolved via a trailing '_' 652 653 // NOTE ON INTERFACE: Currently, the interface is not very consistent 654 // in the sense that some operations (e.g. mov()) can be called in more 655 // the one way to generate the same instruction: The Register argument 656 // can in some cases be replaced with an Operand(Register) argument. 657 // This should be cleaned up and made more orthogonal. The questions 658 // is: should we always use Operands instead of Registers where an 659 // Operand is possible, or should we have a Register (overloaded) form 660 // instead? We must be careful to make sure that the selected instruction 661 // is obvious from the parameters to avoid hard-to-find code generation 662 // bugs. 663 664 // Insert the smallest number of nop instructions 665 // possible to align the pc offset to a multiple 666 // of m. m must be a power of 2. 667 void Align(int m); 668 void Nop(int bytes = 1); 669 // Aligns code to something that's optimal for a jump target for the platform. 670 void CodeTargetAlign(); 671 672 // Stack 673 void pushad(); 674 void popad(); 675 676 void pushfd(); 677 void popfd(); 678 679 void push(const Immediate& x); 680 void push_imm32(int32_t imm32); 681 void push(Register src); 682 void push(const Operand& src); 683 684 void pop(Register dst); 685 void pop(const Operand& dst); 686 687 void enter(const Immediate& size); 688 void leave(); 689 690 // Moves 691 void mov_b(Register dst, Register src) { mov_b(dst, Operand(src)); } 692 void mov_b(Register dst, const Operand& src); 693 void mov_b(Register dst, int8_t imm8) { mov_b(Operand(dst), imm8); } 694 void mov_b(const Operand& dst, int8_t imm8); 695 void mov_b(const Operand& dst, Register src); 696 697 void mov_w(Register dst, const Operand& src); 698 void mov_w(const Operand& dst, Register src); 699 700 void mov(Register dst, int32_t imm32); 701 void mov(Register dst, const Immediate& x); 702 void mov(Register dst, Handle<Object> handle); 703 void mov(Register dst, const Operand& src); 704 void mov(Register dst, Register src); 705 void mov(const Operand& dst, const Immediate& x); 706 void mov(const Operand& dst, Handle<Object> handle); 707 void mov(const Operand& dst, Register src); 708 709 void movsx_b(Register dst, Register src) { movsx_b(dst, Operand(src)); } 710 void movsx_b(Register dst, const Operand& src); 711 712 void movsx_w(Register dst, Register src) { movsx_w(dst, Operand(src)); } 713 void movsx_w(Register dst, const Operand& src); 714 715 void movzx_b(Register dst, Register src) { movzx_b(dst, Operand(src)); } 716 void movzx_b(Register dst, const Operand& src); 717 718 void movzx_w(Register dst, Register src) { movzx_w(dst, Operand(src)); } 719 void movzx_w(Register dst, const Operand& src); 720 721 // Conditional moves 722 void cmov(Condition cc, Register dst, Register src) { 723 cmov(cc, dst, Operand(src)); 724 } 725 void cmov(Condition cc, Register dst, const Operand& src); 726 727 // Flag management. 728 void cld(); 729 730 // Repetitive string instructions. 731 void rep_movs(); 732 void rep_stos(); 733 void stos(); 734 735 // Exchange two registers 736 void xchg(Register dst, Register src); 737 738 // Arithmetics 739 void adc(Register dst, int32_t imm32); 740 void adc(Register dst, const Operand& src); 741 742 void add(Register dst, Register src) { add(dst, Operand(src)); } 743 void add(Register dst, const Operand& src); 744 void add(const Operand& dst, Register src); 745 void add(Register dst, const Immediate& imm) { add(Operand(dst), imm); } 746 void add(const Operand& dst, const Immediate& x); 747 748 void and_(Register dst, int32_t imm32); 749 void and_(Register dst, const Immediate& x); 750 void and_(Register dst, Register src) { and_(dst, Operand(src)); } 751 void and_(Register dst, const Operand& src); 752 void and_(const Operand& dst, Register src); 753 void and_(const Operand& dst, const Immediate& x); 754 755 void cmpb(Register reg, int8_t imm8) { cmpb(Operand(reg), imm8); } 756 void cmpb(const Operand& op, int8_t imm8); 757 void cmpb(Register reg, const Operand& op); 758 void cmpb(const Operand& op, Register reg); 759 void cmpb_al(const Operand& op); 760 void cmpw_ax(const Operand& op); 761 void cmpw(const Operand& op, Immediate imm16); 762 void cmp(Register reg, int32_t imm32); 763 void cmp(Register reg, Handle<Object> handle); 764 void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); } 765 void cmp(Register reg, const Operand& op); 766 void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); } 767 void cmp(const Operand& op, const Immediate& imm); 768 void cmp(const Operand& op, Handle<Object> handle); 769 770 void dec_b(Register dst); 771 void dec_b(const Operand& dst); 772 773 void dec(Register dst); 774 void dec(const Operand& dst); 775 776 void cdq(); 777 778 void idiv(Register src); 779 780 // Signed multiply instructions. 781 void imul(Register src); // edx:eax = eax * src. 782 void imul(Register dst, Register src) { imul(dst, Operand(src)); } 783 void imul(Register dst, const Operand& src); // dst = dst * src. 784 void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32. 785 786 void inc(Register dst); 787 void inc(const Operand& dst); 788 789 void lea(Register dst, const Operand& src); 790 791 // Unsigned multiply instruction. 792 void mul(Register src); // edx:eax = eax * reg. 793 794 void neg(Register dst); 795 796 void not_(Register dst); 797 798 void or_(Register dst, int32_t imm32); 799 void or_(Register dst, Register src) { or_(dst, Operand(src)); } 800 void or_(Register dst, const Operand& src); 801 void or_(const Operand& dst, Register src); 802 void or_(Register dst, const Immediate& imm) { or_(Operand(dst), imm); } 803 void or_(const Operand& dst, const Immediate& x); 804 805 void rcl(Register dst, uint8_t imm8); 806 void rcr(Register dst, uint8_t imm8); 807 808 void sar(Register dst, uint8_t imm8); 809 void sar_cl(Register dst); 810 811 void sbb(Register dst, const Operand& src); 812 813 void shld(Register dst, Register src) { shld(dst, Operand(src)); } 814 void shld(Register dst, const Operand& src); 815 816 void shl(Register dst, uint8_t imm8); 817 void shl_cl(Register dst); 818 819 void shrd(Register dst, Register src) { shrd(dst, Operand(src)); } 820 void shrd(Register dst, const Operand& src); 821 822 void shr(Register dst, uint8_t imm8); 823 void shr_cl(Register dst); 824 825 void sub(Register dst, const Immediate& imm) { sub(Operand(dst), imm); } 826 void sub(const Operand& dst, const Immediate& x); 827 void sub(Register dst, Register src) { sub(dst, Operand(src)); } 828 void sub(Register dst, const Operand& src); 829 void sub(const Operand& dst, Register src); 830 831 void test(Register reg, const Immediate& imm); 832 void test(Register reg0, Register reg1) { test(reg0, Operand(reg1)); } 833 void test(Register reg, const Operand& op); 834 void test_b(Register reg, const Operand& op); 835 void test(const Operand& op, const Immediate& imm); 836 void test_b(Register reg, uint8_t imm8) { test_b(Operand(reg), imm8); } 837 void test_b(const Operand& op, uint8_t imm8); 838 839 void xor_(Register dst, int32_t imm32); 840 void xor_(Register dst, Register src) { xor_(dst, Operand(src)); } 841 void xor_(Register dst, const Operand& src); 842 void xor_(const Operand& dst, Register src); 843 void xor_(Register dst, const Immediate& imm) { xor_(Operand(dst), imm); } 844 void xor_(const Operand& dst, const Immediate& x); 845 846 // Bit operations. 847 void bt(const Operand& dst, Register src); 848 void bts(Register dst, Register src) { bts(Operand(dst), src); } 849 void bts(const Operand& dst, Register src); 850 851 // Miscellaneous 852 void hlt(); 853 void int3(); 854 void nop(); 855 void rdtsc(); 856 void ret(int imm16); 857 858 // Label operations & relative jumps (PPUM Appendix D) 859 // 860 // Takes a branch opcode (cc) and a label (L) and generates 861 // either a backward branch or a forward branch and links it 862 // to the label fixup chain. Usage: 863 // 864 // Label L; // unbound label 865 // j(cc, &L); // forward branch to unbound label 866 // bind(&L); // bind label to the current pc 867 // j(cc, &L); // backward branch to bound label 868 // bind(&L); // illegal: a label may be bound only once 869 // 870 // Note: The same Label can be used for forward and backward branches 871 // but it may be bound only once. 872 873 void bind(Label* L); // binds an unbound label L to the current code position 874 875 // Calls 876 void call(Label* L); 877 void call(byte* entry, RelocInfo::Mode rmode); 878 int CallSize(const Operand& adr); 879 void call(Register reg) { call(Operand(reg)); } 880 void call(const Operand& adr); 881 int CallSize(Handle<Code> code, RelocInfo::Mode mode); 882 void call(Handle<Code> code, 883 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 884 unsigned ast_id = kNoASTId); 885 886 // Jumps 887 // unconditional jump to L 888 void jmp(Label* L, Label::Distance distance = Label::kFar); 889 void jmp(byte* entry, RelocInfo::Mode rmode); 890 void jmp(Register reg) { jmp(Operand(reg)); } 891 void jmp(const Operand& adr); 892 void jmp(Handle<Code> code, RelocInfo::Mode rmode); 893 894 // Conditional jumps 895 void j(Condition cc, 896 Label* L, 897 Label::Distance distance = Label::kFar); 898 void j(Condition cc, byte* entry, RelocInfo::Mode rmode); 899 void j(Condition cc, Handle<Code> code); 900 901 // Floating-point operations 902 void fld(int i); 903 void fstp(int i); 904 905 void fld1(); 906 void fldz(); 907 void fldpi(); 908 void fldln2(); 909 910 void fld_s(const Operand& adr); 911 void fld_d(const Operand& adr); 912 913 void fstp_s(const Operand& adr); 914 void fstp_d(const Operand& adr); 915 void fst_d(const Operand& adr); 916 917 void fild_s(const Operand& adr); 918 void fild_d(const Operand& adr); 919 920 void fist_s(const Operand& adr); 921 922 void fistp_s(const Operand& adr); 923 void fistp_d(const Operand& adr); 924 925 // The fisttp instructions require SSE3. 926 void fisttp_s(const Operand& adr); 927 void fisttp_d(const Operand& adr); 928 929 void fabs(); 930 void fchs(); 931 void fcos(); 932 void fsin(); 933 void fptan(); 934 void fyl2x(); 935 void f2xm1(); 936 void fscale(); 937 void fninit(); 938 939 void fadd(int i); 940 void fsub(int i); 941 void fmul(int i); 942 void fdiv(int i); 943 944 void fisub_s(const Operand& adr); 945 946 void faddp(int i = 1); 947 void fsubp(int i = 1); 948 void fsubrp(int i = 1); 949 void fmulp(int i = 1); 950 void fdivp(int i = 1); 951 void fprem(); 952 void fprem1(); 953 954 void fxch(int i = 1); 955 void fincstp(); 956 void ffree(int i = 0); 957 958 void ftst(); 959 void fucomp(int i); 960 void fucompp(); 961 void fucomi(int i); 962 void fucomip(); 963 void fcompp(); 964 void fnstsw_ax(); 965 void fwait(); 966 void fnclex(); 967 968 void frndint(); 969 970 void sahf(); 971 void setcc(Condition cc, Register reg); 972 973 void cpuid(); 974 975 // SSE2 instructions 976 void cvttss2si(Register dst, const Operand& src); 977 void cvttsd2si(Register dst, const Operand& src); 978 979 void cvtsi2sd(XMMRegister dst, Register src) { cvtsi2sd(dst, Operand(src)); } 980 void cvtsi2sd(XMMRegister dst, const Operand& src); 981 void cvtss2sd(XMMRegister dst, XMMRegister src); 982 void cvtsd2ss(XMMRegister dst, XMMRegister src); 983 984 void addsd(XMMRegister dst, XMMRegister src); 985 void subsd(XMMRegister dst, XMMRegister src); 986 void mulsd(XMMRegister dst, XMMRegister src); 987 void divsd(XMMRegister dst, XMMRegister src); 988 void xorpd(XMMRegister dst, XMMRegister src); 989 void xorps(XMMRegister dst, XMMRegister src); 990 void sqrtsd(XMMRegister dst, XMMRegister src); 991 992 void andpd(XMMRegister dst, XMMRegister src); 993 994 void ucomisd(XMMRegister dst, XMMRegister src); 995 void ucomisd(XMMRegister dst, const Operand& src); 996 997 enum RoundingMode { 998 kRoundToNearest = 0x0, 999 kRoundDown = 0x1, 1000 kRoundUp = 0x2, 1001 kRoundToZero = 0x3 1002 }; 1003 1004 void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode); 1005 1006 void movmskpd(Register dst, XMMRegister src); 1007 1008 void cmpltsd(XMMRegister dst, XMMRegister src); 1009 1010 void movaps(XMMRegister dst, XMMRegister src); 1011 1012 void movdqa(XMMRegister dst, const Operand& src); 1013 void movdqa(const Operand& dst, XMMRegister src); 1014 void movdqu(XMMRegister dst, const Operand& src); 1015 void movdqu(const Operand& dst, XMMRegister src); 1016 1017 // Use either movsd or movlpd. 1018 void movdbl(XMMRegister dst, const Operand& src); 1019 void movdbl(const Operand& dst, XMMRegister src); 1020 1021 void movd(XMMRegister dst, Register src) { movd(dst, Operand(src)); } 1022 void movd(XMMRegister dst, const Operand& src); 1023 void movd(Register dst, XMMRegister src) { movd(Operand(dst), src); } 1024 void movd(const Operand& dst, XMMRegister src); 1025 void movsd(XMMRegister dst, XMMRegister src); 1026 1027 void movss(XMMRegister dst, const Operand& src); 1028 void movss(const Operand& dst, XMMRegister src); 1029 void movss(XMMRegister dst, XMMRegister src); 1030 void extractps(Register dst, XMMRegister src, byte imm8); 1031 1032 void pand(XMMRegister dst, XMMRegister src); 1033 void pxor(XMMRegister dst, XMMRegister src); 1034 void por(XMMRegister dst, XMMRegister src); 1035 void ptest(XMMRegister dst, XMMRegister src); 1036 1037 void psllq(XMMRegister reg, int8_t shift); 1038 void psllq(XMMRegister dst, XMMRegister src); 1039 void psrlq(XMMRegister reg, int8_t shift); 1040 void psrlq(XMMRegister dst, XMMRegister src); 1041 void pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle); 1042 void pextrd(Register dst, XMMRegister src, int8_t offset) { 1043 pextrd(Operand(dst), src, offset); 1044 } 1045 void pextrd(const Operand& dst, XMMRegister src, int8_t offset); 1046 void pinsrd(XMMRegister dst, Register src, int8_t offset) { 1047 pinsrd(dst, Operand(src), offset); 1048 } 1049 void pinsrd(XMMRegister dst, const Operand& src, int8_t offset); 1050 1051 // Parallel XMM operations. 1052 void movntdqa(XMMRegister dst, const Operand& src); 1053 void movntdq(const Operand& dst, XMMRegister src); 1054 // Prefetch src position into cache level. 1055 // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a 1056 // non-temporal 1057 void prefetch(const Operand& src, int level); 1058 // TODO(lrn): Need SFENCE for movnt? 1059 1060 // Debugging 1061 void Print(); 1062 1063 // Check the code size generated from label to here. 1064 int SizeOfCodeGeneratedSince(Label* label) { 1065 return pc_offset() - label->pos(); 1066 } 1067 1068 // Mark address of the ExitJSFrame code. 1069 void RecordJSReturn(); 1070 1071 // Mark address of a debug break slot. 1072 void RecordDebugBreakSlot(); 1073 1074 // Record a comment relocation entry that can be used by a disassembler. 1075 // Use --code-comments to enable, or provide "force = true" flag to always 1076 // write a comment. 1077 void RecordComment(const char* msg, bool force = false); 1078 1079 // Writes a single byte or word of data in the code stream. Used for 1080 // inline tables, e.g., jump-tables. 1081 void db(uint8_t data); 1082 void dd(uint32_t data); 1083 1084 int pc_offset() const { return pc_ - buffer_; } 1085 1086 // Check if there is less than kGap bytes available in the buffer. 1087 // If this is the case, we need to grow the buffer before emitting 1088 // an instruction or relocation information. 1089 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 1090 1091 // Get the number of bytes available in the buffer. 1092 inline int available_space() const { return reloc_info_writer.pos() - pc_; } 1093 1094 static bool IsNop(Address addr); 1095 1096 PositionsRecorder* positions_recorder() { return &positions_recorder_; } 1097 1098 int relocation_writer_size() { 1099 return (buffer_ + buffer_size_) - reloc_info_writer.pos(); 1100 } 1101 1102 // Avoid overflows for displacements etc. 1103 static const int kMaximalBufferSize = 512*MB; 1104 static const int kMinimalBufferSize = 4*KB; 1105 1106 byte byte_at(int pos) { return buffer_[pos]; } 1107 void set_byte_at(int pos, byte value) { buffer_[pos] = value; } 1108 1109 protected: 1110 bool emit_debug_code() const { return emit_debug_code_; } 1111 1112 void movsd(XMMRegister dst, const Operand& src); 1113 void movsd(const Operand& dst, XMMRegister src); 1114 1115 void emit_sse_operand(XMMRegister reg, const Operand& adr); 1116 void emit_sse_operand(XMMRegister dst, XMMRegister src); 1117 void emit_sse_operand(Register dst, XMMRegister src); 1118 1119 byte* addr_at(int pos) { return buffer_ + pos; } 1120 1121 1122 private: 1123 uint32_t long_at(int pos) { 1124 return *reinterpret_cast<uint32_t*>(addr_at(pos)); 1125 } 1126 void long_at_put(int pos, uint32_t x) { 1127 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x; 1128 } 1129 1130 // code emission 1131 void GrowBuffer(); 1132 inline void emit(uint32_t x); 1133 inline void emit(Handle<Object> handle); 1134 inline void emit(uint32_t x, 1135 RelocInfo::Mode rmode, 1136 unsigned ast_id = kNoASTId); 1137 inline void emit(const Immediate& x); 1138 inline void emit_w(const Immediate& x); 1139 1140 // Emit the code-object-relative offset of the label's position 1141 inline void emit_code_relative_offset(Label* label); 1142 1143 // instruction generation 1144 void emit_arith_b(int op1, int op2, Register dst, int imm8); 1145 1146 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81) 1147 // with a given destination expression and an immediate operand. It attempts 1148 // to use the shortest encoding possible. 1149 // sel specifies the /n in the modrm byte (see the Intel PRM). 1150 void emit_arith(int sel, Operand dst, const Immediate& x); 1151 1152 void emit_operand(Register reg, const Operand& adr); 1153 1154 void emit_farith(int b1, int b2, int i); 1155 1156 // labels 1157 void print(Label* L); 1158 void bind_to(Label* L, int pos); 1159 1160 // displacements 1161 inline Displacement disp_at(Label* L); 1162 inline void disp_at_put(Label* L, Displacement disp); 1163 inline void emit_disp(Label* L, Displacement::Type type); 1164 inline void emit_near_disp(Label* L); 1165 1166 // record reloc info for current pc_ 1167 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 1168 1169 friend class CodePatcher; 1170 friend class EnsureSpace; 1171 1172 // Code buffer: 1173 // The buffer into which code and relocation info are generated. 1174 byte* buffer_; 1175 int buffer_size_; 1176 // True if the assembler owns the buffer, false if buffer is external. 1177 bool own_buffer_; 1178 1179 // code generation 1180 byte* pc_; // the program counter; moves forward 1181 RelocInfoWriter reloc_info_writer; 1182 1183 PositionsRecorder positions_recorder_; 1184 1185 bool emit_debug_code_; 1186 1187 friend class PositionsRecorder; 1188}; 1189 1190 1191// Helper class that ensures that there is enough space for generating 1192// instructions and relocation information. The constructor makes 1193// sure that there is enough space and (in debug mode) the destructor 1194// checks that we did not generate too much. 1195class EnsureSpace BASE_EMBEDDED { 1196 public: 1197 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) { 1198 if (assembler_->overflow()) assembler_->GrowBuffer(); 1199#ifdef DEBUG 1200 space_before_ = assembler_->available_space(); 1201#endif 1202 } 1203 1204#ifdef DEBUG 1205 ~EnsureSpace() { 1206 int bytes_generated = space_before_ - assembler_->available_space(); 1207 ASSERT(bytes_generated < assembler_->kGap); 1208 } 1209#endif 1210 1211 private: 1212 Assembler* assembler_; 1213#ifdef DEBUG 1214 int space_before_; 1215#endif 1216}; 1217 1218} } // namespace v8::internal 1219 1220#endif // V8_IA32_ASSEMBLER_IA32_H_ 1221