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