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