• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/assembler/x64/assembler_x64.h"
17 
18 namespace panda::ecmascript::x64 {
Pushq(Register x)19 void AssemblerX64::Pushq(Register x)
20 {
21     EmitRexPrefix(x);
22     // 0x50: Push r16
23     EmitU8(0x50 | LowBits(x));
24 }
25 
Pushq(Immediate x)26 void AssemblerX64::Pushq(Immediate x)
27 {
28     if (InRange8(x.Value())) {
29         // 6A: Push imm8
30         EmitU8(0x6A);
31         EmitI8(static_cast<int8_t>(x.Value()));
32     } else {
33         // 68: Push imm32
34         EmitU8(0x68);
35         EmitI32(x.Value());
36     }
37 }
38 
Push(Register x)39 void AssemblerX64::Push(Register x)
40 {
41     Pushq(x);
42 }
43 
Popq(Register x)44 void AssemblerX64::Popq(Register x)
45 {
46     EmitRexPrefix(x);
47     // 0x58: Pop r16
48     EmitU8(0x58 | LowBits(x));
49 }
50 
Pop(Register x)51 void AssemblerX64::Pop(Register x)
52 {
53     Popq(x);
54 }
55 
56 
Addq(Immediate src,Register dst)57 void AssemblerX64::Addq(Immediate src, Register dst)
58 {
59     EmitRexPrefixW(dst);
60     if (InRange8(src.Value())) {
61         // 83: Add r/m16, imm8
62         EmitU8(0x83);
63         // 0: 83 /0 ib
64         EmitModrm(0, dst);
65         EmitI8(static_cast<int8_t>(src.Value()));
66     } else if (dst == rax) {
67         // 0x5: Add rax, imm32
68         EmitU8(0x5);
69         EmitI32(src.Value());
70     } else {
71         // 81: Add r/m32, imm32
72         EmitU8(0x81);
73         // 0: 81 /0 id
74         EmitModrm(0, dst);
75         EmitI32(src.Value());
76     }
77 }
78 
Addq(Register src,Register dst)79 void AssemblerX64::Addq(Register src, Register dst)
80 {
81     EmitRexPrefix(dst, src);
82     // 03 : add r64, r/m64
83     EmitU8(0x03);
84     EmitModrm(dst, src);
85 }
86 
Addl(Immediate src,Register dst)87 void AssemblerX64::Addl(Immediate src, Register dst)
88 {
89     EmitRexPrefix(dst);
90     if (InRange8(src.Value())) {
91         // 83: Add r/m16, imm8
92         EmitU8(0x83);
93         // 0: 83 /0 ib
94         EmitModrm(0, dst);
95         EmitI8(static_cast<int8_t>(src.Value()));
96     } else if (dst == rax) {
97         // 0x5: Add rax, imm32
98         EmitU8(0x5);
99         EmitI32(src.Value());
100     } else {
101         // 81: Add r/m32, imm32
102         EmitU8(0x81);
103         // 0: 81 /0 id
104         EmitModrm(0, dst);
105         EmitI32(src.Value());
106     }
107 }
108 
Subq(Immediate src,Register dst)109 void AssemblerX64::Subq(Immediate src, Register dst)
110 {
111     EmitRexPrefixW(dst);
112     if (InRange8(src.Value())) {
113         // 83: Sub r/m16, imm8
114         EmitU8(0x83);
115         // 5: 83 /5 ib
116         EmitModrm(5, dst);
117         EmitI8(static_cast<int8_t>(src.Value()));
118     } else if (dst == rax) {
119         // 0x2D: Sub rax, imm32
120         EmitU8(0x2D);
121         EmitI32(src.Value());
122     } else {
123         // 81: sub r/m32, imm32
124         EmitU8(0x81);
125         // 5: 81 /5 id
126         EmitModrm(5, dst);
127         EmitI32(src.Value());
128     }
129 }
130 
Subq(Register src,Register dst)131 void AssemblerX64::Subq(Register src, Register dst)
132 {
133     EmitRexPrefix(src, dst);
134     // 29: sub r/m64, r64
135     EmitU8(0x29);
136     EmitModrm(src, dst);
137 }
138 
Subl(Immediate src,Register dst)139 void AssemblerX64::Subl(Immediate src, Register dst)
140 {
141     EmitRexPrefix(dst);
142     if (InRange8(src.Value())) {
143         // 83: Sub r/m16, imm8
144         EmitU8(0x83);
145         // 5: 83 /5 ib
146         EmitModrm(5, dst);
147         EmitI8(static_cast<int8_t>(src.Value()));
148     } else if (dst == rax) {
149         // 0x2D: Sub eax, imm32
150         EmitU8(0x2D);
151         EmitI32(src.Value());
152     } else {
153         // 81: sub r/m32, imm32
154         EmitU8(0x81);
155         // 5: 81 /5 id
156         EmitModrm(5, dst);
157         EmitI32(src.Value());
158     }
159 }
160 
Cmpq(Immediate src,Register dst)161 void AssemblerX64::Cmpq(Immediate src, Register dst)
162 {
163     EmitRexPrefixW(dst);
164     if (InRange8(src.Value())) {
165         // 83: cmp r/m64, imm8
166         EmitU8(0x83);
167         // 7: 83 /7 ib
168         EmitModrm(7, dst);
169         EmitI8(static_cast<int8_t>(src.Value()));
170     } else if (dst == rax) {
171         // 0x3D: cmp rax, imm32
172         EmitU8(0x3D);
173         EmitI32(src.Value());
174     } else {
175         // 81: cmp r/m32, imm32
176         EmitU8(0x81);
177         // 7: 81 /7 id
178         EmitModrm(7, dst);
179         EmitI32(src.Value());
180     }
181 }
182 
Cmpb(Immediate src,Register dst)183 void AssemblerX64::Cmpb(Immediate src, Register dst)
184 {
185     EmitRexPrefix(dst);
186     if (InRange8(src.Value())) {
187         // 80: cmp r/m8, imm8
188         EmitU8(0x80);
189         // 7: /7 ib
190         EmitModrm(7, dst);
191         EmitI8(static_cast<int8_t>(src.Value()));
192     } else if (dst == rax) {
193         // 0x3C: cmp al, imm8
194         EmitU8(0x3C);
195         EmitI8(src.Value());
196     } else {
197         LOG_ECMA(FATAL) << "this branch is unreachable";
198         UNREACHABLE();
199     }
200 }
201 
Cmpq(Register src,Register dst)202 void AssemblerX64::Cmpq(Register src, Register dst)
203 {
204     EmitRexPrefix(src, dst);
205     // 39: Cmp r/m64, r64
206     EmitU8(0x39);
207     EmitModrm(src, dst);
208 }
209 
Cmpl(Immediate src,Register dst)210 void AssemblerX64::Cmpl(Immediate src, Register dst)
211 {
212     EmitRexPrefix(dst);
213     if (InRange8(src.Value())) {
214         // 83: cmp r/m32, imm8
215         EmitU8(0x83);
216         // 7: 83 /7 ib
217         EmitModrm(7, dst);
218         EmitI8(static_cast<int8_t>(src.Value()));
219     } else if (dst == rax) {
220         // 0x3D: cmp rax, imm32
221         EmitU8(0x3D);
222         EmitI32(src.Value());
223     } else {
224         // 81: cmp r/m32, imm32
225         EmitU8(0x81);
226         // 7: 81 /7 id
227         EmitModrm(7, dst);
228         EmitI32(src.Value());
229     }
230 }
231 
Cmp(Immediate src,Register dst)232 void AssemblerX64::Cmp(Immediate src, Register dst)
233 {
234     Cmpq(src, dst);
235 }
236 
Movq(Register src,Register dst)237 void AssemblerX64::Movq(Register src, Register dst)
238 {
239     EmitRexPrefix(src, dst);
240     // 0x89: Move r16 to r/m16
241     EmitU8(0x89);
242     EmitModrm(src, dst);
243 }
244 
Mov(Register src,Register dst)245 void AssemblerX64::Mov(Register src, Register dst)
246 {
247     EmitRexPrefixl(dst, src);
248     // 0x89: Move r16 to r/m16
249     EmitU8(0x8B);
250     EmitModrm(dst, src);
251 }
252 
Align16()253 void AssemblerX64::Align16()
254 {
255     auto pos = GetCurrentPosition();
256     // 16: align16
257     size_t x = 16;
258     size_t delta = static_cast<size_t>(x - (pos & (x - 1)));
259     for (size_t i = 0; i < delta; i++) {
260         // 0x90: NOP
261         EmitU8(0x90);
262     }
263 }
264 
Movq(const Operand & src,Register dst)265 void AssemblerX64::Movq(const Operand &src, Register dst)
266 {
267     EmitRexPrefix(dst, src);
268     // 0x8B: Move r/m64 to r64
269     EmitU8(0x8B);
270     EmitOperand(dst, src);
271 }
272 
Movq(Register src,const Operand & dst)273 void AssemblerX64::Movq(Register src, const Operand &dst)
274 {
275     EmitRexPrefix(src, dst);
276     // 0x89: Move r64 to r/m64
277     EmitU8(0x89);
278     EmitOperand(src, dst);
279 }
280 
Movq(Immediate src,Operand dst)281 void AssemblerX64::Movq(Immediate src, Operand dst)
282 {
283     EmitRexPrefix(dst);
284     // 0xC7: Move imm32 to r/m32
285     EmitU8(0xC7);
286     // 0: C7 /0 id
287     EmitOperand(0, dst);
288     EmitI32(src.Value());
289 }
290 
Movq(Immediate src,Register dst)291 void AssemblerX64::Movq(Immediate src, Register dst)
292 {
293     EmitRexPrefix(dst);
294     // B8 : mov r32, imm32
295     EmitU8(0xB8 | LowBits(dst));
296     EmitI32(src.Value());
297 }
298 
Mov(const Operand & src,Register dst)299 void AssemblerX64::Mov(const Operand &src, Register dst)
300 {
301     Movq(src, dst);
302 }
303 
EmitJmp(int32_t offset)304 void AssemblerX64::EmitJmp(int32_t offset)
305 {
306     offset--;
307     if (InRange8(offset - sizeof(int8_t))) {
308         // EB: Jmp rel8
309         EmitU8(0xEB);
310         EmitI8(offset - sizeof(int8_t));
311     } else {
312         // E9: Jmp rel32
313         EmitU8(0xE9);
314         EmitI32(offset - sizeof(int32_t));
315     }
316 }
317 
EmitJa(int32_t offset)318 void AssemblerX64::EmitJa(int32_t offset)
319 {
320     offset--;
321     if (InRange8(offset - sizeof(int8_t))) {
322         // 77 : Ja rel8
323         EmitU8(0x77);
324         EmitI8(offset - sizeof(int8_t));
325     } else {
326         offset--;
327         // 0F 87 : ja rel32
328         EmitU8(0x0F);
329         EmitU8(0x87);
330         EmitI32(offset - sizeof(int32_t));
331     }
332 }
333 
EmitJb(int32_t offset)334 void AssemblerX64::EmitJb(int32_t offset)
335 {
336     offset--;
337     if (InRange8(offset - sizeof(int8_t))) {
338         // 72 : Jb rel8
339         EmitU8(0x72);
340         EmitI8(offset - sizeof(int8_t));
341     } else {
342         offset--;
343         // 0F 82 : Jb rel32
344         EmitU8(0x0F);
345         EmitU8(0x82);
346         EmitI32(offset - sizeof(int32_t));
347     }
348 }
349 
EmitJz(int32_t offset)350 void AssemblerX64::EmitJz(int32_t offset)
351 {
352     offset--;
353     if (InRange8(offset - sizeof(int8_t))) {
354         // 74 : Jz rel8
355         EmitU8(0x74);
356         EmitI8(offset - sizeof(int8_t));
357     } else {
358         offset--;
359         // 0F 84 : Jz rel32
360         EmitU8(0x0F);
361         EmitU8(0x84);
362         EmitI32(offset - sizeof(int32_t));
363     }
364 }
365 
EmitJne(int32_t offset)366 void AssemblerX64::EmitJne(int32_t offset)
367 {
368     offset--;
369     if (InRange8(offset - sizeof(int8_t))) {
370         // 75 : Jne rel8;
371         EmitU8(0x75);
372         EmitI8(offset - sizeof(int8_t));
373     } else {
374         offset--;
375         // 0F 85 : Jne rel32
376         EmitU8(0x0F);
377         EmitU8(0x85);
378         EmitI32(offset - sizeof(int32_t));
379     }
380 }
381 
EmitJbe(int32_t offset)382 void AssemblerX64::EmitJbe(int32_t offset)
383 {
384     offset--;
385     if (InRange8(offset - sizeof(int8_t))) {
386         // 76 : Jbe rel8;
387         EmitU8(0x76);
388         EmitI8(offset - sizeof(int8_t));
389     } else {
390         offset--;
391         // 0F 86 : Jne rel32
392         EmitU8(0x0F);
393         EmitU8(0x86);
394         EmitI32(offset - sizeof(int32_t));
395     }
396 }
397 
EmitJnz(int32_t offset)398 void AssemblerX64::EmitJnz(int32_t offset)
399 {
400     offset--;
401     if (InRange8(offset)) {
402         // 75 : Jnz rel8
403         EmitU8(0x75);
404         EmitI8(offset - sizeof(int8_t));
405     } else {
406         offset--;
407         // 0F 85: Jnz rel32
408         EmitU8(0x0F);
409         EmitU8(0x85);
410         EmitI32(offset - sizeof(int32_t));
411     }
412 }
413 
EmitJle(int32_t offset)414 void AssemblerX64::EmitJle(int32_t offset)
415 {
416     offset--;
417     if (InRange8(offset)) {
418         // 7E : Jle rel8
419         EmitU8(0x7E);
420         EmitI8(offset - sizeof(int8_t));
421     } else {
422         offset--;
423         // 0F 8E: Jle rel32
424         EmitU8(0x0F);
425         EmitU8(0x8E);
426         EmitI32(offset - sizeof(int32_t));
427     }
428 }
429 
EmitJae(int32_t offset)430 void AssemblerX64::EmitJae(int32_t offset)
431 {
432     offset--;
433     if (InRange8(offset)) {
434         // 73 : Jae rel8
435         EmitU8(0x73);
436         EmitI8(offset - sizeof(int8_t));
437     } else {
438         offset--;
439         // 0F 83: Jae rel32
440         EmitU8(0x0F);
441         EmitU8(0x83);
442         EmitI32(offset - sizeof(int32_t));
443     }
444 }
445 
EmitJg(int32_t offset)446 void AssemblerX64::EmitJg(int32_t offset)
447 {
448     offset--;
449     if (InRange8(offset)) {
450         // 7F : Jg rel8
451         EmitU8(0x7F);
452         EmitI8(offset - sizeof(int8_t));
453     } else {
454         offset--;
455         // 0F 8F: Jg rel32
456         EmitU8(0x0F);
457         EmitU8(0x8F);
458         EmitI32(offset - sizeof(int32_t));
459     }
460 }
461 
EmitJge(int32_t offset)462 void AssemblerX64::EmitJge(int32_t offset)
463 {
464     offset--;
465     if (InRange8(offset)) {
466         // 7D : Jg rel8
467         EmitU8(0x7D);
468         EmitI8(offset - sizeof(int8_t));
469     } else {
470         offset--;
471         // 0F 8F: Jg rel32
472         EmitU8(0x0F);
473         EmitU8(0x8D);
474         EmitI32(offset - sizeof(int32_t));
475     }
476 }
477 
EmitJe(int32_t offset)478 void AssemblerX64::EmitJe(int32_t offset)
479 {
480     offset--;
481     if (InRange8(offset)) {
482         // 74 : Je rel8
483         EmitU8(0x74);
484         EmitI8(offset - sizeof(int8_t));
485     } else {
486         offset--;
487         // 0F 84: Je rel32
488         EmitU8(0x0F);
489         EmitU8(0x84);
490         EmitI32(offset - sizeof(int32_t));
491     }
492 }
493 
EmitCall(int32_t offset)494 void AssemblerX64::EmitCall(int32_t offset)
495 {
496     offset--;
497     // E8: call rel32
498     EmitU8(0xE8);
499     EmitI32(offset - sizeof(int32_t));
500 }
501 
EmitJnb(int32_t offset)502 void AssemblerX64::EmitJnb(int32_t offset)
503 {
504     offset--;
505     if (InRange8(offset)) {
506         // 73 : Jnb rel8
507         EmitU8(0x73);
508         EmitI8(offset - sizeof(int8_t));
509     } else {
510         offset--;
511         // 0F 83: Jnb rel32
512         EmitU8(0x0F);
513         EmitU8(0x83);
514         EmitI32(offset - sizeof(int32_t));
515     }
516 }
517 
Callq(Register addr)518 void AssemblerX64::Callq(Register addr)
519 {
520     // C3: RET Near return to calling procedure
521     EmitRexPrefix(addr);
522     // FF: Call r/m16
523     EmitU8(0xFF);
524     // 0x2: FF /2
525     EmitModrm(0x2, addr);
526 }
527 
Callq(Label * target)528 void AssemblerX64::Callq(Label *target)
529 {
530     if (target->IsBound()) {
531         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
532         EmitCall(offset);
533         return;
534     }
535 
536     auto pos = GetCurrentPosition();
537     int32_t emitPos = 0;
538     if (target->IsLinked()) {
539         emitPos = static_cast<int32_t>(target->GetLinkedPos());
540     }
541     // +1: skip opcode
542     target->LinkTo(pos + 1);
543     // E8: call rel32
544     EmitU8(0xE8);
545     EmitI32(emitPos);
546 }
547 
Ret()548 void AssemblerX64::Ret()
549 {
550     // C3: RET Near return to calling procedure
551     EmitU8(0xC3);
552 }
553 
Jmp(Label * target,Distance distance)554 void AssemblerX64::Jmp(Label *target, Distance distance)
555 {
556     if (target->IsBound()) {
557         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
558         EmitJmp(offset);
559         return;
560     }
561 
562     auto pos = GetCurrentPosition();
563     int32_t emitPos = 0;
564     if (distance == Distance::Near) {
565         if (target->IsLinkedNear()) {
566             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
567         }
568         // +1: skip opcode
569         target->LinkNearPos(pos + 1);
570         ASSERT(InRange8(emitPos));
571         // EB: Jmp rel8
572         EmitU8(0xEB);
573         EmitI8(static_cast<int8_t>(emitPos));
574     } else {
575         if (target->IsLinked()) {
576             emitPos = static_cast<int32_t>(target->GetLinkedPos());
577         }
578         // +1: skip opcode
579         target->LinkTo(pos + 1);
580         // E9: Jmp rel32
581         EmitU8(0xE9);
582         EmitI32(emitPos);
583     }
584 }
585 
Jmp(Register dst)586 void AssemblerX64::Jmp(Register dst)
587 {
588     EmitRexPrefix(dst);
589     // opcode FF/4 : jmp r/m64
590     EmitU8(0xFF);
591     // 4 means register
592     EmitModrm(4, dst);
593 }
594 
Jmp(Immediate offset)595 void AssemblerX64::Jmp(Immediate offset)
596 {
597     if (InRange8(offset.Value())) {
598         // opcode EB : jmp rel8
599         EmitU8(0xEB);
600         EmitI8(static_cast<int8_t>(offset.Value()));
601     } else {
602         // opcode E9 : jmp rel32
603         EmitU8(0xE9);
604         EmitI32(offset.Value());
605     }
606 }
607 
Ja(Label * target,Distance distance)608 void AssemblerX64::Ja(Label *target, Distance distance)
609 {
610     if (target->IsBound()) {
611         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
612         EmitJa(offset);
613         return;
614     }
615     auto pos = GetCurrentPosition();
616     int32_t emitPos = 0;
617     if (distance == Distance::Near) {
618         if (target->IsLinkedNear()) {
619             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
620         }
621         // +1: skip opcode
622         target->LinkNearPos(pos + 1);
623         ASSERT(InRange8(emitPos));
624         // 77: ja rel8
625         EmitU8(0x77);
626         EmitI8(static_cast<int8_t>(emitPos));
627     } else {
628         if (target->IsLinked()) {
629             emitPos = static_cast<int32_t>(target->GetLinkedPos());
630         }
631         // 2: skip opcode
632         target->LinkTo(pos + 2);
633         // 0F 87: ja rel32
634         EmitU8(0X0F);
635         EmitU8(0x87);
636         EmitI32(emitPos);
637     }
638 }
639 
Jb(Label * target,Distance distance)640 void AssemblerX64::Jb(Label *target, Distance distance)
641 {
642     if (target->IsBound()) {
643         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
644         EmitJb(offset);
645         return;
646     }
647     auto pos = GetCurrentPosition();
648     int32_t emitPos = 0;
649     if (distance == Distance::Near) {
650         if (target->IsLinkedNear()) {
651             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
652         }
653         // +1: skip opcode
654         target->LinkNearPos(pos + 1);
655         ASSERT(InRange8(emitPos));
656         // 72 : Jb rel8
657         EmitU8(0x72);
658         EmitI8(static_cast<int8_t>(emitPos));
659     } else {
660         if (target->IsLinked()) {
661             emitPos = static_cast<int32_t>(target->GetLinkedPos());
662         }
663         // 2: skip opcode
664         target->LinkTo(pos + 2);
665         // 0F 82: jb rel32
666         EmitU8(0X0F);
667         EmitU8(0x82);
668         EmitI32(emitPos);
669     }
670 }
Jz(Label * target,Distance distance)671 void AssemblerX64::Jz(Label *target, Distance distance)
672 {
673     if (target->IsBound()) {
674         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
675         EmitJz(offset);
676         return;
677     }
678     auto pos = GetCurrentPosition();
679     int32_t emitPos = 0;
680     if (distance == Distance::Near) {
681         if (target->IsLinkedNear()) {
682             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
683         }
684         // +1: skip opcode
685         target->LinkNearPos(pos + 1);
686         ASSERT(InRange8(emitPos));
687         // 74 : Jz rel8
688         EmitU8(0x74);
689         EmitI8(static_cast<int8_t>(emitPos));
690     } else {
691         if (target->IsLinked()) {
692             emitPos = static_cast<int32_t>(target->GetLinkedPos());
693         }
694         // 2: skip opcode
695         target->LinkTo(pos + 2);
696         // 0F 84: Jz rel32
697         EmitU8(0X0F);
698         EmitU8(0x84);
699         EmitI32(emitPos);
700     }
701 }
702 
Je(Label * target,Distance distance)703 void AssemblerX64::Je(Label *target, Distance distance)
704 {
705     if (target->IsBound()) {
706         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
707         EmitJe(offset);
708         return;
709     }
710     auto pos = GetCurrentPosition();
711     int32_t emitPos = 0;
712     if (distance == Distance::Near) {
713         if (target->IsLinkedNear()) {
714             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
715         }
716         // +1: skip opcode
717         target->LinkNearPos(pos + 1);
718         ASSERT(InRange8(emitPos));
719         // 74 : Je rel8
720         EmitU8(0x74);
721         EmitI8(static_cast<int8_t>(emitPos));
722     } else {
723         if (target->IsLinked()) {
724             emitPos = static_cast<int32_t>(target->GetLinkedPos());
725         }
726         // 2: skip opcode
727         target->LinkTo(pos + 2);
728         // 0F 84: Je rel32
729         EmitU8(0X0F);
730         EmitU8(0x84);
731         EmitI32(emitPos);
732     }
733 }
734 
Bind(Label * target)735 void AssemblerX64::Bind(Label *target)
736 {
737     size_t pos = GetCurrentPosition();
738     ASSERT(!target->IsBound());
739 
740     if (target->IsLinked()) {
741         uint32_t linkPos = target->GetLinkedPos();
742         while (linkPos != 0) {
743             uint32_t preLinkPos = GetU32(linkPos);
744             int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int32_t));
745             PutI32(linkPos, disp);
746             linkPos = preLinkPos;
747         }
748     }
749 
750     if (target->IsLinkedNear()) {
751         uint32_t linkPos = target->GetLinkedNearPos();
752         while (linkPos != 0) {
753             int8_t offsetToNext = GetI8(static_cast<size_t>(linkPos));
754             int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int8_t));
755             ASSERT(InRange8(disp));
756             PutI8(linkPos, static_cast<int8_t>(disp));
757             if (offsetToNext == 0) {
758                 break;
759             }
760             linkPos += static_cast<uint32_t>(offsetToNext);
761         }
762         target->UnlinkNearPos();
763     }
764 
765     target->BindTo(pos);
766 }
767 
Operand(Register base,int32_t disp)768 Operand::Operand(Register base, int32_t disp)
769 {
770     if (base == rsp || base == r12) {
771         BuildSIB(Times1, rsp, base);
772     }
773     if (disp == 0 && base != rbp && base != r13) {
774         // 0: mode 00 [r/m]
775         BuildModerm(0, base);
776     } else if (AssemblerX64::InRange8(disp)) {
777         // 1: mode 01 [r/m + disp8]
778         BuildModerm(1, base);
779         BuildDisp8(disp);
780     } else {
781         // 2: mode 10 [r/m + disp32]
782         BuildModerm(2, base);
783         BuildDisp32(disp);
784     }
785 }
786 
Operand(Register base,Register index,Scale scale,int32_t disp)787 Operand::Operand(Register base, Register index, Scale scale, int32_t disp)
788 {
789     BuildSIB(scale, index, base);
790     if (disp == 0 && base != rbp && base != r13) {
791         // 0: mode 00 [r/m]
792         BuildModerm(0, rsp);
793     } else if (AssemblerX64::InRange8(disp)) {
794         // 1: mode 01 [r/m + disp8]
795         BuildModerm(1, rsp);
796         BuildDisp8(disp);
797     } else {
798         // 2: mode 10 [r/m + disp32]
799         BuildModerm(2, rsp);
800         BuildDisp32(disp);
801     }
802 }
803 
804 // [index * scale + disp]
Operand(Register index,Scale scale,int32_t disp)805 Operand::Operand(Register index, Scale scale, int32_t disp)
806 {
807     ASSERT(index != rsp);
808     BuildModerm(0, rsp);
809     BuildSIB(scale, index, rbp);
810     BuildDisp32(disp);
811 }
812 
BuildSIB(Scale scale,Register index,Register base)813 void Operand::BuildSIB(Scale scale, Register index, Register base)
814 {
815     sib_ = AssemblerX64::GetSIB(scale, index, base);
816     rex_ |= AssemblerX64::GetSIBRex(index, base);
817     hasSIB_ = true;
818 }
819 
BuildModerm(int32_t mode,Register rm)820 void Operand::BuildModerm(int32_t mode, Register rm)
821 {
822     rex_ |= AssemblerX64::GetModrmRex(rm);
823     moderm_ = AssemblerX64::GetModrm(mode, rm);
824 }
825 
BuildDisp8(int32_t disp)826 void Operand::BuildDisp8(int32_t disp)
827 {
828     disp_ = disp;
829     hasDisp8_ = true;
830 }
831 
BuildDisp32(int32_t disp)832 void Operand::BuildDisp32(int32_t disp)
833 {
834     disp_ = disp;
835     hasDisp32_ = true;
836 }
837 
EmitOperand(int32_t reg,Operand rm)838 void AssemblerX64::EmitOperand(int32_t reg, Operand rm)
839 {
840     // moderm
841     EmitU8(rm.moderm_ | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE));
842     if (rm.hasSIB_) {
843         EmitU8(rm.sib_);
844     }
845 
846     if (rm.hasDisp8_) {
847         EmitI8(static_cast<int8_t>(rm.disp_));
848     } else if (rm.hasDisp32_) {
849         EmitI32(rm.disp_);
850     }
851 }
852 
Movl(Register src,Register dst)853 void AssemblerX64::Movl(Register src, Register dst)
854 {
855     EmitRexPrefixl(src, dst);
856     // 0x89: Move r16 to r/m16
857     EmitU8(0x89);
858     EmitModrm(src, dst);
859 }
860 
Movl(const Operand & src,Register dst)861 void AssemblerX64::Movl(const Operand &src, Register dst)
862 {
863     EmitRexPrefixl(dst, src);
864     // 0x8B: Move r/m64 to r64
865     EmitU8(0x8B);
866     EmitOperand(dst, src);
867 }
868 
Testq(Immediate src,Register dst)869 void AssemblerX64::Testq(Immediate src, Register dst)
870 {
871     if (InRange8(src.Value())) {
872         Testb(src, dst);
873     } else if (dst == rax) {
874         // A9: Test rax, imm32
875         EmitU8(0xA9);
876         EmitI32(src.Value());
877     } else {
878         EmitRexPrefixW(dst);
879         // F7: Test r/m64, imm32
880         EmitU8(0xF7);
881         // 0: F7 0 id
882         EmitModrm(0, dst);
883         EmitI32(src.Value());
884     }
885 }
886 
Testb(Immediate src,Register dst)887 void AssemblerX64::Testb(Immediate src, Register dst)
888 {
889     ASSERT(InRange8(src.Value()));
890     if (dst == rax) {
891         // A8: Test al, imm8
892         EmitU8(0xA8);
893     } else {
894         // AH BH CG DH can not be encoded to access if REX prefix used.
895         if (dst >= rsp) {
896             EmitRexPrefixL(dst);
897         }
898         // F6: Test r/m8, imm8
899         // REX F6: Test r/m8*, imm8
900         EmitU8(0xF6);
901         // 0: F6 /0 ib
902         EmitModrm(0, dst);
903     }
904     EmitI8(static_cast<int8_t>(src.Value()));
905 }
906 
Jne(Label * target,Distance distance)907 void AssemblerX64::Jne(Label *target, Distance distance)
908 {
909     if (target->IsBound()) {
910         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
911         EmitJne(offset);
912         return;
913     }
914     auto pos = GetCurrentPosition();
915     int32_t emitPos = 0;
916     if (distance == Distance::Near) {
917         if (target->IsLinkedNear()) {
918             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
919         }
920         // +1: skip opcode
921         target->LinkNearPos(pos + 1);
922         ASSERT(InRange8(emitPos));
923         // 75 : Jne rel8;
924         EmitU8(0x75);
925         EmitI8(static_cast<int8_t>(emitPos));
926     } else {
927         if (target->IsLinked()) {
928             emitPos = static_cast<int32_t>(target->GetLinkedPos());
929         }
930         // 2: skip opcode
931         target->LinkTo(pos + 2);
932         // 0F 85 : Jne rel32
933         EmitU8(0x0F);
934         EmitU8(0x85);
935         EmitI32(emitPos);
936     }
937 }
938 
Cmpl(Register src,Register dst)939 void AssemblerX64::Cmpl(Register src, Register dst)
940 {
941     EmitRexPrefixl(src, dst);
942     // 39: Cmp r16 to r/m16
943     EmitU8(0x39);
944     EmitModrm(src, dst);
945 }
946 
Jbe(Label * target,Distance distance)947 void AssemblerX64::Jbe(Label *target, Distance distance)
948 {
949     if (target->IsBound()) {
950         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
951         EmitJbe(offset);
952         return;
953     }
954     auto pos = GetCurrentPosition();
955     int32_t emitPos = 0;
956     if (distance == Distance::Near) {
957         if (target->IsLinkedNear()) {
958             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
959         }
960         // +1: skip opcode
961         target->LinkNearPos(pos + 1);
962         ASSERT(InRange8(emitPos));
963         // 76 : Jbe rel8;
964         EmitU8(0x76);
965         EmitI8(static_cast<int8_t>(emitPos));
966     } else {
967         if (target->IsLinked()) {
968             emitPos = static_cast<int32_t>(target->GetLinkedPos());
969         }
970         // 2: skip opcode
971         target->LinkTo(pos + 2);
972         // 0F 86 : Jbe rel32
973         EmitU8(0x0F);
974         EmitU8(0x86);
975         EmitI32(emitPos);
976     }
977 }
978 
CMovbe(Register src,Register dst)979 void AssemblerX64::CMovbe(Register src, Register dst)
980 {
981     EmitRexPrefixl(dst, src);
982     // 0f 46: CMovbe r32, r/m32
983     EmitU8(0x0F);
984     EmitU8(0x46);
985     EmitModrm(dst, src);
986 }
987 
Leaq(const Operand & src,Register dst)988 void AssemblerX64::Leaq(const Operand &src, Register dst)
989 {
990     EmitRexPrefix(dst, src);
991     // 8D : lea r64, m
992     EmitU8(0x8D);
993     EmitOperand(dst, src);
994 }
995 
Leal(const Operand & src,Register dst)996 void AssemblerX64::Leal(const Operand &src, Register dst)
997 {
998     EmitRexPrefixl(dst, src);
999     // 8D : lea r64, m
1000     EmitU8(0x8D);
1001     EmitOperand(dst, src);
1002 }
1003 
Shrq(Immediate src,Register dst)1004 void AssemblerX64::Shrq(Immediate src, Register dst)
1005 {
1006     EmitRexPrefixW(dst);
1007     // C1 : Shr r/m64, imm8;
1008     EmitU8(0xc1);
1009     // 5: C1 /5 id
1010     EmitModrm(5, dst);
1011     EmitI8(static_cast<int8_t>(src.Value()));
1012 }
1013 
Shr(Immediate src,Register dst)1014 void AssemblerX64::Shr(Immediate src, Register dst)
1015 {
1016     Shrq(src, dst);
1017 }
1018 
Andq(Immediate src,Register dst)1019 void AssemblerX64::Andq(Immediate src, Register dst)
1020 {
1021     EmitRexPrefixW(dst);
1022     if (InRange8(src.Value())) {
1023         // 83: and r/m64, imm8
1024         EmitU8(0x83);
1025         // 4: 83 /4 ib
1026         EmitModrm(4, dst);
1027         EmitI8(static_cast<int8_t>(src.Value()));
1028     } else if (dst == rax) {
1029         // 0x25: and rax, imm32
1030         EmitU8(0x25);
1031         EmitI32(src.Value());
1032     } else {
1033         // 81: and r/m64, imm32
1034         EmitU8(0x81);
1035         // 4: 81 /4 id
1036         EmitModrm(4, dst);
1037         EmitI32(src.Value());
1038     }
1039 }
1040 
Andl(Immediate src,Register dst)1041 void AssemblerX64::Andl(Immediate src, Register dst)
1042 {
1043     EmitRexPrefix(dst);
1044     if (InRange8(src.Value())) {
1045         // 83: and r/m64, imm8
1046         EmitU8(0x83);
1047         // 4: 83 /4 ib
1048         EmitModrm(4, dst);
1049         EmitI8(static_cast<int8_t>(src.Value()));
1050     } else if (dst == rax) {
1051         // 0x25: and rax, imm32
1052         EmitU8(0x25);
1053         EmitI32(src.Value());
1054     } else {
1055         // 81: and r/m64, imm32
1056         EmitU8(0x81);
1057         // 4: 81 /4 id
1058         EmitModrm(4, dst);
1059         EmitI32(src.Value());
1060     }
1061 }
1062 
And(Register src,Register dst)1063 void AssemblerX64::And(Register src, Register dst)
1064 {
1065     EmitRexPrefix(src, dst);
1066     // 21 : And r/m64, r64
1067     EmitU8(0x21);
1068     EmitModrm(src, dst);
1069 }
1070 
Or(Immediate src,Register dst)1071 void AssemblerX64::Or(Immediate src, Register dst)
1072 {
1073     EmitRexPrefixW(dst);
1074     if (InRange8(src.Value())) {
1075         // 83: or r/m64, imm8
1076         EmitU8(0x83);
1077         // 1: 83 /1 ib
1078         EmitModrm(1, dst);
1079         EmitI8(static_cast<int8_t>(src.Value()));
1080     } else if (dst == rax) {
1081         // 0x0D: or rax, imm32
1082         EmitU8(0x0D);
1083         EmitI32(src.Value());
1084     } else {
1085         // 81: or r/m64, imm32
1086         EmitU8(0x81);
1087         // 1: 81 /1 id
1088         EmitModrm(1, dst);
1089         EmitI32(src.Value());
1090     }
1091 }
1092 
Orq(Register src,Register dst)1093 void AssemblerX64::Orq(Register src, Register dst)
1094 {
1095     EmitRexPrefix(src, dst);
1096     // 09 : Or r/m64, r64
1097     EmitU8(0x09);
1098     EmitModrm(src, dst);
1099 }
1100 
Jnz(Label * target,Distance distance)1101 void AssemblerX64::Jnz(Label *target, Distance distance)
1102 {
1103     if (target->IsBound()) {
1104         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1105         EmitJnz(offset);
1106         return;
1107     }
1108     auto pos = GetCurrentPosition();
1109     int32_t emitPos = 0;
1110     if (distance == Distance::Near) {
1111         if (target->IsLinkedNear()) {
1112             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1113         }
1114         // +1: skip opcode
1115         target->LinkNearPos(pos + 1);
1116         ASSERT(InRange8(emitPos));
1117         // 75 : Jnz rel8;
1118         EmitU8(0x75);
1119         EmitI8(static_cast<int8_t>(emitPos));
1120     } else {
1121         if (target->IsLinked()) {
1122             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1123         }
1124         // 2: skip opcode
1125         target->LinkTo(pos + 2);
1126         // 0F 85 : Jnz rel32
1127         EmitU8(0x0F);
1128         EmitU8(0x85);
1129         EmitI32(emitPos);
1130     }
1131 }
1132 
Jle(Label * target,Distance distance)1133 void AssemblerX64::Jle(Label *target, Distance distance)
1134 {
1135     if (target->IsBound()) {
1136         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1137         EmitJle(offset);
1138         return;
1139     }
1140     auto pos = GetCurrentPosition();
1141     int32_t emitPos = 0;
1142     if (distance == Distance::Near) {
1143         if (target->IsLinkedNear()) {
1144             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1145         }
1146         // +1: skip opcode
1147         target->LinkNearPos(pos + 1);
1148         ASSERT(InRange8(emitPos));
1149         // 7E : Jle rel8;
1150         EmitU8(0x7E);
1151         EmitI8(static_cast<int8_t>(emitPos));
1152     } else {
1153         if (target->IsLinked()) {
1154             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1155         }
1156         // 2: skip opcode
1157         target->LinkTo(pos + 2);
1158         // 0F 8E: Jle rel32
1159         EmitU8(0x0F);
1160         EmitU8(0x8E);
1161         EmitI32(emitPos);
1162     }
1163 }
1164 
Jae(Label * target,Distance distance)1165 void AssemblerX64::Jae(Label *target, Distance distance)
1166 {
1167     if (target->IsBound()) {
1168         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1169         EmitJae(offset);
1170         return;
1171     }
1172     auto pos = GetCurrentPosition();
1173     int32_t emitPos = 0;
1174     if (distance == Distance::Near) {
1175         if (target->IsLinkedNear()) {
1176             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1177         }
1178         // +1: skip opcode
1179         target->LinkNearPos(pos + 1);
1180         ASSERT(InRange8(emitPos));
1181         // 73 : Jae rel8
1182         EmitU8(0x73);
1183         EmitI8(static_cast<int8_t>(emitPos));
1184     } else {
1185         if (target->IsLinked()) {
1186             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1187         }
1188         // 2: skip opcode
1189         target->LinkTo(pos + 2);
1190         // 0F 83: Jae rel32
1191         EmitU8(0x0F);
1192         EmitU8(0x83);
1193         EmitI32(emitPos);
1194     }
1195 }
1196 
Jg(Label * target,Distance distance)1197 void AssemblerX64::Jg(Label *target, Distance distance)
1198 {
1199     if (target->IsBound()) {
1200         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1201         EmitJg(offset);
1202         return;
1203     }
1204     auto pos = GetCurrentPosition();
1205     int32_t emitPos = 0;
1206     if (distance == Distance::Near) {
1207         if (target->IsLinkedNear()) {
1208             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1209         }
1210         // +1: skip opcode
1211         target->LinkNearPos(pos + 1);
1212         ASSERT(InRange8(emitPos));
1213         // 7F : Jg rel8
1214         EmitU8(0x7F);
1215         EmitI8(static_cast<int8_t>(emitPos));
1216     } else {
1217         if (target->IsLinked()) {
1218             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1219         }
1220         // 2: skip opcode
1221         target->LinkTo(pos + 2);
1222         // 0F 8F: Jae rel32
1223         EmitU8(0x0F);
1224         EmitU8(0x8F);
1225         EmitI32(emitPos);
1226     }
1227 }
1228 
Jge(Label * target,Distance distance)1229 void AssemblerX64::Jge(Label *target, Distance distance)
1230 {
1231     if (target->IsBound()) {
1232         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1233         EmitJge(offset);
1234         return;
1235     }
1236     auto pos = GetCurrentPosition();
1237     int32_t emitPos = 0;
1238     if (distance == Distance::Near) {
1239         if (target->IsLinkedNear()) {
1240             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1241         }
1242         // +1: skip opcode
1243         target->LinkNearPos(pos + 1);
1244         ASSERT(InRange8(emitPos));
1245         // 7F : Jg rel8
1246         EmitU8(0x7D);
1247         EmitI8(static_cast<int8_t>(emitPos));
1248     } else {
1249         if (target->IsLinked()) {
1250             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1251         }
1252         // 2: skip opcode
1253         target->LinkTo(pos + 2);
1254         // 0F 8F: Jae rel32
1255         EmitU8(0x0F);
1256         EmitU8(0x8D);
1257         EmitI32(emitPos);
1258     }
1259 }
1260 
Movzbq(const Operand & src,Register dst)1261 void AssemblerX64::Movzbq(const Operand &src, Register dst)
1262 {
1263     EmitRexPrefix(dst, src);
1264     // 0F B6 : Movzx r64, r/m16
1265     EmitU8(0x0F);
1266     EmitU8(0xB6);
1267     // 0F B6 /r: Movzx r64, r/m16
1268     EmitOperand(dst, src);
1269 }
1270 
Btq(Immediate src,Register dst)1271 void AssemblerX64::Btq(Immediate src, Register dst)
1272 {
1273     EmitRexPrefixW(dst);
1274     // 0F BA: bt r/m32, imm8;
1275     EmitU8(0x0F);
1276     EmitU8(0xBA);
1277     // /4: 0F BA bt r/m32, imm8
1278     EmitModrm(4, dst);
1279     EmitI8(static_cast<int8_t>(src.Value()));
1280 }
Btl(Immediate src,Register dst)1281 void AssemblerX64::Btl(Immediate src, Register dst)
1282 {
1283     EmitRexPrefix(dst);
1284     // 0F BA: bt r/m32, imm8;
1285     EmitU8(0x0F);
1286     EmitU8(0xBA);
1287     // /4: 0F BA bt r/m32, imm8
1288     EmitModrm(4, dst);
1289     EmitI8(static_cast<int8_t>(src.Value()));
1290 }
1291 
Movabs(uint64_t src,Register dst)1292 void AssemblerX64::Movabs(uint64_t src, Register dst)
1293 {
1294     // REX.W + B8 + rd io : Mov r64, imm64
1295     EmitRexPrefixW(dst);
1296     EmitU8(0xB8 | LowBits(dst));
1297     EmitU64(src);
1298 }
1299 
Shll(Immediate src,Register dst)1300 void AssemblerX64::Shll(Immediate src, Register dst)
1301 {
1302     EmitRexPrefix(dst);
1303     // C1 : shl r/m32, imm8
1304     EmitU8(0xC1);
1305     // C1 /4
1306     EmitModrm(4, dst);
1307     EmitI8(static_cast<int8_t>(src.Value()));
1308 }
1309 
Shlq(Immediate src,Register dst)1310 void AssemblerX64::Shlq(Immediate src, Register dst)
1311 {
1312     EmitRexPrefixW(dst);
1313     // C1 : shl r/m64, imm8
1314     EmitU8(0xC1);
1315     // C1 /4
1316     EmitModrm(4, dst);
1317     EmitI8(static_cast<int8_t>(src.Value()));
1318 }
1319 
Int3()1320 void AssemblerX64::Int3()
1321 {
1322     // CC :: INT3
1323     EmitU8(0xCC);
1324 }
1325 
Movzwq(const Operand & src,Register dst)1326 void AssemblerX64::Movzwq(const Operand &src, Register dst)
1327 {
1328     EmitRexPrefixW(dst);
1329     EmitU8(0x0F);
1330     EmitU8(0xB7);
1331     EmitOperand(dst, src);
1332 }
1333 
Jnb(Label * target,Distance distance)1334 void AssemblerX64::Jnb(Label *target, Distance distance)
1335 {
1336     if (target->IsBound()) {
1337         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1338         EmitJnb(offset);
1339         return;
1340     }
1341     auto pos = GetCurrentPosition();
1342     int32_t emitPos = 0;
1343     if (distance == Distance::Near) {
1344         if (target->IsLinkedNear()) {
1345             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1346         }
1347         // +1: skip opcode
1348         target->LinkNearPos(pos + 1);
1349         ASSERT(InRange8(emitPos));
1350         // 73 : Jnb rel8
1351         EmitU8(0x73);
1352         EmitI8(static_cast<int8_t>(emitPos));
1353     } else {
1354         if (target->IsLinked()) {
1355             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1356         }
1357         // 2: skip opcode
1358         target->LinkTo(pos + 2);
1359         // 0F 83: Jnb rel32
1360         EmitU8(0x0F);
1361         EmitU8(0x83);
1362         EmitI32(emitPos);
1363     }
1364 }
1365 }  // panda::ecmascript::x64
1366