• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
is_validRegister67   bool is_valid() const  { return 0 <= code_ && code_ < 8; }
isRegister68   bool is(Register reg) const  { return code_ == reg.code_; }
69   // eax, ebx, ecx and edx are byte registers, the rest are not.
is_byte_registerRegister70   bool is_byte_register() const  { return code_ <= 3; }
codeRegister71   int code() const  {
72     ASSERT(is_valid());
73     return code_;
74   }
bitRegister75   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 {
is_validXMMRegister96   bool is_valid() const  { return 0 <= code_ && code_ < 2; }  // currently
codeXMMRegister97   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.
ReverseCondition(Condition cc)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.
NegateHint(Hint hint)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 
CodeRelativeOffset(Label * label)202   static Immediate CodeRelativeOffset(Label* label) {
203     return Immediate(label);
204   }
205 
is_zero()206   bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
is_int8()207   bool is_int8() const {
208     return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
209   }
is_int16()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 
StaticVariable(const ExternalReference & ext)265   static Operand StaticVariable(const ExternalReference& ext) {
266     return Operand(reinterpret_cast<int32_t>(ext.address()),
267                    RelocInfo::EXTERNAL_REFERENCE);
268   }
269 
StaticArray(Register index,ScaleFactor scale,const ExternalReference & arr)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 
data()326   int data() const { return data_; }
type()327   Type type() const { return TypeField::decode(data_); }
next(Label * L)328   void next(Label* L) const {
329     int n = NextField::decode(data_);
330     n > 0 ? L->link_to(n) : L->Unuse();
331   }
link_to(Label * L)332   void link_to(Label* L) { init(L, type()); }
333 
Displacement(int data)334   explicit Displacement(int data) { data_ = data; }
335 
Displacement(Label * L,Type type)336   Displacement(Label* L, Type type) { init(L, type); }
337 
print()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.
IsSupported(CpuFeature f)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.
IsEnabled(CpuFeature f)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:
Scope(CpuFeature f)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     }
~Scope()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.
set_target_at(Address instruction_payload,Address target)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.
set_external_target_at(Address instruction_payload,Address target)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.
SizeOfCodeGeneratedSince(Label * l)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 
pc_offset()796   int pc_offset() const  { return pc_ - buffer_; }
current_statement_position()797   int current_statement_position() const { return current_statement_position_; }
current_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.
overflow()803   inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
804 
805   // Get the number of bytes available in the buffer.
available_space()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:
addr_at(int pos)821   byte* addr_at(int pos)  { return buffer_ + pos; }
byte_at(int pos)822   byte byte_at(int pos)  { return buffer_[pos]; }
long_at(int pos)823   uint32_t long_at(int pos)  {
824     return *reinterpret_cast<uint32_t*>(addr_at(pos));
825   }
long_at_put(int pos,uint32_t x)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:
EnsureSpace(Assembler * assembler)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
~EnsureSpace()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