OLD | NEW |
| (Empty) |
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 | |
6 // are 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 | |
14 // distribution. | |
15 // | |
16 // - Neither the name of Sun Microsystems or the names of contributors may | |
17 // be used to endorse or promote products derived from this software without | |
18 // specific prior written permission. | |
19 // | |
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
31 // OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | |
33 // The original source code covered by the above license above has been modified | |
34 // significantly by Google Inc. | |
35 // Copyright 2006-2008 the V8 project authors. All rights reserved. | |
36 | |
37 #include "v8.h" | |
38 | |
39 #include "disassembler.h" | |
40 #include "macro-assembler.h" | |
41 #include "serialize.h" | |
42 | |
43 namespace v8 { namespace internal { | |
44 | |
45 // ----------------------------------------------------------------------------- | |
46 // Implementation of Register | |
47 | |
48 Register eax = { 0 }; | |
49 Register ecx = { 1 }; | |
50 Register edx = { 2 }; | |
51 Register ebx = { 3 }; | |
52 Register esp = { 4 }; | |
53 Register ebp = { 5 }; | |
54 Register esi = { 6 }; | |
55 Register edi = { 7 }; | |
56 Register no_reg = { -1 }; | |
57 | |
58 XMMRegister xmm0 = { 0 }; | |
59 XMMRegister xmm1 = { 1 }; | |
60 XMMRegister xmm2 = { 2 }; | |
61 XMMRegister xmm3 = { 3 }; | |
62 XMMRegister xmm4 = { 4 }; | |
63 XMMRegister xmm5 = { 5 }; | |
64 XMMRegister xmm6 = { 6 }; | |
65 XMMRegister xmm7 = { 7 }; | |
66 | |
67 | |
68 // ----------------------------------------------------------------------------- | |
69 // Implementation of CpuFeatures | |
70 | |
71 // Safe default is no features. | |
72 uint64_t CpuFeatures::supported_ = 0; | |
73 uint64_t CpuFeatures::enabled_ = 0; | |
74 | |
75 | |
76 // The Probe method needs executable memory, so it uses Heap::CreateCode. | |
77 // Allocation failure is silent and leads to safe default. | |
78 void CpuFeatures::Probe() { | |
79 ASSERT(Heap::HasBeenSetup()); | |
80 ASSERT(supported_ == 0); | |
81 if (Serializer::enabled()) return; // No features if we might serialize. | |
82 | |
83 Assembler assm(NULL, 0); | |
84 Label cpuid, done; | |
85 #define __ assm. | |
86 // Save old esp, since we are going to modify the stack. | |
87 __ push(ebp); | |
88 __ pushfd(); | |
89 __ push(ecx); | |
90 __ push(ebx); | |
91 __ mov(ebp, Operand(esp)); | |
92 | |
93 // If we can modify bit 21 of the EFLAGS register, then CPUID is supported. | |
94 __ pushfd(); | |
95 __ pop(eax); | |
96 __ mov(edx, Operand(eax)); | |
97 __ xor_(eax, 0x200000); // Flip bit 21. | |
98 __ push(eax); | |
99 __ popfd(); | |
100 __ pushfd(); | |
101 __ pop(eax); | |
102 __ xor_(eax, Operand(edx)); // Different if CPUID is supported. | |
103 __ j(not_zero, &cpuid); | |
104 | |
105 // CPUID not supported. Clear the supported features in edx:eax. | |
106 __ xor_(eax, Operand(eax)); | |
107 __ xor_(edx, Operand(edx)); | |
108 __ jmp(&done); | |
109 | |
110 // Invoke CPUID with 1 in eax to get feature information in | |
111 // ecx:edx. Temporarily enable CPUID support because we know it's | |
112 // safe here. | |
113 __ bind(&cpuid); | |
114 __ mov(eax, 1); | |
115 supported_ = (1 << CPUID); | |
116 { Scope fscope(CPUID); | |
117 __ cpuid(); | |
118 } | |
119 supported_ = 0; | |
120 | |
121 // Move the result from ecx:edx to edx:eax and make sure to mark the | |
122 // CPUID feature as supported. | |
123 __ mov(eax, Operand(edx)); | |
124 __ or_(eax, 1 << CPUID); | |
125 __ mov(edx, Operand(ecx)); | |
126 | |
127 // Done. | |
128 __ bind(&done); | |
129 __ mov(esp, Operand(ebp)); | |
130 __ pop(ebx); | |
131 __ pop(ecx); | |
132 __ popfd(); | |
133 __ pop(ebp); | |
134 __ ret(0); | |
135 #undef __ | |
136 | |
137 CodeDesc desc; | |
138 assm.GetCode(&desc); | |
139 Object* code = | |
140 Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL); | |
141 if (!code->IsCode()) return; | |
142 LOG(CodeCreateEvent("Builtin", Code::cast(code), "CpuFeatures::Probe")); | |
143 typedef uint64_t (*F0)(); | |
144 F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry()); | |
145 supported_ = probe(); | |
146 } | |
147 | |
148 | |
149 // ----------------------------------------------------------------------------- | |
150 // Implementation of Displacement | |
151 | |
152 void Displacement::init(Label* L, Type type) { | |
153 ASSERT(!L->is_bound()); | |
154 int next = 0; | |
155 if (L->is_linked()) { | |
156 next = L->pos(); | |
157 ASSERT(next > 0); // Displacements must be at positions > 0 | |
158 } | |
159 // Ensure that we _never_ overflow the next field. | |
160 ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize)); | |
161 data_ = NextField::encode(next) | TypeField::encode(type); | |
162 } | |
163 | |
164 | |
165 // ----------------------------------------------------------------------------- | |
166 // Implementation of RelocInfo | |
167 | |
168 | |
169 const int RelocInfo::kApplyMask = | |
170 RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | | |
171 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE; | |
172 | |
173 | |
174 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { | |
175 // Patch the code at the current address with the supplied instructions. | |
176 for (int i = 0; i < instruction_count; i++) { | |
177 *(pc_ + i) = *(instructions + i); | |
178 } | |
179 } | |
180 | |
181 | |
182 // Patch the code at the current PC with a call to the target address. | |
183 // Additional guard int3 instructions can be added if required. | |
184 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { | |
185 // Call instruction takes up 5 bytes and int3 takes up one byte. | |
186 int code_size = 5 + guard_bytes; | |
187 | |
188 // Patch the code. | |
189 CodePatcher patcher(pc_, code_size); | |
190 patcher.masm()->call(target, RelocInfo::NONE); | |
191 | |
192 // Add the requested number of int3 instructions after the call. | |
193 for (int i = 0; i < guard_bytes; i++) { | |
194 patcher.masm()->int3(); | |
195 } | |
196 } | |
197 | |
198 | |
199 // ----------------------------------------------------------------------------- | |
200 // Implementation of Operand | |
201 | |
202 Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) { | |
203 // [base + disp/r] | |
204 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { | |
205 // [base] | |
206 set_modrm(0, base); | |
207 if (base.is(esp)) set_sib(times_1, esp, base); | |
208 } else if (is_int8(disp) && rmode == RelocInfo::NONE) { | |
209 // [base + disp8] | |
210 set_modrm(1, base); | |
211 if (base.is(esp)) set_sib(times_1, esp, base); | |
212 set_disp8(disp); | |
213 } else { | |
214 // [base + disp/r] | |
215 set_modrm(2, base); | |
216 if (base.is(esp)) set_sib(times_1, esp, base); | |
217 set_dispr(disp, rmode); | |
218 } | |
219 } | |
220 | |
221 | |
222 Operand::Operand(Register base, | |
223 Register index, | |
224 ScaleFactor scale, | |
225 int32_t disp, | |
226 RelocInfo::Mode rmode) { | |
227 ASSERT(!index.is(esp)); // illegal addressing mode | |
228 // [base + index*scale + disp/r] | |
229 if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { | |
230 // [base + index*scale] | |
231 set_modrm(0, esp); | |
232 set_sib(scale, index, base); | |
233 } else if (is_int8(disp) && rmode == RelocInfo::NONE) { | |
234 // [base + index*scale + disp8] | |
235 set_modrm(1, esp); | |
236 set_sib(scale, index, base); | |
237 set_disp8(disp); | |
238 } else { | |
239 // [base + index*scale + disp/r] | |
240 set_modrm(2, esp); | |
241 set_sib(scale, index, base); | |
242 set_dispr(disp, rmode); | |
243 } | |
244 } | |
245 | |
246 | |
247 Operand::Operand(Register index, | |
248 ScaleFactor scale, | |
249 int32_t disp, | |
250 RelocInfo::Mode rmode) { | |
251 ASSERT(!index.is(esp)); // illegal addressing mode | |
252 // [index*scale + disp/r] | |
253 set_modrm(0, esp); | |
254 set_sib(scale, index, ebp); | |
255 set_dispr(disp, rmode); | |
256 } | |
257 | |
258 | |
259 void Operand::set_sib(ScaleFactor scale, Register index, Register base) { | |
260 ASSERT(len_ == 1); | |
261 ASSERT((scale & -4) == 0); | |
262 buf_[1] = scale << 6 | index.code() << 3 | base.code(); | |
263 len_ = 2; | |
264 } | |
265 | |
266 | |
267 void Operand::set_disp8(int8_t disp) { | |
268 ASSERT(len_ == 1 || len_ == 2); | |
269 *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp; | |
270 } | |
271 | |
272 | |
273 bool Operand::is_reg(Register reg) const { | |
274 return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. | |
275 && ((buf_[0] & 0x07) == reg.code()); // register codes match. | |
276 } | |
277 | |
278 // ----------------------------------------------------------------------------- | |
279 // Implementation of Assembler | |
280 | |
281 // Emit a single byte. Must always be inlined. | |
282 #define EMIT(x) \ | |
283 *pc_++ = (x) | |
284 | |
285 | |
286 #ifdef GENERATED_CODE_COVERAGE | |
287 static void InitCoverageLog(); | |
288 #endif | |
289 | |
290 // spare_buffer_ | |
291 static byte* spare_buffer_ = NULL; | |
292 | |
293 Assembler::Assembler(void* buffer, int buffer_size) { | |
294 if (buffer == NULL) { | |
295 // do our own buffer management | |
296 if (buffer_size <= kMinimalBufferSize) { | |
297 buffer_size = kMinimalBufferSize; | |
298 | |
299 if (spare_buffer_ != NULL) { | |
300 buffer = spare_buffer_; | |
301 spare_buffer_ = NULL; | |
302 } | |
303 } | |
304 if (buffer == NULL) { | |
305 buffer_ = NewArray<byte>(buffer_size); | |
306 } else { | |
307 buffer_ = static_cast<byte*>(buffer); | |
308 } | |
309 buffer_size_ = buffer_size; | |
310 own_buffer_ = true; | |
311 } else { | |
312 // use externally provided buffer instead | |
313 ASSERT(buffer_size > 0); | |
314 buffer_ = static_cast<byte*>(buffer); | |
315 buffer_size_ = buffer_size; | |
316 own_buffer_ = false; | |
317 } | |
318 | |
319 // Clear the buffer in debug mode unless it was provided by the | |
320 // caller in which case we can't be sure it's okay to overwrite | |
321 // existing code in it; see CodePatcher::CodePatcher(...). | |
322 #ifdef DEBUG | |
323 if (own_buffer_) { | |
324 memset(buffer_, 0xCC, buffer_size); // int3 | |
325 } | |
326 #endif | |
327 | |
328 // setup buffer pointers | |
329 ASSERT(buffer_ != NULL); | |
330 pc_ = buffer_; | |
331 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); | |
332 | |
333 last_pc_ = NULL; | |
334 current_statement_position_ = RelocInfo::kNoPosition; | |
335 current_position_ = RelocInfo::kNoPosition; | |
336 written_statement_position_ = current_statement_position_; | |
337 written_position_ = current_position_; | |
338 #ifdef GENERATED_CODE_COVERAGE | |
339 InitCoverageLog(); | |
340 #endif | |
341 } | |
342 | |
343 | |
344 Assembler::~Assembler() { | |
345 if (own_buffer_) { | |
346 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { | |
347 spare_buffer_ = buffer_; | |
348 } else { | |
349 DeleteArray(buffer_); | |
350 } | |
351 } | |
352 } | |
353 | |
354 | |
355 void Assembler::GetCode(CodeDesc* desc) { | |
356 // finalize code | |
357 // (at this point overflow() may be true, but the gap ensures that | |
358 // we are still not overlapping instructions and relocation info) | |
359 ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap | |
360 // setup desc | |
361 desc->buffer = buffer_; | |
362 desc->buffer_size = buffer_size_; | |
363 desc->instr_size = pc_offset(); | |
364 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); | |
365 desc->origin = this; | |
366 | |
367 Counters::reloc_info_size.Increment(desc->reloc_size); | |
368 } | |
369 | |
370 | |
371 void Assembler::Align(int m) { | |
372 ASSERT(IsPowerOf2(m)); | |
373 while ((pc_offset() & (m - 1)) != 0) { | |
374 nop(); | |
375 } | |
376 } | |
377 | |
378 | |
379 void Assembler::cpuid() { | |
380 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID)); | |
381 EnsureSpace ensure_space(this); | |
382 last_pc_ = pc_; | |
383 EMIT(0x0F); | |
384 EMIT(0xA2); | |
385 } | |
386 | |
387 | |
388 void Assembler::pushad() { | |
389 EnsureSpace ensure_space(this); | |
390 last_pc_ = pc_; | |
391 EMIT(0x60); | |
392 } | |
393 | |
394 | |
395 void Assembler::popad() { | |
396 EnsureSpace ensure_space(this); | |
397 last_pc_ = pc_; | |
398 EMIT(0x61); | |
399 } | |
400 | |
401 | |
402 void Assembler::pushfd() { | |
403 EnsureSpace ensure_space(this); | |
404 last_pc_ = pc_; | |
405 EMIT(0x9C); | |
406 } | |
407 | |
408 | |
409 void Assembler::popfd() { | |
410 EnsureSpace ensure_space(this); | |
411 last_pc_ = pc_; | |
412 EMIT(0x9D); | |
413 } | |
414 | |
415 | |
416 void Assembler::push(const Immediate& x) { | |
417 EnsureSpace ensure_space(this); | |
418 last_pc_ = pc_; | |
419 if (x.is_int8()) { | |
420 EMIT(0x6a); | |
421 EMIT(x.x_); | |
422 } else { | |
423 EMIT(0x68); | |
424 emit(x); | |
425 } | |
426 } | |
427 | |
428 | |
429 void Assembler::push(Register src) { | |
430 EnsureSpace ensure_space(this); | |
431 last_pc_ = pc_; | |
432 EMIT(0x50 | src.code()); | |
433 } | |
434 | |
435 | |
436 void Assembler::push(const Operand& src) { | |
437 EnsureSpace ensure_space(this); | |
438 last_pc_ = pc_; | |
439 EMIT(0xFF); | |
440 emit_operand(esi, src); | |
441 } | |
442 | |
443 | |
444 void Assembler::pop(Register dst) { | |
445 ASSERT(reloc_info_writer.last_pc() != NULL); | |
446 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { | |
447 // (last_pc_ != NULL) is rolled into the above check | |
448 // If a last_pc_ is set, we need to make sure that there has not been any | |
449 // relocation information generated between the last instruction and this | |
450 // pop instruction. | |
451 byte instr = last_pc_[0]; | |
452 if ((instr & ~0x7) == 0x50) { | |
453 int push_reg_code = instr & 0x7; | |
454 if (push_reg_code == dst.code()) { | |
455 pc_ = last_pc_; | |
456 if (FLAG_print_push_pop_elimination) { | |
457 PrintF("%d push/pop (same reg) eliminated\n", pc_offset()); | |
458 } | |
459 } else { | |
460 // Convert 'push src; pop dst' to 'mov dst, src'. | |
461 last_pc_[0] = 0x8b; | |
462 Register src = { push_reg_code }; | |
463 EnsureSpace ensure_space(this); | |
464 emit_operand(dst, Operand(src)); | |
465 if (FLAG_print_push_pop_elimination) { | |
466 PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset()); | |
467 } | |
468 } | |
469 last_pc_ = NULL; | |
470 return; | |
471 } else if (instr == 0xff) { // push of an operand, convert to a move | |
472 byte op1 = last_pc_[1]; | |
473 // Check if the operation is really a push | |
474 if ((op1 & 0x38) == (6 << 3)) { | |
475 op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3); | |
476 last_pc_[0] = 0x8b; | |
477 last_pc_[1] = op1; | |
478 last_pc_ = NULL; | |
479 if (FLAG_print_push_pop_elimination) { | |
480 PrintF("%d push/pop (op->reg) eliminated\n", pc_offset()); | |
481 } | |
482 return; | |
483 } | |
484 } else if ((instr == 0x89) && | |
485 (last_pc_[1] == 0x04) && | |
486 (last_pc_[2] == 0x24)) { | |
487 // 0x71283c 396 890424 mov [esp],eax | |
488 // 0x71283f 399 58 pop eax | |
489 if (dst.is(eax)) { | |
490 // change to | |
491 // 0x710fac 216 83c404 add esp,0x4 | |
492 last_pc_[0] = 0x83; | |
493 last_pc_[1] = 0xc4; | |
494 last_pc_[2] = 0x04; | |
495 last_pc_ = NULL; | |
496 if (FLAG_print_push_pop_elimination) { | |
497 PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset()); | |
498 } | |
499 return; | |
500 } | |
501 } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit | |
502 byte imm8 = last_pc_[1]; | |
503 if (imm8 == 0) { | |
504 // 6a00 push 0x0 | |
505 // 58 pop eax | |
506 last_pc_[0] = 0x31; | |
507 last_pc_[1] = 0xc0; | |
508 // change to | |
509 // 31c0 xor eax,eax | |
510 last_pc_ = NULL; | |
511 if (FLAG_print_push_pop_elimination) { | |
512 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | |
513 } | |
514 return; | |
515 } else { | |
516 // 6a00 push 0xXX | |
517 // 58 pop eax | |
518 last_pc_[0] = 0xb8; | |
519 EnsureSpace ensure_space(this); | |
520 if ((imm8 & 0x80) != 0) { | |
521 EMIT(0xff); | |
522 EMIT(0xff); | |
523 EMIT(0xff); | |
524 // change to | |
525 // b8XXffffff mov eax,0xffffffXX | |
526 } else { | |
527 EMIT(0x00); | |
528 EMIT(0x00); | |
529 EMIT(0x00); | |
530 // change to | |
531 // b8XX000000 mov eax,0x000000XX | |
532 } | |
533 last_pc_ = NULL; | |
534 if (FLAG_print_push_pop_elimination) { | |
535 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | |
536 } | |
537 return; | |
538 } | |
539 } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit | |
540 // 68XXXXXXXX push 0xXXXXXXXX | |
541 // 58 pop eax | |
542 last_pc_[0] = 0xb8; | |
543 last_pc_ = NULL; | |
544 // change to | |
545 // b8XXXXXXXX mov eax,0xXXXXXXXX | |
546 if (FLAG_print_push_pop_elimination) { | |
547 PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset()); | |
548 } | |
549 return; | |
550 } | |
551 | |
552 // Other potential patterns for peephole: | |
553 // 0x712716 102 890424 mov [esp], eax | |
554 // 0x712719 105 8b1424 mov edx, [esp] | |
555 } | |
556 EnsureSpace ensure_space(this); | |
557 last_pc_ = pc_; | |
558 EMIT(0x58 | dst.code()); | |
559 } | |
560 | |
561 | |
562 void Assembler::pop(const Operand& dst) { | |
563 EnsureSpace ensure_space(this); | |
564 last_pc_ = pc_; | |
565 EMIT(0x8F); | |
566 emit_operand(eax, dst); | |
567 } | |
568 | |
569 | |
570 void Assembler::enter(const Immediate& size) { | |
571 EnsureSpace ensure_space(this); | |
572 last_pc_ = pc_; | |
573 EMIT(0xC8); | |
574 emit_w(size); | |
575 EMIT(0); | |
576 } | |
577 | |
578 | |
579 void Assembler::leave() { | |
580 EnsureSpace ensure_space(this); | |
581 last_pc_ = pc_; | |
582 EMIT(0xC9); | |
583 } | |
584 | |
585 | |
586 void Assembler::mov_b(Register dst, const Operand& src) { | |
587 EnsureSpace ensure_space(this); | |
588 last_pc_ = pc_; | |
589 EMIT(0x8A); | |
590 emit_operand(dst, src); | |
591 } | |
592 | |
593 | |
594 void Assembler::mov_b(const Operand& dst, int8_t imm8) { | |
595 EnsureSpace ensure_space(this); | |
596 last_pc_ = pc_; | |
597 EMIT(0xC6); | |
598 emit_operand(eax, dst); | |
599 EMIT(imm8); | |
600 } | |
601 | |
602 | |
603 void Assembler::mov_b(const Operand& dst, Register src) { | |
604 EnsureSpace ensure_space(this); | |
605 last_pc_ = pc_; | |
606 EMIT(0x88); | |
607 emit_operand(src, dst); | |
608 } | |
609 | |
610 | |
611 void Assembler::mov_w(Register dst, const Operand& src) { | |
612 EnsureSpace ensure_space(this); | |
613 last_pc_ = pc_; | |
614 EMIT(0x66); | |
615 EMIT(0x8B); | |
616 emit_operand(dst, src); | |
617 } | |
618 | |
619 | |
620 void Assembler::mov_w(const Operand& dst, Register src) { | |
621 EnsureSpace ensure_space(this); | |
622 last_pc_ = pc_; | |
623 EMIT(0x66); | |
624 EMIT(0x89); | |
625 emit_operand(src, dst); | |
626 } | |
627 | |
628 | |
629 void Assembler::mov(Register dst, int32_t imm32) { | |
630 EnsureSpace ensure_space(this); | |
631 last_pc_ = pc_; | |
632 EMIT(0xB8 | dst.code()); | |
633 emit(imm32); | |
634 } | |
635 | |
636 | |
637 void Assembler::mov(Register dst, const Immediate& x) { | |
638 EnsureSpace ensure_space(this); | |
639 last_pc_ = pc_; | |
640 EMIT(0xB8 | dst.code()); | |
641 emit(x); | |
642 } | |
643 | |
644 | |
645 void Assembler::mov(Register dst, Handle<Object> handle) { | |
646 EnsureSpace ensure_space(this); | |
647 last_pc_ = pc_; | |
648 EMIT(0xB8 | dst.code()); | |
649 emit(handle); | |
650 } | |
651 | |
652 | |
653 void Assembler::mov(Register dst, const Operand& src) { | |
654 EnsureSpace ensure_space(this); | |
655 last_pc_ = pc_; | |
656 EMIT(0x8B); | |
657 emit_operand(dst, src); | |
658 } | |
659 | |
660 | |
661 void Assembler::mov(Register dst, Register src) { | |
662 EnsureSpace ensure_space(this); | |
663 last_pc_ = pc_; | |
664 EMIT(0x89); | |
665 EMIT(0xC0 | src.code() << 3 | dst.code()); | |
666 } | |
667 | |
668 | |
669 void Assembler::mov(const Operand& dst, const Immediate& x) { | |
670 EnsureSpace ensure_space(this); | |
671 last_pc_ = pc_; | |
672 EMIT(0xC7); | |
673 emit_operand(eax, dst); | |
674 emit(x); | |
675 } | |
676 | |
677 | |
678 void Assembler::mov(const Operand& dst, Handle<Object> handle) { | |
679 EnsureSpace ensure_space(this); | |
680 last_pc_ = pc_; | |
681 EMIT(0xC7); | |
682 emit_operand(eax, dst); | |
683 emit(handle); | |
684 } | |
685 | |
686 | |
687 void Assembler::mov(const Operand& dst, Register src) { | |
688 EnsureSpace ensure_space(this); | |
689 last_pc_ = pc_; | |
690 EMIT(0x89); | |
691 emit_operand(src, dst); | |
692 } | |
693 | |
694 | |
695 void Assembler::movsx_b(Register dst, const Operand& src) { | |
696 EnsureSpace ensure_space(this); | |
697 last_pc_ = pc_; | |
698 EMIT(0x0F); | |
699 EMIT(0xBE); | |
700 emit_operand(dst, src); | |
701 } | |
702 | |
703 | |
704 void Assembler::movsx_w(Register dst, const Operand& src) { | |
705 EnsureSpace ensure_space(this); | |
706 last_pc_ = pc_; | |
707 EMIT(0x0F); | |
708 EMIT(0xBF); | |
709 emit_operand(dst, src); | |
710 } | |
711 | |
712 | |
713 void Assembler::movzx_b(Register dst, const Operand& src) { | |
714 EnsureSpace ensure_space(this); | |
715 last_pc_ = pc_; | |
716 EMIT(0x0F); | |
717 EMIT(0xB6); | |
718 emit_operand(dst, src); | |
719 } | |
720 | |
721 | |
722 void Assembler::movzx_w(Register dst, const Operand& src) { | |
723 EnsureSpace ensure_space(this); | |
724 last_pc_ = pc_; | |
725 EMIT(0x0F); | |
726 EMIT(0xB7); | |
727 emit_operand(dst, src); | |
728 } | |
729 | |
730 | |
731 void Assembler::cmov(Condition cc, Register dst, int32_t imm32) { | |
732 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); | |
733 EnsureSpace ensure_space(this); | |
734 last_pc_ = pc_; | |
735 UNIMPLEMENTED(); | |
736 USE(cc); | |
737 USE(dst); | |
738 USE(imm32); | |
739 } | |
740 | |
741 | |
742 void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) { | |
743 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); | |
744 EnsureSpace ensure_space(this); | |
745 last_pc_ = pc_; | |
746 UNIMPLEMENTED(); | |
747 USE(cc); | |
748 USE(dst); | |
749 USE(handle); | |
750 } | |
751 | |
752 | |
753 void Assembler::cmov(Condition cc, Register dst, const Operand& src) { | |
754 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV)); | |
755 EnsureSpace ensure_space(this); | |
756 last_pc_ = pc_; | |
757 UNIMPLEMENTED(); | |
758 USE(cc); | |
759 USE(dst); | |
760 USE(src); | |
761 } | |
762 | |
763 | |
764 void Assembler::xchg(Register dst, Register src) { | |
765 EnsureSpace ensure_space(this); | |
766 last_pc_ = pc_; | |
767 if (src.is(eax) || dst.is(eax)) { // Single-byte encoding | |
768 EMIT(0x90 | (src.is(eax) ? dst.code() : src.code())); | |
769 } else { | |
770 EMIT(0x87); | |
771 EMIT(0xC0 | src.code() << 3 | dst.code()); | |
772 } | |
773 } | |
774 | |
775 | |
776 void Assembler::adc(Register dst, int32_t imm32) { | |
777 EnsureSpace ensure_space(this); | |
778 last_pc_ = pc_; | |
779 emit_arith(2, Operand(dst), Immediate(imm32)); | |
780 } | |
781 | |
782 | |
783 void Assembler::adc(Register dst, const Operand& src) { | |
784 EnsureSpace ensure_space(this); | |
785 last_pc_ = pc_; | |
786 EMIT(0x13); | |
787 emit_operand(dst, src); | |
788 } | |
789 | |
790 | |
791 void Assembler::add(Register dst, const Operand& src) { | |
792 EnsureSpace ensure_space(this); | |
793 last_pc_ = pc_; | |
794 EMIT(0x03); | |
795 emit_operand(dst, src); | |
796 } | |
797 | |
798 | |
799 void Assembler::add(const Operand& dst, const Immediate& x) { | |
800 ASSERT(reloc_info_writer.last_pc() != NULL); | |
801 if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { | |
802 byte instr = last_pc_[0]; | |
803 if ((instr & 0xf8) == 0x50) { | |
804 // Last instruction was a push. Check whether this is a pop without a | |
805 // result. | |
806 if ((dst.is_reg(esp)) && | |
807 (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) { | |
808 pc_ = last_pc_; | |
809 last_pc_ = NULL; | |
810 if (FLAG_print_push_pop_elimination) { | |
811 PrintF("%d push/pop(noreg) eliminated\n", pc_offset()); | |
812 } | |
813 return; | |
814 } | |
815 } | |
816 } | |
817 EnsureSpace ensure_space(this); | |
818 last_pc_ = pc_; | |
819 emit_arith(0, dst, x); | |
820 } | |
821 | |
822 | |
823 void Assembler::and_(Register dst, int32_t imm32) { | |
824 EnsureSpace ensure_space(this); | |
825 last_pc_ = pc_; | |
826 emit_arith(4, Operand(dst), Immediate(imm32)); | |
827 } | |
828 | |
829 | |
830 void Assembler::and_(Register dst, const Operand& src) { | |
831 EnsureSpace ensure_space(this); | |
832 last_pc_ = pc_; | |
833 EMIT(0x23); | |
834 emit_operand(dst, src); | |
835 } | |
836 | |
837 | |
838 void Assembler::and_(const Operand& dst, const Immediate& x) { | |
839 EnsureSpace ensure_space(this); | |
840 last_pc_ = pc_; | |
841 emit_arith(4, dst, x); | |
842 } | |
843 | |
844 | |
845 void Assembler::and_(const Operand& dst, Register src) { | |
846 EnsureSpace ensure_space(this); | |
847 last_pc_ = pc_; | |
848 EMIT(0x21); | |
849 emit_operand(src, dst); | |
850 } | |
851 | |
852 | |
853 void Assembler::cmpb(const Operand& op, int8_t imm8) { | |
854 EnsureSpace ensure_space(this); | |
855 last_pc_ = pc_; | |
856 EMIT(0x80); | |
857 emit_operand(edi, op); // edi == 7 | |
858 EMIT(imm8); | |
859 } | |
860 | |
861 | |
862 void Assembler::cmpw(const Operand& op, Immediate imm16) { | |
863 ASSERT(imm16.is_int16()); | |
864 EnsureSpace ensure_space(this); | |
865 last_pc_ = pc_; | |
866 EMIT(0x66); | |
867 EMIT(0x81); | |
868 emit_operand(edi, op); | |
869 emit_w(imm16); | |
870 } | |
871 | |
872 | |
873 void Assembler::cmp(Register reg, int32_t imm32) { | |
874 EnsureSpace ensure_space(this); | |
875 last_pc_ = pc_; | |
876 emit_arith(7, Operand(reg), Immediate(imm32)); | |
877 } | |
878 | |
879 | |
880 void Assembler::cmp(Register reg, Handle<Object> handle) { | |
881 EnsureSpace ensure_space(this); | |
882 last_pc_ = pc_; | |
883 emit_arith(7, Operand(reg), Immediate(handle)); | |
884 } | |
885 | |
886 | |
887 void Assembler::cmp(Register reg, const Operand& op) { | |
888 EnsureSpace ensure_space(this); | |
889 last_pc_ = pc_; | |
890 EMIT(0x3B); | |
891 emit_operand(reg, op); | |
892 } | |
893 | |
894 | |
895 void Assembler::cmp(const Operand& op, const Immediate& imm) { | |
896 EnsureSpace ensure_space(this); | |
897 last_pc_ = pc_; | |
898 emit_arith(7, op, imm); | |
899 } | |
900 | |
901 | |
902 void Assembler::cmpb_al(const Operand& op) { | |
903 EnsureSpace ensure_space(this); | |
904 last_pc_ = pc_; | |
905 EMIT(0x38); // CMP r/m8, r8 | |
906 emit_operand(eax, op); // eax has same code as register al. | |
907 } | |
908 | |
909 | |
910 void Assembler::cmpw_ax(const Operand& op) { | |
911 EnsureSpace ensure_space(this); | |
912 last_pc_ = pc_; | |
913 EMIT(0x66); | |
914 EMIT(0x39); // CMP r/m16, r16 | |
915 emit_operand(eax, op); // eax has same code as register ax. | |
916 } | |
917 | |
918 | |
919 void Assembler::dec_b(Register dst) { | |
920 EnsureSpace ensure_space(this); | |
921 last_pc_ = pc_; | |
922 EMIT(0xFE); | |
923 EMIT(0xC8 | dst.code()); | |
924 } | |
925 | |
926 | |
927 void Assembler::dec(Register dst) { | |
928 EnsureSpace ensure_space(this); | |
929 last_pc_ = pc_; | |
930 EMIT(0x48 | dst.code()); | |
931 } | |
932 | |
933 | |
934 void Assembler::dec(const Operand& dst) { | |
935 EnsureSpace ensure_space(this); | |
936 last_pc_ = pc_; | |
937 EMIT(0xFF); | |
938 emit_operand(ecx, dst); | |
939 } | |
940 | |
941 | |
942 void Assembler::cdq() { | |
943 EnsureSpace ensure_space(this); | |
944 last_pc_ = pc_; | |
945 EMIT(0x99); | |
946 } | |
947 | |
948 | |
949 void Assembler::idiv(Register src) { | |
950 EnsureSpace ensure_space(this); | |
951 last_pc_ = pc_; | |
952 EMIT(0xF7); | |
953 EMIT(0xF8 | src.code()); | |
954 } | |
955 | |
956 | |
957 void Assembler::imul(Register dst, const Operand& src) { | |
958 EnsureSpace ensure_space(this); | |
959 last_pc_ = pc_; | |
960 EMIT(0x0F); | |
961 EMIT(0xAF); | |
962 emit_operand(dst, src); | |
963 } | |
964 | |
965 | |
966 void Assembler::imul(Register dst, Register src, int32_t imm32) { | |
967 EnsureSpace ensure_space(this); | |
968 last_pc_ = pc_; | |
969 if (is_int8(imm32)) { | |
970 EMIT(0x6B); | |
971 EMIT(0xC0 | dst.code() << 3 | src.code()); | |
972 EMIT(imm32); | |
973 } else { | |
974 EMIT(0x69); | |
975 EMIT(0xC0 | dst.code() << 3 | src.code()); | |
976 emit(imm32); | |
977 } | |
978 } | |
979 | |
980 | |
981 void Assembler::inc(Register dst) { | |
982 EnsureSpace ensure_space(this); | |
983 last_pc_ = pc_; | |
984 EMIT(0x40 | dst.code()); | |
985 } | |
986 | |
987 | |
988 void Assembler::inc(const Operand& dst) { | |
989 EnsureSpace ensure_space(this); | |
990 last_pc_ = pc_; | |
991 EMIT(0xFF); | |
992 emit_operand(eax, dst); | |
993 } | |
994 | |
995 | |
996 void Assembler::lea(Register dst, const Operand& src) { | |
997 EnsureSpace ensure_space(this); | |
998 last_pc_ = pc_; | |
999 EMIT(0x8D); | |
1000 emit_operand(dst, src); | |
1001 } | |
1002 | |
1003 | |
1004 void Assembler::mul(Register src) { | |
1005 EnsureSpace ensure_space(this); | |
1006 last_pc_ = pc_; | |
1007 EMIT(0xF7); | |
1008 EMIT(0xE0 | src.code()); | |
1009 } | |
1010 | |
1011 | |
1012 void Assembler::neg(Register dst) { | |
1013 EnsureSpace ensure_space(this); | |
1014 last_pc_ = pc_; | |
1015 EMIT(0xF7); | |
1016 EMIT(0xD8 | dst.code()); | |
1017 } | |
1018 | |
1019 | |
1020 void Assembler::not_(Register dst) { | |
1021 EnsureSpace ensure_space(this); | |
1022 last_pc_ = pc_; | |
1023 EMIT(0xF7); | |
1024 EMIT(0xD0 | dst.code()); | |
1025 } | |
1026 | |
1027 | |
1028 void Assembler::or_(Register dst, int32_t imm32) { | |
1029 EnsureSpace ensure_space(this); | |
1030 last_pc_ = pc_; | |
1031 emit_arith(1, Operand(dst), Immediate(imm32)); | |
1032 } | |
1033 | |
1034 | |
1035 void Assembler::or_(Register dst, const Operand& src) { | |
1036 EnsureSpace ensure_space(this); | |
1037 last_pc_ = pc_; | |
1038 EMIT(0x0B); | |
1039 emit_operand(dst, src); | |
1040 } | |
1041 | |
1042 | |
1043 void Assembler::or_(const Operand& dst, const Immediate& x) { | |
1044 EnsureSpace ensure_space(this); | |
1045 last_pc_ = pc_; | |
1046 emit_arith(1, dst, x); | |
1047 } | |
1048 | |
1049 | |
1050 void Assembler::or_(const Operand& dst, Register src) { | |
1051 EnsureSpace ensure_space(this); | |
1052 last_pc_ = pc_; | |
1053 EMIT(0x09); | |
1054 emit_operand(src, dst); | |
1055 } | |
1056 | |
1057 | |
1058 void Assembler::rcl(Register dst, uint8_t imm8) { | |
1059 EnsureSpace ensure_space(this); | |
1060 last_pc_ = pc_; | |
1061 ASSERT(is_uint5(imm8)); // illegal shift count | |
1062 if (imm8 == 1) { | |
1063 EMIT(0xD1); | |
1064 EMIT(0xD0 | dst.code()); | |
1065 } else { | |
1066 EMIT(0xC1); | |
1067 EMIT(0xD0 | dst.code()); | |
1068 EMIT(imm8); | |
1069 } | |
1070 } | |
1071 | |
1072 | |
1073 void Assembler::sar(Register dst, uint8_t imm8) { | |
1074 EnsureSpace ensure_space(this); | |
1075 last_pc_ = pc_; | |
1076 ASSERT(is_uint5(imm8)); // illegal shift count | |
1077 if (imm8 == 1) { | |
1078 EMIT(0xD1); | |
1079 EMIT(0xF8 | dst.code()); | |
1080 } else { | |
1081 EMIT(0xC1); | |
1082 EMIT(0xF8 | dst.code()); | |
1083 EMIT(imm8); | |
1084 } | |
1085 } | |
1086 | |
1087 | |
1088 void Assembler::sar(Register dst) { | |
1089 EnsureSpace ensure_space(this); | |
1090 last_pc_ = pc_; | |
1091 EMIT(0xD3); | |
1092 EMIT(0xF8 | dst.code()); | |
1093 } | |
1094 | |
1095 | |
1096 void Assembler::sbb(Register dst, const Operand& src) { | |
1097 EnsureSpace ensure_space(this); | |
1098 last_pc_ = pc_; | |
1099 EMIT(0x1B); | |
1100 emit_operand(dst, src); | |
1101 } | |
1102 | |
1103 | |
1104 void Assembler::shld(Register dst, const Operand& src) { | |
1105 EnsureSpace ensure_space(this); | |
1106 last_pc_ = pc_; | |
1107 EMIT(0x0F); | |
1108 EMIT(0xA5); | |
1109 emit_operand(dst, src); | |
1110 } | |
1111 | |
1112 | |
1113 void Assembler::shl(Register dst, uint8_t imm8) { | |
1114 EnsureSpace ensure_space(this); | |
1115 last_pc_ = pc_; | |
1116 ASSERT(is_uint5(imm8)); // illegal shift count | |
1117 if (imm8 == 1) { | |
1118 EMIT(0xD1); | |
1119 EMIT(0xE0 | dst.code()); | |
1120 } else { | |
1121 EMIT(0xC1); | |
1122 EMIT(0xE0 | dst.code()); | |
1123 EMIT(imm8); | |
1124 } | |
1125 } | |
1126 | |
1127 | |
1128 void Assembler::shl(Register dst) { | |
1129 EnsureSpace ensure_space(this); | |
1130 last_pc_ = pc_; | |
1131 EMIT(0xD3); | |
1132 EMIT(0xE0 | dst.code()); | |
1133 } | |
1134 | |
1135 | |
1136 void Assembler::shrd(Register dst, const Operand& src) { | |
1137 EnsureSpace ensure_space(this); | |
1138 last_pc_ = pc_; | |
1139 EMIT(0x0F); | |
1140 EMIT(0xAD); | |
1141 emit_operand(dst, src); | |
1142 } | |
1143 | |
1144 | |
1145 void Assembler::shr(Register dst, uint8_t imm8) { | |
1146 EnsureSpace ensure_space(this); | |
1147 last_pc_ = pc_; | |
1148 ASSERT(is_uint5(imm8)); // illegal shift count | |
1149 EMIT(0xC1); | |
1150 EMIT(0xE8 | dst.code()); | |
1151 EMIT(imm8); | |
1152 } | |
1153 | |
1154 | |
1155 void Assembler::shr(Register dst) { | |
1156 EnsureSpace ensure_space(this); | |
1157 last_pc_ = pc_; | |
1158 EMIT(0xD3); | |
1159 EMIT(0xE8 | dst.code()); | |
1160 } | |
1161 | |
1162 | |
1163 void Assembler::shr_cl(Register dst) { | |
1164 EnsureSpace ensure_space(this); | |
1165 last_pc_ = pc_; | |
1166 EMIT(0xD1); | |
1167 EMIT(0xE8 | dst.code()); | |
1168 } | |
1169 | |
1170 | |
1171 void Assembler::sub(const Operand& dst, const Immediate& x) { | |
1172 EnsureSpace ensure_space(this); | |
1173 last_pc_ = pc_; | |
1174 emit_arith(5, dst, x); | |
1175 } | |
1176 | |
1177 | |
1178 void Assembler::sub(Register dst, const Operand& src) { | |
1179 EnsureSpace ensure_space(this); | |
1180 last_pc_ = pc_; | |
1181 EMIT(0x2B); | |
1182 emit_operand(dst, src); | |
1183 } | |
1184 | |
1185 | |
1186 void Assembler::sub(const Operand& dst, Register src) { | |
1187 EnsureSpace ensure_space(this); | |
1188 last_pc_ = pc_; | |
1189 EMIT(0x29); | |
1190 emit_operand(src, dst); | |
1191 } | |
1192 | |
1193 | |
1194 void Assembler::test(Register reg, const Immediate& imm) { | |
1195 EnsureSpace ensure_space(this); | |
1196 last_pc_ = pc_; | |
1197 // Only use test against byte for registers that have a byte | |
1198 // variant: eax, ebx, ecx, and edx. | |
1199 if (imm.rmode_ == RelocInfo::NONE && is_uint8(imm.x_) && reg.code() < 4) { | |
1200 uint8_t imm8 = imm.x_; | |
1201 if (reg.is(eax)) { | |
1202 EMIT(0xA8); | |
1203 EMIT(imm8); | |
1204 } else { | |
1205 emit_arith_b(0xF6, 0xC0, reg, imm8); | |
1206 } | |
1207 } else { | |
1208 // This is not using emit_arith because test doesn't support | |
1209 // sign-extension of 8-bit operands. | |
1210 if (reg.is(eax)) { | |
1211 EMIT(0xA9); | |
1212 } else { | |
1213 EMIT(0xF7); | |
1214 EMIT(0xC0 | reg.code()); | |
1215 } | |
1216 emit(imm); | |
1217 } | |
1218 } | |
1219 | |
1220 | |
1221 void Assembler::test(Register reg, const Operand& op) { | |
1222 EnsureSpace ensure_space(this); | |
1223 last_pc_ = pc_; | |
1224 EMIT(0x85); | |
1225 emit_operand(reg, op); | |
1226 } | |
1227 | |
1228 | |
1229 void Assembler::test(const Operand& op, const Immediate& imm) { | |
1230 EnsureSpace ensure_space(this); | |
1231 last_pc_ = pc_; | |
1232 EMIT(0xF7); | |
1233 emit_operand(eax, op); | |
1234 emit(imm); | |
1235 } | |
1236 | |
1237 | |
1238 void Assembler::xor_(Register dst, int32_t imm32) { | |
1239 EnsureSpace ensure_space(this); | |
1240 last_pc_ = pc_; | |
1241 emit_arith(6, Operand(dst), Immediate(imm32)); | |
1242 } | |
1243 | |
1244 | |
1245 void Assembler::xor_(Register dst, const Operand& src) { | |
1246 EnsureSpace ensure_space(this); | |
1247 last_pc_ = pc_; | |
1248 EMIT(0x33); | |
1249 emit_operand(dst, src); | |
1250 } | |
1251 | |
1252 | |
1253 void Assembler::xor_(const Operand& src, Register dst) { | |
1254 EnsureSpace ensure_space(this); | |
1255 last_pc_ = pc_; | |
1256 EMIT(0x31); | |
1257 emit_operand(dst, src); | |
1258 } | |
1259 | |
1260 | |
1261 void Assembler::xor_(const Operand& dst, const Immediate& x) { | |
1262 EnsureSpace ensure_space(this); | |
1263 last_pc_ = pc_; | |
1264 emit_arith(6, dst, x); | |
1265 } | |
1266 | |
1267 | |
1268 void Assembler::bt(const Operand& dst, Register src) { | |
1269 EnsureSpace ensure_space(this); | |
1270 last_pc_ = pc_; | |
1271 EMIT(0x0F); | |
1272 EMIT(0xA3); | |
1273 emit_operand(src, dst); | |
1274 } | |
1275 | |
1276 | |
1277 void Assembler::bts(const Operand& dst, Register src) { | |
1278 EnsureSpace ensure_space(this); | |
1279 last_pc_ = pc_; | |
1280 EMIT(0x0F); | |
1281 EMIT(0xAB); | |
1282 emit_operand(src, dst); | |
1283 } | |
1284 | |
1285 | |
1286 void Assembler::hlt() { | |
1287 EnsureSpace ensure_space(this); | |
1288 last_pc_ = pc_; | |
1289 EMIT(0xF4); | |
1290 } | |
1291 | |
1292 | |
1293 void Assembler::int3() { | |
1294 EnsureSpace ensure_space(this); | |
1295 last_pc_ = pc_; | |
1296 EMIT(0xCC); | |
1297 } | |
1298 | |
1299 | |
1300 void Assembler::nop() { | |
1301 EnsureSpace ensure_space(this); | |
1302 last_pc_ = pc_; | |
1303 EMIT(0x90); | |
1304 } | |
1305 | |
1306 | |
1307 void Assembler::rdtsc() { | |
1308 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::RDTSC)); | |
1309 EnsureSpace ensure_space(this); | |
1310 last_pc_ = pc_; | |
1311 EMIT(0x0F); | |
1312 EMIT(0x31); | |
1313 } | |
1314 | |
1315 | |
1316 void Assembler::ret(int imm16) { | |
1317 EnsureSpace ensure_space(this); | |
1318 last_pc_ = pc_; | |
1319 ASSERT(is_uint16(imm16)); | |
1320 if (imm16 == 0) { | |
1321 EMIT(0xC3); | |
1322 } else { | |
1323 EMIT(0xC2); | |
1324 EMIT(imm16 & 0xFF); | |
1325 EMIT((imm16 >> 8) & 0xFF); | |
1326 } | |
1327 } | |
1328 | |
1329 | |
1330 // Labels refer to positions in the (to be) generated code. | |
1331 // There are bound, linked, and unused labels. | |
1332 // | |
1333 // Bound labels refer to known positions in the already | |
1334 // generated code. pos() is the position the label refers to. | |
1335 // | |
1336 // Linked labels refer to unknown positions in the code | |
1337 // to be generated; pos() is the position of the 32bit | |
1338 // Displacement of the last instruction using the label. | |
1339 | |
1340 | |
1341 void Assembler::print(Label* L) { | |
1342 if (L->is_unused()) { | |
1343 PrintF("unused label\n"); | |
1344 } else if (L->is_bound()) { | |
1345 PrintF("bound label to %d\n", L->pos()); | |
1346 } else if (L->is_linked()) { | |
1347 Label l = *L; | |
1348 PrintF("unbound label"); | |
1349 while (l.is_linked()) { | |
1350 Displacement disp = disp_at(&l); | |
1351 PrintF("@ %d ", l.pos()); | |
1352 disp.print(); | |
1353 PrintF("\n"); | |
1354 disp.next(&l); | |
1355 } | |
1356 } else { | |
1357 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); | |
1358 } | |
1359 } | |
1360 | |
1361 | |
1362 void Assembler::bind_to(Label* L, int pos) { | |
1363 EnsureSpace ensure_space(this); | |
1364 last_pc_ = NULL; | |
1365 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position | |
1366 while (L->is_linked()) { | |
1367 Displacement disp = disp_at(L); | |
1368 int fixup_pos = L->pos(); | |
1369 if (disp.type() == Displacement::CODE_RELATIVE) { | |
1370 // Relative to Code* heap object pointer. | |
1371 long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag); | |
1372 } else { | |
1373 if (disp.type() == Displacement::UNCONDITIONAL_JUMP) { | |
1374 ASSERT(byte_at(fixup_pos - 1) == 0xE9); // jmp expected | |
1375 } | |
1376 // relative address, relative to point after address | |
1377 int imm32 = pos - (fixup_pos + sizeof(int32_t)); | |
1378 long_at_put(fixup_pos, imm32); | |
1379 } | |
1380 disp.next(L); | |
1381 } | |
1382 L->bind_to(pos); | |
1383 } | |
1384 | |
1385 | |
1386 void Assembler::link_to(Label* L, Label* appendix) { | |
1387 EnsureSpace ensure_space(this); | |
1388 last_pc_ = NULL; | |
1389 if (appendix->is_linked()) { | |
1390 if (L->is_linked()) { | |
1391 // append appendix to L's list | |
1392 Label p; | |
1393 Label q = *L; | |
1394 do { | |
1395 p = q; | |
1396 Displacement disp = disp_at(&q); | |
1397 disp.next(&q); | |
1398 } while (q.is_linked()); | |
1399 Displacement disp = disp_at(&p); | |
1400 disp.link_to(appendix); | |
1401 disp_at_put(&p, disp); | |
1402 p.Unuse(); // to avoid assertion failure in ~Label | |
1403 } else { | |
1404 // L is empty, simply use appendix | |
1405 *L = *appendix; | |
1406 } | |
1407 } | |
1408 appendix->Unuse(); // appendix should not be used anymore | |
1409 } | |
1410 | |
1411 | |
1412 void Assembler::bind(Label* L) { | |
1413 EnsureSpace ensure_space(this); | |
1414 last_pc_ = NULL; | |
1415 ASSERT(!L->is_bound()); // label can only be bound once | |
1416 bind_to(L, pc_offset()); | |
1417 } | |
1418 | |
1419 | |
1420 void Assembler::call(Label* L) { | |
1421 EnsureSpace ensure_space(this); | |
1422 last_pc_ = pc_; | |
1423 if (L->is_bound()) { | |
1424 const int long_size = 5; | |
1425 int offs = L->pos() - pc_offset(); | |
1426 ASSERT(offs <= 0); | |
1427 // 1110 1000 #32-bit disp | |
1428 EMIT(0xE8); | |
1429 emit(offs - long_size); | |
1430 } else { | |
1431 // 1110 1000 #32-bit disp | |
1432 EMIT(0xE8); | |
1433 emit_disp(L, Displacement::OTHER); | |
1434 } | |
1435 } | |
1436 | |
1437 | |
1438 void Assembler::call(byte* entry, RelocInfo::Mode rmode) { | |
1439 EnsureSpace ensure_space(this); | |
1440 last_pc_ = pc_; | |
1441 ASSERT(!RelocInfo::IsCodeTarget(rmode)); | |
1442 EMIT(0xE8); | |
1443 emit(entry - (pc_ + sizeof(int32_t)), rmode); | |
1444 } | |
1445 | |
1446 | |
1447 void Assembler::call(const Operand& adr) { | |
1448 EnsureSpace ensure_space(this); | |
1449 last_pc_ = pc_; | |
1450 EMIT(0xFF); | |
1451 emit_operand(edx, adr); | |
1452 } | |
1453 | |
1454 | |
1455 void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) { | |
1456 WriteRecordedPositions(); | |
1457 EnsureSpace ensure_space(this); | |
1458 last_pc_ = pc_; | |
1459 ASSERT(RelocInfo::IsCodeTarget(rmode)); | |
1460 EMIT(0xE8); | |
1461 emit(reinterpret_cast<intptr_t>(code.location()), rmode); | |
1462 } | |
1463 | |
1464 | |
1465 void Assembler::jmp(Label* L) { | |
1466 EnsureSpace ensure_space(this); | |
1467 last_pc_ = pc_; | |
1468 if (L->is_bound()) { | |
1469 const int short_size = 2; | |
1470 const int long_size = 5; | |
1471 int offs = L->pos() - pc_offset(); | |
1472 ASSERT(offs <= 0); | |
1473 if (is_int8(offs - short_size)) { | |
1474 // 1110 1011 #8-bit disp | |
1475 EMIT(0xEB); | |
1476 EMIT((offs - short_size) & 0xFF); | |
1477 } else { | |
1478 // 1110 1001 #32-bit disp | |
1479 EMIT(0xE9); | |
1480 emit(offs - long_size); | |
1481 } | |
1482 } else { | |
1483 // 1110 1001 #32-bit disp | |
1484 EMIT(0xE9); | |
1485 emit_disp(L, Displacement::UNCONDITIONAL_JUMP); | |
1486 } | |
1487 } | |
1488 | |
1489 | |
1490 void Assembler::jmp(byte* entry, RelocInfo::Mode rmode) { | |
1491 EnsureSpace ensure_space(this); | |
1492 last_pc_ = pc_; | |
1493 ASSERT(!RelocInfo::IsCodeTarget(rmode)); | |
1494 EMIT(0xE9); | |
1495 emit(entry - (pc_ + sizeof(int32_t)), rmode); | |
1496 } | |
1497 | |
1498 | |
1499 void Assembler::jmp(const Operand& adr) { | |
1500 EnsureSpace ensure_space(this); | |
1501 last_pc_ = pc_; | |
1502 EMIT(0xFF); | |
1503 emit_operand(esp, adr); | |
1504 } | |
1505 | |
1506 | |
1507 void Assembler::jmp(Handle<Code> code, RelocInfo::Mode rmode) { | |
1508 EnsureSpace ensure_space(this); | |
1509 last_pc_ = pc_; | |
1510 ASSERT(RelocInfo::IsCodeTarget(rmode)); | |
1511 EMIT(0xE9); | |
1512 emit(reinterpret_cast<intptr_t>(code.location()), rmode); | |
1513 } | |
1514 | |
1515 | |
1516 | |
1517 void Assembler::j(Condition cc, Label* L, Hint hint) { | |
1518 EnsureSpace ensure_space(this); | |
1519 last_pc_ = pc_; | |
1520 ASSERT(0 <= cc && cc < 16); | |
1521 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); | |
1522 if (L->is_bound()) { | |
1523 const int short_size = 2; | |
1524 const int long_size = 6; | |
1525 int offs = L->pos() - pc_offset(); | |
1526 ASSERT(offs <= 0); | |
1527 if (is_int8(offs - short_size)) { | |
1528 // 0111 tttn #8-bit disp | |
1529 EMIT(0x70 | cc); | |
1530 EMIT((offs - short_size) & 0xFF); | |
1531 } else { | |
1532 // 0000 1111 1000 tttn #32-bit disp | |
1533 EMIT(0x0F); | |
1534 EMIT(0x80 | cc); | |
1535 emit(offs - long_size); | |
1536 } | |
1537 } else { | |
1538 // 0000 1111 1000 tttn #32-bit disp | |
1539 // Note: could eliminate cond. jumps to this jump if condition | |
1540 // is the same however, seems to be rather unlikely case. | |
1541 EMIT(0x0F); | |
1542 EMIT(0x80 | cc); | |
1543 emit_disp(L, Displacement::OTHER); | |
1544 } | |
1545 } | |
1546 | |
1547 | |
1548 void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint) { | |
1549 EnsureSpace ensure_space(this); | |
1550 last_pc_ = pc_; | |
1551 ASSERT((0 <= cc) && (cc < 16)); | |
1552 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); | |
1553 // 0000 1111 1000 tttn #32-bit disp | |
1554 EMIT(0x0F); | |
1555 EMIT(0x80 | cc); | |
1556 emit(entry - (pc_ + sizeof(int32_t)), rmode); | |
1557 } | |
1558 | |
1559 | |
1560 void Assembler::j(Condition cc, Handle<Code> code, Hint hint) { | |
1561 EnsureSpace ensure_space(this); | |
1562 last_pc_ = pc_; | |
1563 if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint); | |
1564 // 0000 1111 1000 tttn #32-bit disp | |
1565 EMIT(0x0F); | |
1566 EMIT(0x80 | cc); | |
1567 emit(reinterpret_cast<intptr_t>(code.location()), RelocInfo::CODE_TARGET); | |
1568 } | |
1569 | |
1570 | |
1571 // FPU instructions | |
1572 | |
1573 | |
1574 void Assembler::fld(int i) { | |
1575 EnsureSpace ensure_space(this); | |
1576 last_pc_ = pc_; | |
1577 emit_farith(0xD9, 0xC0, i); | |
1578 } | |
1579 | |
1580 | |
1581 void Assembler::fld1() { | |
1582 EnsureSpace ensure_space(this); | |
1583 last_pc_ = pc_; | |
1584 EMIT(0xD9); | |
1585 EMIT(0xE8); | |
1586 } | |
1587 | |
1588 | |
1589 void Assembler::fldz() { | |
1590 EnsureSpace ensure_space(this); | |
1591 last_pc_ = pc_; | |
1592 EMIT(0xD9); | |
1593 EMIT(0xEE); | |
1594 } | |
1595 | |
1596 | |
1597 void Assembler::fld_s(const Operand& adr) { | |
1598 EnsureSpace ensure_space(this); | |
1599 last_pc_ = pc_; | |
1600 EMIT(0xD9); | |
1601 emit_operand(eax, adr); | |
1602 } | |
1603 | |
1604 | |
1605 void Assembler::fld_d(const Operand& adr) { | |
1606 EnsureSpace ensure_space(this); | |
1607 last_pc_ = pc_; | |
1608 EMIT(0xDD); | |
1609 emit_operand(eax, adr); | |
1610 } | |
1611 | |
1612 | |
1613 void Assembler::fstp_s(const Operand& adr) { | |
1614 EnsureSpace ensure_space(this); | |
1615 last_pc_ = pc_; | |
1616 EMIT(0xD9); | |
1617 emit_operand(ebx, adr); | |
1618 } | |
1619 | |
1620 | |
1621 void Assembler::fstp_d(const Operand& adr) { | |
1622 EnsureSpace ensure_space(this); | |
1623 last_pc_ = pc_; | |
1624 EMIT(0xDD); | |
1625 emit_operand(ebx, adr); | |
1626 } | |
1627 | |
1628 | |
1629 void Assembler::fild_s(const Operand& adr) { | |
1630 EnsureSpace ensure_space(this); | |
1631 last_pc_ = pc_; | |
1632 EMIT(0xDB); | |
1633 emit_operand(eax, adr); | |
1634 } | |
1635 | |
1636 | |
1637 void Assembler::fild_d(const Operand& adr) { | |
1638 EnsureSpace ensure_space(this); | |
1639 last_pc_ = pc_; | |
1640 EMIT(0xDF); | |
1641 emit_operand(ebp, adr); | |
1642 } | |
1643 | |
1644 | |
1645 void Assembler::fistp_s(const Operand& adr) { | |
1646 EnsureSpace ensure_space(this); | |
1647 last_pc_ = pc_; | |
1648 EMIT(0xDB); | |
1649 emit_operand(ebx, adr); | |
1650 } | |
1651 | |
1652 | |
1653 void Assembler::fisttp_s(const Operand& adr) { | |
1654 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE3)); | |
1655 EnsureSpace ensure_space(this); | |
1656 last_pc_ = pc_; | |
1657 EMIT(0xDB); | |
1658 emit_operand(ecx, adr); | |
1659 } | |
1660 | |
1661 | |
1662 void Assembler::fist_s(const Operand& adr) { | |
1663 EnsureSpace ensure_space(this); | |
1664 last_pc_ = pc_; | |
1665 EMIT(0xDB); | |
1666 emit_operand(edx, adr); | |
1667 } | |
1668 | |
1669 | |
1670 void Assembler::fistp_d(const Operand& adr) { | |
1671 EnsureSpace ensure_space(this); | |
1672 last_pc_ = pc_; | |
1673 EMIT(0xDF); | |
1674 emit_operand(edi, adr); | |
1675 } | |
1676 | |
1677 | |
1678 void Assembler::fabs() { | |
1679 EnsureSpace ensure_space(this); | |
1680 last_pc_ = pc_; | |
1681 EMIT(0xD9); | |
1682 EMIT(0xE1); | |
1683 } | |
1684 | |
1685 | |
1686 void Assembler::fchs() { | |
1687 EnsureSpace ensure_space(this); | |
1688 last_pc_ = pc_; | |
1689 EMIT(0xD9); | |
1690 EMIT(0xE0); | |
1691 } | |
1692 | |
1693 | |
1694 void Assembler::fadd(int i) { | |
1695 EnsureSpace ensure_space(this); | |
1696 last_pc_ = pc_; | |
1697 emit_farith(0xDC, 0xC0, i); | |
1698 } | |
1699 | |
1700 | |
1701 void Assembler::fsub(int i) { | |
1702 EnsureSpace ensure_space(this); | |
1703 last_pc_ = pc_; | |
1704 emit_farith(0xDC, 0xE8, i); | |
1705 } | |
1706 | |
1707 | |
1708 void Assembler::fisub_s(const Operand& adr) { | |
1709 EnsureSpace ensure_space(this); | |
1710 last_pc_ = pc_; | |
1711 EMIT(0xDA); | |
1712 emit_operand(esp, adr); | |
1713 } | |
1714 | |
1715 | |
1716 void Assembler::fmul(int i) { | |
1717 EnsureSpace ensure_space(this); | |
1718 last_pc_ = pc_; | |
1719 emit_farith(0xDC, 0xC8, i); | |
1720 } | |
1721 | |
1722 | |
1723 void Assembler::fdiv(int i) { | |
1724 EnsureSpace ensure_space(this); | |
1725 last_pc_ = pc_; | |
1726 emit_farith(0xDC, 0xF8, i); | |
1727 } | |
1728 | |
1729 | |
1730 void Assembler::faddp(int i) { | |
1731 EnsureSpace ensure_space(this); | |
1732 last_pc_ = pc_; | |
1733 emit_farith(0xDE, 0xC0, i); | |
1734 } | |
1735 | |
1736 | |
1737 void Assembler::fsubp(int i) { | |
1738 EnsureSpace ensure_space(this); | |
1739 last_pc_ = pc_; | |
1740 emit_farith(0xDE, 0xE8, i); | |
1741 } | |
1742 | |
1743 | |
1744 void Assembler::fsubrp(int i) { | |
1745 EnsureSpace ensure_space(this); | |
1746 last_pc_ = pc_; | |
1747 emit_farith(0xDE, 0xE0, i); | |
1748 } | |
1749 | |
1750 | |
1751 void Assembler::fmulp(int i) { | |
1752 EnsureSpace ensure_space(this); | |
1753 last_pc_ = pc_; | |
1754 emit_farith(0xDE, 0xC8, i); | |
1755 } | |
1756 | |
1757 | |
1758 void Assembler::fdivp(int i) { | |
1759 EnsureSpace ensure_space(this); | |
1760 last_pc_ = pc_; | |
1761 emit_farith(0xDE, 0xF8, i); | |
1762 } | |
1763 | |
1764 | |
1765 void Assembler::fprem() { | |
1766 EnsureSpace ensure_space(this); | |
1767 last_pc_ = pc_; | |
1768 EMIT(0xD9); | |
1769 EMIT(0xF8); | |
1770 } | |
1771 | |
1772 | |
1773 void Assembler::fprem1() { | |
1774 EnsureSpace ensure_space(this); | |
1775 last_pc_ = pc_; | |
1776 EMIT(0xD9); | |
1777 EMIT(0xF5); | |
1778 } | |
1779 | |
1780 | |
1781 void Assembler::fxch(int i) { | |
1782 EnsureSpace ensure_space(this); | |
1783 last_pc_ = pc_; | |
1784 emit_farith(0xD9, 0xC8, i); | |
1785 } | |
1786 | |
1787 | |
1788 void Assembler::fincstp() { | |
1789 EnsureSpace ensure_space(this); | |
1790 last_pc_ = pc_; | |
1791 EMIT(0xD9); | |
1792 EMIT(0xF7); | |
1793 } | |
1794 | |
1795 | |
1796 void Assembler::ffree(int i) { | |
1797 EnsureSpace ensure_space(this); | |
1798 last_pc_ = pc_; | |
1799 emit_farith(0xDD, 0xC0, i); | |
1800 } | |
1801 | |
1802 | |
1803 void Assembler::ftst() { | |
1804 EnsureSpace ensure_space(this); | |
1805 last_pc_ = pc_; | |
1806 EMIT(0xD9); | |
1807 EMIT(0xE4); | |
1808 } | |
1809 | |
1810 | |
1811 void Assembler::fucomp(int i) { | |
1812 EnsureSpace ensure_space(this); | |
1813 last_pc_ = pc_; | |
1814 emit_farith(0xDD, 0xE8, i); | |
1815 } | |
1816 | |
1817 | |
1818 void Assembler::fucompp() { | |
1819 EnsureSpace ensure_space(this); | |
1820 last_pc_ = pc_; | |
1821 EMIT(0xDA); | |
1822 EMIT(0xE9); | |
1823 } | |
1824 | |
1825 | |
1826 void Assembler::fcompp() { | |
1827 EnsureSpace ensure_space(this); | |
1828 last_pc_ = pc_; | |
1829 EMIT(0xDE); | |
1830 EMIT(0xD9); | |
1831 } | |
1832 | |
1833 | |
1834 void Assembler::fnstsw_ax() { | |
1835 EnsureSpace ensure_space(this); | |
1836 last_pc_ = pc_; | |
1837 EMIT(0xdF); | |
1838 EMIT(0xE0); | |
1839 } | |
1840 | |
1841 | |
1842 void Assembler::fwait() { | |
1843 EnsureSpace ensure_space(this); | |
1844 last_pc_ = pc_; | |
1845 EMIT(0x9B); | |
1846 } | |
1847 | |
1848 | |
1849 void Assembler::frndint() { | |
1850 EnsureSpace ensure_space(this); | |
1851 last_pc_ = pc_; | |
1852 EMIT(0xD9); | |
1853 EMIT(0xFC); | |
1854 } | |
1855 | |
1856 | |
1857 void Assembler::fnclex() { | |
1858 EnsureSpace ensure_space(this); | |
1859 last_pc_ = pc_; | |
1860 EMIT(0xDB); | |
1861 EMIT(0xE2); | |
1862 } | |
1863 | |
1864 | |
1865 void Assembler::sahf() { | |
1866 EnsureSpace ensure_space(this); | |
1867 last_pc_ = pc_; | |
1868 EMIT(0x9E); | |
1869 } | |
1870 | |
1871 | |
1872 void Assembler::setcc(Condition cc, Register reg) { | |
1873 ASSERT(reg.is_byte_register()); | |
1874 EnsureSpace ensure_space(this); | |
1875 last_pc_ = pc_; | |
1876 EMIT(0x0F); | |
1877 EMIT(0x90 | cc); | |
1878 EMIT(0xC0 | reg.code()); | |
1879 } | |
1880 | |
1881 | |
1882 void Assembler::cvttss2si(Register dst, const Operand& src) { | |
1883 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1884 EnsureSpace ensure_space(this); | |
1885 last_pc_ = pc_; | |
1886 EMIT(0xF3); | |
1887 EMIT(0x0F); | |
1888 EMIT(0x2C); | |
1889 emit_operand(dst, src); | |
1890 } | |
1891 | |
1892 | |
1893 void Assembler::cvttsd2si(Register dst, const Operand& src) { | |
1894 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1895 EnsureSpace ensure_space(this); | |
1896 last_pc_ = pc_; | |
1897 EMIT(0xF2); | |
1898 EMIT(0x0F); | |
1899 EMIT(0x2C); | |
1900 emit_operand(dst, src); | |
1901 } | |
1902 | |
1903 | |
1904 void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) { | |
1905 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1906 EnsureSpace ensure_space(this); | |
1907 last_pc_ = pc_; | |
1908 EMIT(0xF2); | |
1909 EMIT(0x0F); | |
1910 EMIT(0x2A); | |
1911 emit_sse_operand(dst, src); | |
1912 } | |
1913 | |
1914 | |
1915 void Assembler::addsd(XMMRegister dst, XMMRegister src) { | |
1916 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1917 EnsureSpace ensure_space(this); | |
1918 last_pc_ = pc_; | |
1919 EMIT(0xF2); | |
1920 EMIT(0x0F); | |
1921 EMIT(0x58); | |
1922 emit_sse_operand(dst, src); | |
1923 } | |
1924 | |
1925 | |
1926 void Assembler::mulsd(XMMRegister dst, XMMRegister src) { | |
1927 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1928 EnsureSpace ensure_space(this); | |
1929 last_pc_ = pc_; | |
1930 EMIT(0xF2); | |
1931 EMIT(0x0F); | |
1932 EMIT(0x59); | |
1933 emit_sse_operand(dst, src); | |
1934 } | |
1935 | |
1936 | |
1937 void Assembler::subsd(XMMRegister dst, XMMRegister src) { | |
1938 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1939 EnsureSpace ensure_space(this); | |
1940 last_pc_ = pc_; | |
1941 EMIT(0xF2); | |
1942 EMIT(0x0F); | |
1943 EMIT(0x5C); | |
1944 emit_sse_operand(dst, src); | |
1945 } | |
1946 | |
1947 | |
1948 void Assembler::divsd(XMMRegister dst, XMMRegister src) { | |
1949 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1950 EnsureSpace ensure_space(this); | |
1951 last_pc_ = pc_; | |
1952 EMIT(0xF2); | |
1953 EMIT(0x0F); | |
1954 EMIT(0x5E); | |
1955 emit_sse_operand(dst, src); | |
1956 } | |
1957 | |
1958 | |
1959 void Assembler::movdbl(XMMRegister dst, const Operand& src) { | |
1960 EnsureSpace ensure_space(this); | |
1961 last_pc_ = pc_; | |
1962 movsd(dst, src); | |
1963 } | |
1964 | |
1965 | |
1966 void Assembler::movdbl(const Operand& dst, XMMRegister src) { | |
1967 EnsureSpace ensure_space(this); | |
1968 last_pc_ = pc_; | |
1969 movsd(dst, src); | |
1970 } | |
1971 | |
1972 | |
1973 void Assembler::movsd(const Operand& dst, XMMRegister src ) { | |
1974 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1975 EnsureSpace ensure_space(this); | |
1976 last_pc_ = pc_; | |
1977 EMIT(0xF2); // double | |
1978 EMIT(0x0F); | |
1979 EMIT(0x11); // store | |
1980 emit_sse_operand(src, dst); | |
1981 } | |
1982 | |
1983 | |
1984 void Assembler::movsd(XMMRegister dst, const Operand& src) { | |
1985 ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2)); | |
1986 EnsureSpace ensure_space(this); | |
1987 last_pc_ = pc_; | |
1988 EMIT(0xF2); // double | |
1989 EMIT(0x0F); | |
1990 EMIT(0x10); // load | |
1991 emit_sse_operand(dst, src); | |
1992 } | |
1993 | |
1994 | |
1995 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) { | |
1996 Register ireg = { reg.code() }; | |
1997 emit_operand(ireg, adr); | |
1998 } | |
1999 | |
2000 | |
2001 void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) { | |
2002 EMIT(0xC0 | dst.code() << 3 | src.code()); | |
2003 } | |
2004 | |
2005 | |
2006 void Assembler::Print() { | |
2007 Disassembler::Decode(stdout, buffer_, pc_); | |
2008 } | |
2009 | |
2010 | |
2011 void Assembler::RecordJSReturn() { | |
2012 WriteRecordedPositions(); | |
2013 EnsureSpace ensure_space(this); | |
2014 RecordRelocInfo(RelocInfo::JS_RETURN); | |
2015 } | |
2016 | |
2017 | |
2018 void Assembler::RecordComment(const char* msg) { | |
2019 if (FLAG_debug_code) { | |
2020 EnsureSpace ensure_space(this); | |
2021 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); | |
2022 } | |
2023 } | |
2024 | |
2025 | |
2026 void Assembler::RecordPosition(int pos) { | |
2027 ASSERT(pos != RelocInfo::kNoPosition); | |
2028 ASSERT(pos >= 0); | |
2029 current_position_ = pos; | |
2030 } | |
2031 | |
2032 | |
2033 void Assembler::RecordStatementPosition(int pos) { | |
2034 ASSERT(pos != RelocInfo::kNoPosition); | |
2035 ASSERT(pos >= 0); | |
2036 current_statement_position_ = pos; | |
2037 } | |
2038 | |
2039 | |
2040 void Assembler::WriteRecordedPositions() { | |
2041 // Write the statement position if it is different from what was written last | |
2042 // time. | |
2043 if (current_statement_position_ != written_statement_position_) { | |
2044 EnsureSpace ensure_space(this); | |
2045 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_); | |
2046 written_statement_position_ = current_statement_position_; | |
2047 } | |
2048 | |
2049 // Write the position if it is different from what was written last time and | |
2050 // also different from the written statement position. | |
2051 if (current_position_ != written_position_ && | |
2052 current_position_ != written_statement_position_) { | |
2053 EnsureSpace ensure_space(this); | |
2054 RecordRelocInfo(RelocInfo::POSITION, current_position_); | |
2055 written_position_ = current_position_; | |
2056 } | |
2057 } | |
2058 | |
2059 | |
2060 void Assembler::GrowBuffer() { | |
2061 ASSERT(overflow()); // should not call this otherwise | |
2062 if (!own_buffer_) FATAL("external code buffer is too small"); | |
2063 | |
2064 // compute new buffer size | |
2065 CodeDesc desc; // the new buffer | |
2066 if (buffer_size_ < 4*KB) { | |
2067 desc.buffer_size = 4*KB; | |
2068 } else { | |
2069 desc.buffer_size = 2*buffer_size_; | |
2070 } | |
2071 // Some internal data structures overflow for very large buffers, | |
2072 // they must ensure that kMaximalBufferSize is not too large. | |
2073 if ((desc.buffer_size > kMaximalBufferSize) || | |
2074 (desc.buffer_size > Heap::OldGenerationSize())) { | |
2075 V8::FatalProcessOutOfMemory("Assembler::GrowBuffer"); | |
2076 } | |
2077 | |
2078 // setup new buffer | |
2079 desc.buffer = NewArray<byte>(desc.buffer_size); | |
2080 desc.instr_size = pc_offset(); | |
2081 desc.reloc_size = (buffer_ + buffer_size_) - (reloc_info_writer.pos()); | |
2082 | |
2083 // Clear the buffer in debug mode. Use 'int3' instructions to make | |
2084 // sure to get into problems if we ever run uninitialized code. | |
2085 #ifdef DEBUG | |
2086 memset(desc.buffer, 0xCC, desc.buffer_size); | |
2087 #endif | |
2088 | |
2089 // copy the data | |
2090 int pc_delta = desc.buffer - buffer_; | |
2091 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); | |
2092 memmove(desc.buffer, buffer_, desc.instr_size); | |
2093 memmove(rc_delta + reloc_info_writer.pos(), | |
2094 reloc_info_writer.pos(), desc.reloc_size); | |
2095 | |
2096 // switch buffers | |
2097 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { | |
2098 spare_buffer_ = buffer_; | |
2099 } else { | |
2100 DeleteArray(buffer_); | |
2101 } | |
2102 buffer_ = desc.buffer; | |
2103 buffer_size_ = desc.buffer_size; | |
2104 pc_ += pc_delta; | |
2105 if (last_pc_ != NULL) { | |
2106 last_pc_ += pc_delta; | |
2107 } | |
2108 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, | |
2109 reloc_info_writer.last_pc() + pc_delta); | |
2110 | |
2111 // relocate runtime entries | |
2112 for (RelocIterator it(desc); !it.done(); it.next()) { | |
2113 RelocInfo::Mode rmode = it.rinfo()->rmode(); | |
2114 if (rmode == RelocInfo::RUNTIME_ENTRY) { | |
2115 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc()); | |
2116 *p -= pc_delta; // relocate entry | |
2117 } else if (rmode == RelocInfo::INTERNAL_REFERENCE) { | |
2118 int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc()); | |
2119 if (*p != 0) { // 0 means uninitialized. | |
2120 *p += pc_delta; | |
2121 } | |
2122 } | |
2123 } | |
2124 | |
2125 ASSERT(!overflow()); | |
2126 } | |
2127 | |
2128 | |
2129 void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { | |
2130 ASSERT(is_uint8(op1) && is_uint8(op2)); // wrong opcode | |
2131 ASSERT(is_uint8(imm8)); | |
2132 ASSERT((op1 & 0x01) == 0); // should be 8bit operation | |
2133 EMIT(op1); | |
2134 EMIT(op2 | dst.code()); | |
2135 EMIT(imm8); | |
2136 } | |
2137 | |
2138 | |
2139 void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) { | |
2140 ASSERT((0 <= sel) && (sel <= 7)); | |
2141 Register ireg = { sel }; | |
2142 if (x.is_int8()) { | |
2143 EMIT(0x83); // using a sign-extended 8-bit immediate. | |
2144 emit_operand(ireg, dst); | |
2145 EMIT(x.x_ & 0xFF); | |
2146 } else if (dst.is_reg(eax)) { | |
2147 EMIT((sel << 3) | 0x05); // short form if the destination is eax. | |
2148 emit(x); | |
2149 } else { | |
2150 EMIT(0x81); // using a literal 32-bit immediate. | |
2151 emit_operand(ireg, dst); | |
2152 emit(x); | |
2153 } | |
2154 } | |
2155 | |
2156 | |
2157 void Assembler::emit_operand(Register reg, const Operand& adr) { | |
2158 const unsigned length = adr.len_; | |
2159 ASSERT(length > 0); | |
2160 | |
2161 // Emit updated ModRM byte containing the given register. | |
2162 pc_[0] = (adr.buf_[0] & ~0x38) | (reg.code() << 3); | |
2163 | |
2164 // Emit the rest of the encoded operand. | |
2165 for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i]; | |
2166 pc_ += length; | |
2167 | |
2168 // Emit relocation information if necessary. | |
2169 if (length >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) { | |
2170 pc_ -= sizeof(int32_t); // pc_ must be *at* disp32 | |
2171 RecordRelocInfo(adr.rmode_); | |
2172 pc_ += sizeof(int32_t); | |
2173 } | |
2174 } | |
2175 | |
2176 | |
2177 void Assembler::emit_farith(int b1, int b2, int i) { | |
2178 ASSERT(is_uint8(b1) && is_uint8(b2)); // wrong opcode | |
2179 ASSERT(0 <= i && i < 8); // illegal stack offset | |
2180 EMIT(b1); | |
2181 EMIT(b2 + i); | |
2182 } | |
2183 | |
2184 | |
2185 void Assembler::dd(uint32_t data, RelocInfo::Mode reloc_info) { | |
2186 EnsureSpace ensure_space(this); | |
2187 emit(data, reloc_info); | |
2188 } | |
2189 | |
2190 | |
2191 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { | |
2192 ASSERT(rmode != RelocInfo::NONE); | |
2193 // Don't record external references unless the heap will be serialized. | |
2194 if (rmode == RelocInfo::EXTERNAL_REFERENCE && | |
2195 !Serializer::enabled() && | |
2196 !FLAG_debug_code) { | |
2197 return; | |
2198 } | |
2199 RelocInfo rinfo(pc_, rmode, data); | |
2200 reloc_info_writer.Write(&rinfo); | |
2201 } | |
2202 | |
2203 | |
2204 void Assembler::WriteInternalReference(int position, const Label& bound_label) { | |
2205 ASSERT(bound_label.is_bound()); | |
2206 ASSERT(0 <= position); | |
2207 ASSERT(position + static_cast<int>(sizeof(uint32_t)) <= pc_offset()); | |
2208 ASSERT(long_at(position) == 0); // only initialize once! | |
2209 | |
2210 uint32_t label_loc = reinterpret_cast<uint32_t>(addr_at(bound_label.pos())); | |
2211 long_at_put(position, label_loc); | |
2212 } | |
2213 | |
2214 | |
2215 #ifdef GENERATED_CODE_COVERAGE | |
2216 static FILE* coverage_log = NULL; | |
2217 | |
2218 | |
2219 static void InitCoverageLog() { | |
2220 char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); | |
2221 if (file_name != NULL) { | |
2222 coverage_log = fopen(file_name, "aw+"); | |
2223 } | |
2224 } | |
2225 | |
2226 | |
2227 void LogGeneratedCodeCoverage(const char* file_line) { | |
2228 const char* return_address = (&file_line)[-1]; | |
2229 char* push_insn = const_cast<char*>(return_address - 12); | |
2230 push_insn[0] = 0xeb; // Relative branch insn. | |
2231 push_insn[1] = 13; // Skip over coverage insns. | |
2232 if (coverage_log != NULL) { | |
2233 fprintf(coverage_log, "%s\n", file_line); | |
2234 fflush(coverage_log); | |
2235 } | |
2236 } | |
2237 | |
2238 #endif | |
2239 | |
2240 } } // namespace v8::internal | |
OLD | NEW |