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 2006-2008 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 "serialize.h" 41 42 namespace v8 { 43 namespace internal { 44 45 // CPU Registers. 46 // 47 // 1) We would prefer to use an enum, but enum values are assignment- 48 // compatible with int, which has caused code-generation bugs. 49 // 50 // 2) We would prefer to use a class instead of a struct but we don't like 51 // the register initialization to depend on the particular initialization 52 // order (which appears to be different on OS X, Linux, and Windows for the 53 // installed versions of C++ we tried). Using a struct permits C-style 54 // "initialization". Also, the Register objects cannot be const as this 55 // forces initialization stubs in MSVC, making us dependent on initialization 56 // order. 57 // 58 // 3) By not using an enum, we are possibly preventing the compiler from 59 // doing certain constant folds, which may significantly reduce the 60 // code generated for some assembly instructions (because they boil down 61 // to a few constants). If this is a problem, we could change the code 62 // such that we use an enum in optimized mode, and the struct in debug 63 // mode. This way we get the compile-time error checking in debug mode 64 // and best performance in optimized code. 65 // 66 struct Register { 67 bool is_valid() const { return 0 <= code_ && code_ < 8; } 68 bool is(Register reg) const { return code_ == reg.code_; } 69 // eax, ebx, ecx and edx are byte registers, the rest are not. 70 bool is_byte_register() const { return code_ <= 3; } 71 int code() const { 72 ASSERT(is_valid()); 73 return code_; 74 } 75 int bit() const { 76 ASSERT(is_valid()); 77 return 1 << code_; 78 } 79 80 // Unfortunately we can't make this private in a struct. 81 int code_; 82 }; 83 84 const Register eax = { 0 }; 85 const Register ecx = { 1 }; 86 const Register edx = { 2 }; 87 const Register ebx = { 3 }; 88 const Register esp = { 4 }; 89 const Register ebp = { 5 }; 90 const Register esi = { 6 }; 91 const Register edi = { 7 }; 92 const Register no_reg = { -1 }; 93 94 95 struct XMMRegister { 96 bool is_valid() const { return 0 <= code_ && code_ < 2; } // currently 97 int code() const { 98 ASSERT(is_valid()); 99 return code_; 100 } 101 102 int code_; 103 }; 104 105 const XMMRegister xmm0 = { 0 }; 106 const XMMRegister xmm1 = { 1 }; 107 const XMMRegister xmm2 = { 2 }; 108 const XMMRegister xmm3 = { 3 }; 109 const XMMRegister xmm4 = { 4 }; 110 const XMMRegister xmm5 = { 5 }; 111 const XMMRegister xmm6 = { 6 }; 112 const XMMRegister xmm7 = { 7 }; 113 114 enum Condition { 115 // any value < 0 is considered no_condition 116 no_condition = -1, 117 118 overflow = 0, 119 no_overflow = 1, 120 below = 2, 121 above_equal = 3, 122 equal = 4, 123 not_equal = 5, 124 below_equal = 6, 125 above = 7, 126 negative = 8, 127 positive = 9, 128 parity_even = 10, 129 parity_odd = 11, 130 less = 12, 131 greater_equal = 13, 132 less_equal = 14, 133 greater = 15, 134 135 // aliases 136 carry = below, 137 not_carry = above_equal, 138 zero = equal, 139 not_zero = not_equal, 140 sign = negative, 141 not_sign = positive 142 }; 143 144 145 // Returns the equivalent of !cc. 146 // Negation of the default no_condition (-1) results in a non-default 147 // no_condition value (-2). As long as tests for no_condition check 148 // for condition < 0, this will work as expected. 149 inline Condition NegateCondition(Condition cc); 150 151 // Corresponds to transposing the operands of a comparison. 152 inline Condition ReverseCondition(Condition cc) { 153 switch (cc) { 154 case below: 155 return above; 156 case above: 157 return below; 158 case above_equal: 159 return below_equal; 160 case below_equal: 161 return above_equal; 162 case less: 163 return greater; 164 case greater: 165 return less; 166 case greater_equal: 167 return less_equal; 168 case less_equal: 169 return greater_equal; 170 default: 171 return cc; 172 }; 173 } 174 175 enum Hint { 176 no_hint = 0, 177 not_taken = 0x2e, 178 taken = 0x3e 179 }; 180 181 // The result of negating a hint is as if the corresponding condition 182 // were negated by NegateCondition. That is, no_hint is mapped to 183 // itself and not_taken and taken are mapped to each other. 184 inline Hint NegateHint(Hint hint) { 185 return (hint == no_hint) 186 ? no_hint 187 : ((hint == not_taken) ? taken : not_taken); 188 } 189 190 191 // ----------------------------------------------------------------------------- 192 // Machine instruction Immediates 193 194 class Immediate BASE_EMBEDDED { 195 public: 196 inline explicit Immediate(int x); 197 inline explicit Immediate(const char* s); 198 inline explicit Immediate(const ExternalReference& ext); 199 inline explicit Immediate(Handle<Object> handle); 200 inline explicit Immediate(Smi* value); 201 202 static Immediate CodeRelativeOffset(Label* label) { 203 return Immediate(label); 204 } 205 206 bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; } 207 bool is_int8() const { 208 return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE; 209 } 210 bool is_int16() const { 211 return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE; 212 } 213 214 private: 215 inline explicit Immediate(Label* value); 216 217 int x_; 218 RelocInfo::Mode rmode_; 219 220 friend class Assembler; 221 }; 222 223 224 // ----------------------------------------------------------------------------- 225 // Machine instruction Operands 226 227 enum ScaleFactor { 228 times_1 = 0, 229 times_2 = 1, 230 times_4 = 2, 231 times_8 = 3, 232 times_int_size = times_4, 233 times_half_pointer_size = times_2, 234 times_pointer_size = times_4, 235 times_twice_pointer_size = times_8 236 }; 237 238 239 class Operand BASE_EMBEDDED { 240 public: 241 // reg 242 INLINE(explicit Operand(Register reg)); 243 244 // [disp/r] 245 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode)); 246 // disp only must always be relocated 247 248 // [base + disp/r] 249 explicit Operand(Register base, int32_t disp, 250 RelocInfo::Mode rmode = RelocInfo::NONE); 251 252 // [base + index*scale + disp/r] 253 explicit Operand(Register base, 254 Register index, 255 ScaleFactor scale, 256 int32_t disp, 257 RelocInfo::Mode rmode = RelocInfo::NONE); 258 259 // [index*scale + disp/r] 260 explicit Operand(Register index, 261 ScaleFactor scale, 262 int32_t disp, 263 RelocInfo::Mode rmode = RelocInfo::NONE); 264 265 static Operand StaticVariable(const ExternalReference& ext) { 266 return Operand(reinterpret_cast<int32_t>(ext.address()), 267 RelocInfo::EXTERNAL_REFERENCE); 268 } 269 270 static Operand StaticArray(Register index, 271 ScaleFactor scale, 272 const ExternalReference& arr) { 273 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()), 274 RelocInfo::EXTERNAL_REFERENCE); 275 } 276 277 // Returns true if this Operand is a wrapper for the specified register. 278 bool is_reg(Register reg) const; 279 280 private: 281 byte buf_[6]; 282 // The number of bytes in buf_. 283 unsigned int len_; 284 // Only valid if len_ > 4. 285 RelocInfo::Mode rmode_; 286 287 // Set the ModRM byte without an encoded 'reg' register. The 288 // register is encoded later as part of the emit_operand operation. 289 inline void set_modrm(int mod, Register rm); 290 291 inline void set_sib(ScaleFactor scale, Register index, Register base); 292 inline void set_disp8(int8_t disp); 293 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode); 294 295 friend class Assembler; 296 }; 297 298 299 // ----------------------------------------------------------------------------- 300 // A Displacement describes the 32bit immediate field of an instruction which 301 // may be used together with a Label in order to refer to a yet unknown code 302 // position. Displacements stored in the instruction stream are used to describe 303 // the instruction and to chain a list of instructions using the same Label. 304 // A Displacement contains 2 different fields: 305 // 306 // next field: position of next displacement in the chain (0 = end of list) 307 // type field: instruction type 308 // 309 // A next value of null (0) indicates the end of a chain (note that there can 310 // be no displacement at position zero, because there is always at least one 311 // instruction byte before the displacement). 312 // 313 // Displacement _data field layout 314 // 315 // |31.....2|1......0| 316 // [ next | type | 317 318 class Displacement BASE_EMBEDDED { 319 public: 320 enum Type { 321 UNCONDITIONAL_JUMP, 322 CODE_RELATIVE, 323 OTHER 324 }; 325 326 int data() const { return data_; } 327 Type type() const { return TypeField::decode(data_); } 328 void next(Label* L) const { 329 int n = NextField::decode(data_); 330 n > 0 ? L->link_to(n) : L->Unuse(); 331 } 332 void link_to(Label* L) { init(L, type()); } 333 334 explicit Displacement(int data) { data_ = data; } 335 336 Displacement(Label* L, Type type) { init(L, type); } 337 338 void print() { 339 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), 340 NextField::decode(data_)); 341 } 342 343 private: 344 int data_; 345 346 class TypeField: public BitField<Type, 0, 2> {}; 347 class NextField: public BitField<int, 2, 32-2> {}; 348 349 void init(Label* L, Type type); 350 }; 351 352 353 354 // CpuFeatures keeps track of which features are supported by the target CPU. 355 // Supported features must be enabled by a Scope before use. 356 // Example: 357 // if (CpuFeatures::IsSupported(SSE2)) { 358 // CpuFeatures::Scope fscope(SSE2); 359 // // Generate SSE2 floating point code. 360 // } else { 361 // // Generate standard x87 floating point code. 362 // } 363 class CpuFeatures : public AllStatic { 364 public: 365 // Detect features of the target CPU. Set safe defaults if the serializer 366 // is enabled (snapshots must be portable). 367 static void Probe(); 368 // Check whether a feature is supported by the target CPU. 369 static bool IsSupported(CpuFeature f) { 370 if (f == SSE2 && !FLAG_enable_sse2) return false; 371 if (f == SSE3 && !FLAG_enable_sse3) return false; 372 if (f == CMOV && !FLAG_enable_cmov) return false; 373 if (f == RDTSC && !FLAG_enable_rdtsc) return false; 374 return (supported_ & (static_cast<uint64_t>(1) << f)) != 0; 375 } 376 // Check whether a feature is currently enabled. 377 static bool IsEnabled(CpuFeature f) { 378 return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0; 379 } 380 // Enable a specified feature within a scope. 381 class Scope BASE_EMBEDDED { 382 #ifdef DEBUG 383 public: 384 explicit Scope(CpuFeature f) { 385 uint64_t mask = static_cast<uint64_t>(1) << f; 386 ASSERT(CpuFeatures::IsSupported(f)); 387 ASSERT(!Serializer::enabled() || (found_by_runtime_probing_ & mask) == 0); 388 old_enabled_ = CpuFeatures::enabled_; 389 CpuFeatures::enabled_ |= mask; 390 } 391 ~Scope() { CpuFeatures::enabled_ = old_enabled_; } 392 private: 393 uint64_t old_enabled_; 394 #else 395 public: 396 explicit Scope(CpuFeature f) {} 397 #endif 398 }; 399 private: 400 static uint64_t supported_; 401 static uint64_t enabled_; 402 static uint64_t found_by_runtime_probing_; 403 }; 404 405 406 class Assembler : public Malloced { 407 private: 408 // We check before assembling an instruction that there is sufficient 409 // space to write an instruction and its relocation information. 410 // The relocation writer's position must be kGap bytes above the end of 411 // the generated instructions. This leaves enough space for the 412 // longest possible ia32 instruction, 15 bytes, and the longest possible 413 // relocation information encoding, RelocInfoWriter::kMaxLength == 16. 414 // (There is a 15 byte limit on ia32 instruction length that rules out some 415 // otherwise valid instructions.) 416 // This allows for a single, fast space check per instruction. 417 static const int kGap = 32; 418 419 public: 420 // Create an assembler. Instructions and relocation information are emitted 421 // into a buffer, with the instructions starting from the beginning and the 422 // relocation information starting from the end of the buffer. See CodeDesc 423 // for a detailed comment on the layout (globals.h). 424 // 425 // If the provided buffer is NULL, the assembler allocates and grows its own 426 // buffer, and buffer_size determines the initial buffer size. The buffer is 427 // owned by the assembler and deallocated upon destruction of the assembler. 428 // 429 // If the provided buffer is not NULL, the assembler uses the provided buffer 430 // for code generation and assumes its size to be buffer_size. If the buffer 431 // is too small, a fatal error occurs. No deallocation of the buffer is done 432 // upon destruction of the assembler. 433 Assembler(void* buffer, int buffer_size); 434 ~Assembler(); 435 436 // GetCode emits any pending (non-emitted) code and fills the descriptor 437 // desc. GetCode() is idempotent; it returns the same result if no other 438 // Assembler functions are invoked in between GetCode() calls. 439 void GetCode(CodeDesc* desc); 440 441 // Read/Modify the code target in the branch/call instruction at pc. 442 inline static Address target_address_at(Address pc); 443 inline static void set_target_address_at(Address pc, Address target); 444 445 // This sets the branch destination (which is in the instruction on x86). 446 // This is for calls and branches within generated code. 447 inline static void set_target_at(Address instruction_payload, 448 Address target) { 449 set_target_address_at(instruction_payload, target); 450 } 451 452 // This sets the branch destination (which is in the instruction on x86). 453 // This is for calls and branches to runtime code. 454 inline static void set_external_target_at(Address instruction_payload, 455 Address target) { 456 set_target_address_at(instruction_payload, target); 457 } 458 459 static const int kCallTargetSize = kPointerSize; 460 static const int kExternalTargetSize = kPointerSize; 461 462 // Distance between the address of the code target in the call instruction 463 // and the return address 464 static const int kCallTargetAddressOffset = kPointerSize; 465 // Distance between start of patched return sequence and the emitted address 466 // to jump to. 467 static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32. 468 469 static const int kCallInstructionLength = 5; 470 static const int kJSReturnSequenceLength = 6; 471 472 // --------------------------------------------------------------------------- 473 // Code generation 474 // 475 // - function names correspond one-to-one to ia32 instruction mnemonics 476 // - unless specified otherwise, instructions operate on 32bit operands 477 // - instructions on 8bit (byte) operands/registers have a trailing '_b' 478 // - instructions on 16bit (word) operands/registers have a trailing '_w' 479 // - naming conflicts with C++ keywords are resolved via a trailing '_' 480 481 // NOTE ON INTERFACE: Currently, the interface is not very consistent 482 // in the sense that some operations (e.g. mov()) can be called in more 483 // the one way to generate the same instruction: The Register argument 484 // can in some cases be replaced with an Operand(Register) argument. 485 // This should be cleaned up and made more orthogonal. The questions 486 // is: should we always use Operands instead of Registers where an 487 // Operand is possible, or should we have a Register (overloaded) form 488 // instead? We must be careful to make sure that the selected instruction 489 // is obvious from the parameters to avoid hard-to-find code generation 490 // bugs. 491 492 // Insert the smallest number of nop instructions 493 // possible to align the pc offset to a multiple 494 // of m. m must be a power of 2. 495 void Align(int m); 496 497 // Stack 498 void pushad(); 499 void popad(); 500 501 void pushfd(); 502 void popfd(); 503 504 void push(const Immediate& x); 505 void push(Register src); 506 void push(const Operand& src); 507 void push(Label* label, RelocInfo::Mode relocation_mode); 508 509 void pop(Register dst); 510 void pop(const Operand& dst); 511 512 void enter(const Immediate& size); 513 void leave(); 514 515 // Moves 516 void mov_b(Register dst, const Operand& src); 517 void mov_b(const Operand& dst, int8_t imm8); 518 void mov_b(const Operand& dst, Register src); 519 520 void mov_w(Register dst, const Operand& src); 521 void mov_w(const Operand& dst, Register src); 522 523 void mov(Register dst, int32_t imm32); 524 void mov(Register dst, const Immediate& x); 525 void mov(Register dst, Handle<Object> handle); 526 void mov(Register dst, const Operand& src); 527 void mov(Register dst, Register src); 528 void mov(const Operand& dst, const Immediate& x); 529 void mov(const Operand& dst, Handle<Object> handle); 530 void mov(const Operand& dst, Register src); 531 532 void movsx_b(Register dst, const Operand& src); 533 534 void movsx_w(Register dst, const Operand& src); 535 536 void movzx_b(Register dst, const Operand& src); 537 538 void movzx_w(Register dst, const Operand& src); 539 540 // Conditional moves 541 void cmov(Condition cc, Register dst, int32_t imm32); 542 void cmov(Condition cc, Register dst, Handle<Object> handle); 543 void cmov(Condition cc, Register dst, const Operand& src); 544 545 // Repetitive string instructions. 546 void rep_movs(); 547 548 // Exchange two registers 549 void xchg(Register dst, Register src); 550 551 // Arithmetics 552 void adc(Register dst, int32_t imm32); 553 void adc(Register dst, const Operand& src); 554 555 void add(Register dst, const Operand& src); 556 void add(const Operand& dst, const Immediate& x); 557 558 void and_(Register dst, int32_t imm32); 559 void and_(Register dst, const Operand& src); 560 void and_(const Operand& src, Register dst); 561 void and_(const Operand& dst, const Immediate& x); 562 563 void cmpb(const Operand& op, int8_t imm8); 564 void cmpb(Register src, const Operand& dst); 565 void cmpb(const Operand& dst, Register src); 566 void cmpb_al(const Operand& op); 567 void cmpw_ax(const Operand& op); 568 void cmpw(const Operand& op, Immediate imm16); 569 void cmp(Register reg, int32_t imm32); 570 void cmp(Register reg, Handle<Object> handle); 571 void cmp(Register reg, const Operand& op); 572 void cmp(const Operand& op, const Immediate& imm); 573 void cmp(const Operand& op, Handle<Object> handle); 574 575 void dec_b(Register dst); 576 577 void dec(Register dst); 578 void dec(const Operand& dst); 579 580 void cdq(); 581 582 void idiv(Register src); 583 584 // Signed multiply instructions. 585 void imul(Register src); // edx:eax = eax * src. 586 void imul(Register dst, const Operand& src); // dst = dst * src. 587 void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32. 588 589 void inc(Register dst); 590 void inc(const Operand& dst); 591 592 void lea(Register dst, const Operand& src); 593 594 // Unsigned multiply instruction. 595 void mul(Register src); // edx:eax = eax * reg. 596 597 void neg(Register dst); 598 599 void not_(Register dst); 600 601 void or_(Register dst, int32_t imm32); 602 void or_(Register dst, const Operand& src); 603 void or_(const Operand& dst, Register src); 604 void or_(const Operand& dst, const Immediate& x); 605 606 void rcl(Register dst, uint8_t imm8); 607 608 void sar(Register dst, uint8_t imm8); 609 void sar_cl(Register dst); 610 611 void sbb(Register dst, const Operand& src); 612 613 void shld(Register dst, const Operand& src); 614 615 void shl(Register dst, uint8_t imm8); 616 void shl_cl(Register dst); 617 618 void shrd(Register dst, const Operand& src); 619 620 void shr(Register dst, uint8_t imm8); 621 void shr_cl(Register dst); 622 623 void subb(const Operand& dst, int8_t imm8); 624 void subb(Register dst, const Operand& src); 625 void sub(const Operand& dst, const Immediate& x); 626 void sub(Register dst, const Operand& src); 627 void sub(const Operand& dst, Register src); 628 629 void test(Register reg, const Immediate& imm); 630 void test(Register reg, const Operand& op); 631 void test_b(Register reg, const Operand& op); 632 void test(const Operand& op, const Immediate& imm); 633 634 void xor_(Register dst, int32_t imm32); 635 void xor_(Register dst, const Operand& src); 636 void xor_(const Operand& src, Register dst); 637 void xor_(const Operand& dst, const Immediate& x); 638 639 // Bit operations. 640 void bt(const Operand& dst, Register src); 641 void bts(const Operand& dst, Register src); 642 643 // Miscellaneous 644 void hlt(); 645 void int3(); 646 void nop(); 647 void rdtsc(); 648 void ret(int imm16); 649 650 // Label operations & relative jumps (PPUM Appendix D) 651 // 652 // Takes a branch opcode (cc) and a label (L) and generates 653 // either a backward branch or a forward branch and links it 654 // to the label fixup chain. Usage: 655 // 656 // Label L; // unbound label 657 // j(cc, &L); // forward branch to unbound label 658 // bind(&L); // bind label to the current pc 659 // j(cc, &L); // backward branch to bound label 660 // bind(&L); // illegal: a label may be bound only once 661 // 662 // Note: The same Label can be used for forward and backward branches 663 // but it may be bound only once. 664 665 void bind(Label* L); // binds an unbound label L to the current code position 666 667 // Calls 668 void call(Label* L); 669 void call(byte* entry, RelocInfo::Mode rmode); 670 void call(const Operand& adr); 671 void call(const ExternalReference& target); 672 void call(Handle<Code> code, RelocInfo::Mode rmode); 673 674 // Jumps 675 void jmp(Label* L); // unconditional jump to L 676 void jmp(byte* entry, RelocInfo::Mode rmode); 677 void jmp(const Operand& adr); 678 void jmp(Handle<Code> code, RelocInfo::Mode rmode); 679 680 // Conditional jumps 681 void j(Condition cc, Label* L, Hint hint = no_hint); 682 void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint); 683 void j(Condition cc, Handle<Code> code, Hint hint = no_hint); 684 685 // Floating-point operations 686 void fld(int i); 687 void fstp(int i); 688 689 void fld1(); 690 void fldz(); 691 void fldpi(); 692 693 void fld_s(const Operand& adr); 694 void fld_d(const Operand& adr); 695 696 void fstp_s(const Operand& adr); 697 void fstp_d(const Operand& adr); 698 void fst_d(const Operand& adr); 699 700 void fild_s(const Operand& adr); 701 void fild_d(const Operand& adr); 702 703 void fist_s(const Operand& adr); 704 705 void fistp_s(const Operand& adr); 706 void fistp_d(const Operand& adr); 707 708 void fisttp_s(const Operand& adr); 709 void fisttp_d(const Operand& adr); 710 711 void fabs(); 712 void fchs(); 713 void fcos(); 714 void fsin(); 715 716 void fadd(int i); 717 void fsub(int i); 718 void fmul(int i); 719 void fdiv(int i); 720 721 void fisub_s(const Operand& adr); 722 723 void faddp(int i = 1); 724 void fsubp(int i = 1); 725 void fsubrp(int i = 1); 726 void fmulp(int i = 1); 727 void fdivp(int i = 1); 728 void fprem(); 729 void fprem1(); 730 731 void fxch(int i = 1); 732 void fincstp(); 733 void ffree(int i = 0); 734 735 void ftst(); 736 void fucomp(int i); 737 void fucompp(); 738 void fucomi(int i); 739 void fucomip(); 740 void fcompp(); 741 void fnstsw_ax(); 742 void fwait(); 743 void fnclex(); 744 745 void frndint(); 746 747 void sahf(); 748 void setcc(Condition cc, Register reg); 749 750 void cpuid(); 751 752 // SSE2 instructions 753 void cvttss2si(Register dst, const Operand& src); 754 void cvttsd2si(Register dst, const Operand& src); 755 756 void cvtsi2sd(XMMRegister dst, const Operand& src); 757 758 void addsd(XMMRegister dst, XMMRegister src); 759 void subsd(XMMRegister dst, XMMRegister src); 760 void mulsd(XMMRegister dst, XMMRegister src); 761 void divsd(XMMRegister dst, XMMRegister src); 762 void xorpd(XMMRegister dst, XMMRegister src); 763 764 void comisd(XMMRegister dst, XMMRegister src); 765 766 void movdqa(XMMRegister dst, const Operand& src); 767 void movdqa(const Operand& dst, XMMRegister src); 768 void movdqu(XMMRegister dst, const Operand& src); 769 void movdqu(const Operand& dst, XMMRegister src); 770 771 // Use either movsd or movlpd. 772 void movdbl(XMMRegister dst, const Operand& src); 773 void movdbl(const Operand& dst, XMMRegister src); 774 775 // Debugging 776 void Print(); 777 778 // Check the code size generated from label to here. 779 int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); } 780 781 // Mark address of the ExitJSFrame code. 782 void RecordJSReturn(); 783 784 // Record a comment relocation entry that can be used by a disassembler. 785 // Use --debug_code to enable. 786 void RecordComment(const char* msg); 787 788 void RecordPosition(int pos); 789 void RecordStatementPosition(int pos); 790 void WriteRecordedPositions(); 791 792 // Writes a single word of data in the code stream. 793 // Used for inline tables, e.g., jump-tables. 794 void dd(uint32_t data, RelocInfo::Mode reloc_info); 795 796 int pc_offset() const { return pc_ - buffer_; } 797 int current_statement_position() const { return current_statement_position_; } 798 int current_position() const { return current_position_; } 799 800 // Check if there is less than kGap bytes available in the buffer. 801 // If this is the case, we need to grow the buffer before emitting 802 // an instruction or relocation information. 803 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 804 805 // Get the number of bytes available in the buffer. 806 inline int available_space() const { return reloc_info_writer.pos() - pc_; } 807 808 // Avoid overflows for displacements etc. 809 static const int kMaximalBufferSize = 512*MB; 810 static const int kMinimalBufferSize = 4*KB; 811 812 protected: 813 void movsd(XMMRegister dst, const Operand& src); 814 void movsd(const Operand& dst, XMMRegister src); 815 816 void emit_sse_operand(XMMRegister reg, const Operand& adr); 817 void emit_sse_operand(XMMRegister dst, XMMRegister src); 818 819 820 private: 821 byte* addr_at(int pos) { return buffer_ + pos; } 822 byte byte_at(int pos) { return buffer_[pos]; } 823 uint32_t long_at(int pos) { 824 return *reinterpret_cast<uint32_t*>(addr_at(pos)); 825 } 826 void long_at_put(int pos, uint32_t x) { 827 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x; 828 } 829 830 // code emission 831 void GrowBuffer(); 832 inline void emit(uint32_t x); 833 inline void emit(Handle<Object> handle); 834 inline void emit(uint32_t x, RelocInfo::Mode rmode); 835 inline void emit(const Immediate& x); 836 inline void emit_w(const Immediate& x); 837 838 // Emit the code-object-relative offset of the label's position 839 inline void emit_code_relative_offset(Label* label); 840 841 // instruction generation 842 void emit_arith_b(int op1, int op2, Register dst, int imm8); 843 844 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81) 845 // with a given destination expression and an immediate operand. It attempts 846 // to use the shortest encoding possible. 847 // sel specifies the /n in the modrm byte (see the Intel PRM). 848 void emit_arith(int sel, Operand dst, const Immediate& x); 849 850 void emit_operand(Register reg, const Operand& adr); 851 852 void emit_farith(int b1, int b2, int i); 853 854 // labels 855 void print(Label* L); 856 void bind_to(Label* L, int pos); 857 void link_to(Label* L, Label* appendix); 858 859 // displacements 860 inline Displacement disp_at(Label* L); 861 inline void disp_at_put(Label* L, Displacement disp); 862 inline void emit_disp(Label* L, Displacement::Type type); 863 864 // record reloc info for current pc_ 865 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 866 867 friend class CodePatcher; 868 friend class EnsureSpace; 869 870 // Code buffer: 871 // The buffer into which code and relocation info are generated. 872 byte* buffer_; 873 int buffer_size_; 874 // True if the assembler owns the buffer, false if buffer is external. 875 bool own_buffer_; 876 // A previously allocated buffer of kMinimalBufferSize bytes, or NULL. 877 static byte* spare_buffer_; 878 879 // code generation 880 byte* pc_; // the program counter; moves forward 881 RelocInfoWriter reloc_info_writer; 882 883 // push-pop elimination 884 byte* last_pc_; 885 886 // source position information 887 int current_statement_position_; 888 int current_position_; 889 int written_statement_position_; 890 int written_position_; 891 }; 892 893 894 // Helper class that ensures that there is enough space for generating 895 // instructions and relocation information. The constructor makes 896 // sure that there is enough space and (in debug mode) the destructor 897 // checks that we did not generate too much. 898 class EnsureSpace BASE_EMBEDDED { 899 public: 900 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) { 901 if (assembler_->overflow()) assembler_->GrowBuffer(); 902 #ifdef DEBUG 903 space_before_ = assembler_->available_space(); 904 #endif 905 } 906 907 #ifdef DEBUG 908 ~EnsureSpace() { 909 int bytes_generated = space_before_ - assembler_->available_space(); 910 ASSERT(bytes_generated < assembler_->kGap); 911 } 912 #endif 913 914 private: 915 Assembler* assembler_; 916 #ifdef DEBUG 917 int space_before_; 918 #endif 919 }; 920 921 } } // namespace v8::internal 922 923 #endif // V8_IA32_ASSEMBLER_IA32_H_ 924