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