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 - SIZE_OF_INT8)) {
308         // EB: Jmp rel8
309         EmitU8(0xEB);
310         EmitI8(offset - SIZE_OF_INT8);
311     } else {
312         // E9: Jmp rel32
313         EmitU8(0xE9);
314         EmitI32(offset - SIZE_OF_INT32);
315     }
316 }
317 
EmitJa(int32_t offset)318 void AssemblerX64::EmitJa(int32_t offset)
319 {
320     offset--;
321     if (InRange8(offset - SIZE_OF_INT8)) {
322         // 77 : Ja rel8
323         EmitU8(0x77);
324         EmitI8(offset - SIZE_OF_INT8);
325     } else {
326         offset--;
327         // 0F 87 : ja rel32
328         EmitU8(0x0F);
329         EmitU8(0x87);
330         EmitI32(offset - SIZE_OF_INT32);
331     }
332 }
333 
EmitJb(int32_t offset)334 void AssemblerX64::EmitJb(int32_t offset)
335 {
336     offset--;
337     if (InRange8(offset - SIZE_OF_INT8)) {
338         // 72 : Jb rel8
339         EmitU8(0x72);
340         EmitI8(offset - SIZE_OF_INT8);
341     } else {
342         offset--;
343         // 0F 82 : Jb rel32
344         EmitU8(0x0F);
345         EmitU8(0x82);
346         EmitI32(offset - SIZE_OF_INT32);
347     }
348 }
349 
EmitJz(int32_t offset)350 void AssemblerX64::EmitJz(int32_t offset)
351 {
352     offset--;
353     if (InRange8(offset - SIZE_OF_INT8)) {
354         // 74 : Jz rel8
355         EmitU8(0x74);
356         EmitI8(offset - SIZE_OF_INT8);
357     } else {
358         offset--;
359         // 0F 84 : Jz rel32
360         EmitU8(0x0F);
361         EmitU8(0x84);
362         EmitI32(offset - SIZE_OF_INT32);
363     }
364 }
365 
EmitJne(int32_t offset)366 void AssemblerX64::EmitJne(int32_t offset)
367 {
368     offset--;
369     if (InRange8(offset - SIZE_OF_INT8)) {
370         // 75 : Jne rel8;
371         EmitU8(0x75);
372         EmitI8(offset - SIZE_OF_INT8);
373     } else {
374         offset--;
375         // 0F 85 : Jne rel32
376         EmitU8(0x0F);
377         EmitU8(0x85);
378         EmitI32(offset - SIZE_OF_INT32);
379     }
380 }
381 
EmitJbe(int32_t offset)382 void AssemblerX64::EmitJbe(int32_t offset)
383 {
384     offset--;
385     if (InRange8(offset - SIZE_OF_INT8)) {
386         // 76 : Jbe rel8;
387         EmitU8(0x76);
388         EmitI8(offset - SIZE_OF_INT8);
389     } else {
390         offset--;
391         // 0F 86 : Jne rel32
392         EmitU8(0x0F);
393         EmitU8(0x86);
394         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
405     } else {
406         offset--;
407         // 0F 85: Jnz rel32
408         EmitU8(0x0F);
409         EmitU8(0x85);
410         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
421     } else {
422         offset--;
423         // 0F 8E: Jle rel32
424         EmitU8(0x0F);
425         EmitU8(0x8E);
426         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
437     } else {
438         offset--;
439         // 0F 83: Jae rel32
440         EmitU8(0x0F);
441         EmitU8(0x83);
442         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
453     } else {
454         offset--;
455         // 0F 8F: Jg rel32
456         EmitU8(0x0F);
457         EmitU8(0x8F);
458         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
469     } else {
470         offset--;
471         // 0F 8F: Jg rel32
472         EmitU8(0x0F);
473         EmitU8(0x8D);
474         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
485     } else {
486         offset--;
487         // 0F 84: Je rel32
488         EmitU8(0x0F);
489         EmitU8(0x84);
490         EmitI32(offset - SIZE_OF_INT32);
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 - SIZE_OF_INT32);
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 - SIZE_OF_INT8);
509     } else {
510         offset--;
511         // 0F 83: Jnb rel32
512         EmitU8(0x0F);
513         EmitU8(0x83);
514         EmitI32(offset - SIZE_OF_INT32);
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 
Movl(Register src, const Operand& dst)869 void AssemblerX64::Movl(Register src, const Operand& dst)
870 {
871     EmitRexPrefixl(src, dst);
872     // 0x89: Move r32 to r/m64
873     EmitU8(0x89);
874     EmitOperand(src, dst);
875 }
876 
Testq(Immediate src, Register dst)877 void AssemblerX64::Testq(Immediate src, Register dst)
878 {
879     if (InRange8(src.Value())) {
880         Testb(src, dst);
881     } else if (dst == rax) {
882         // A9: Test rax, imm32
883         EmitU8(0xA9);
884         EmitI32(src.Value());
885     } else {
886         EmitRexPrefixW(dst);
887         // F7: Test r/m64, imm32
888         EmitU8(0xF7);
889         // 0: F7 0 id
890         EmitModrm(0, dst);
891         EmitI32(src.Value());
892     }
893 }
894 
Testb(Immediate src, Register dst)895 void AssemblerX64::Testb(Immediate src, Register dst)
896 {
897     ASSERT(InRange8(src.Value()));
898     if (dst == rax) {
899         // A8: Test al, imm8
900         EmitU8(0xA8);
901     } else {
902         // AH BH CG DH can not be encoded to access if REX prefix used.
903         if (dst >= rsp) {
904             EmitRexPrefixL(dst);
905         }
906         // F6: Test r/m8, imm8
907         // REX F6: Test r/m8*, imm8
908         EmitU8(0xF6);
909         // 0: F6 /0 ib
910         EmitModrm(0, dst);
911     }
912     EmitI8(static_cast<int8_t>(src.Value()));
913 }
914 
Jne(Label *target, Distance distance)915 void AssemblerX64::Jne(Label *target, Distance distance)
916 {
917     if (target->IsBound()) {
918         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
919         EmitJne(offset);
920         return;
921     }
922     auto pos = GetCurrentPosition();
923     int32_t emitPos = 0;
924     if (distance == Distance::Near) {
925         if (target->IsLinkedNear()) {
926             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
927         }
928         // +1: skip opcode
929         target->LinkNearPos(pos + 1);
930         ASSERT(InRange8(emitPos));
931         // 75 : Jne rel8;
932         EmitU8(0x75);
933         EmitI8(static_cast<int8_t>(emitPos));
934     } else {
935         if (target->IsLinked()) {
936             emitPos = static_cast<int32_t>(target->GetLinkedPos());
937         }
938         // 2: skip opcode
939         target->LinkTo(pos + 2);
940         // 0F 85 : Jne rel32
941         EmitU8(0x0F);
942         EmitU8(0x85);
943         EmitI32(emitPos);
944     }
945 }
946 
Cmpl(Register src, Register dst)947 void AssemblerX64::Cmpl(Register src, Register dst)
948 {
949     EmitRexPrefixl(src, dst);
950     // 39: Cmp r16 to r/m16
951     EmitU8(0x39);
952     EmitModrm(src, dst);
953 }
954 
Jbe(Label *target, Distance distance)955 void AssemblerX64::Jbe(Label *target, Distance distance)
956 {
957     if (target->IsBound()) {
958         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
959         EmitJbe(offset);
960         return;
961     }
962     auto pos = GetCurrentPosition();
963     int32_t emitPos = 0;
964     if (distance == Distance::Near) {
965         if (target->IsLinkedNear()) {
966             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
967         }
968         // +1: skip opcode
969         target->LinkNearPos(pos + 1);
970         ASSERT(InRange8(emitPos));
971         // 76 : Jbe rel8;
972         EmitU8(0x76);
973         EmitI8(static_cast<int8_t>(emitPos));
974     } else {
975         if (target->IsLinked()) {
976             emitPos = static_cast<int32_t>(target->GetLinkedPos());
977         }
978         // 2: skip opcode
979         target->LinkTo(pos + 2);
980         // 0F 86 : Jbe rel32
981         EmitU8(0x0F);
982         EmitU8(0x86);
983         EmitI32(emitPos);
984     }
985 }
986 
CMovbe(Register src, Register dst)987 void AssemblerX64::CMovbe(Register src, Register dst)
988 {
989     EmitRexPrefixl(dst, src);
990     // 0f 46: CMovbe r32, r/m32
991     EmitU8(0x0F);
992     EmitU8(0x46);
993     EmitModrm(dst, src);
994 }
995 
Leaq(const Operand &src, Register dst)996 void AssemblerX64::Leaq(const Operand &src, Register dst)
997 {
998     EmitRexPrefix(dst, src);
999     // 8D : lea r64, m
1000     EmitU8(0x8D);
1001     EmitOperand(dst, src);
1002 }
1003 
Leal(const Operand &src, Register dst)1004 void AssemblerX64::Leal(const Operand &src, Register dst)
1005 {
1006     EmitRexPrefixl(dst, src);
1007     // 8D : lea r64, m
1008     EmitU8(0x8D);
1009     EmitOperand(dst, src);
1010 }
1011 
Shrq(Immediate src, Register dst)1012 void AssemblerX64::Shrq(Immediate src, Register dst)
1013 {
1014     EmitRexPrefixW(dst);
1015     // C1 : Shr r/m64, imm8;
1016     EmitU8(0xc1);
1017     // 5: C1 /5 id
1018     EmitModrm(5, dst);
1019     EmitI8(static_cast<int8_t>(src.Value()));
1020 }
1021 
Shrl(Immediate src, Register dst)1022 void AssemblerX64::Shrl(Immediate src, Register dst)
1023 {
1024     EmitRexPrefix(dst);
1025     // C1 : Shr r/m32, imm8;
1026     EmitU8(0xc1);
1027     // 5: C1 /5 id
1028     EmitModrm(5, dst);
1029     EmitI8(static_cast<int8_t>(src.Value()));
1030 }
1031 
Shr(Immediate src, Register dst)1032 void AssemblerX64::Shr(Immediate src, Register dst)
1033 {
1034     Shrq(src, dst);
1035 }
1036 
Andq(Immediate src, Register dst)1037 void AssemblerX64::Andq(Immediate src, Register dst)
1038 {
1039     EmitRexPrefixW(dst);
1040     if (InRange8(src.Value())) {
1041         // 83: and r/m64, imm8
1042         EmitU8(0x83);
1043         // 4: 83 /4 ib
1044         EmitModrm(4, dst);
1045         EmitI8(static_cast<int8_t>(src.Value()));
1046     } else if (dst == rax) {
1047         // 0x25: and rax, imm32
1048         EmitU8(0x25);
1049         EmitI32(src.Value());
1050     } else {
1051         // 81: and r/m64, imm32
1052         EmitU8(0x81);
1053         // 4: 81 /4 id
1054         EmitModrm(4, dst);
1055         EmitI32(src.Value());
1056     }
1057 }
1058 
Andl(Immediate src, Register dst)1059 void AssemblerX64::Andl(Immediate src, Register dst)
1060 {
1061     EmitRexPrefix(dst);
1062     if (InRange8(src.Value())) {
1063         // 83: and r/m64, imm8
1064         EmitU8(0x83);
1065         // 4: 83 /4 ib
1066         EmitModrm(4, dst);
1067         EmitI8(static_cast<int8_t>(src.Value()));
1068     } else if (dst == rax) {
1069         // 0x25: and rax, imm32
1070         EmitU8(0x25);
1071         EmitI32(src.Value());
1072     } else {
1073         // 81: and r/m64, imm32
1074         EmitU8(0x81);
1075         // 4: 81 /4 id
1076         EmitModrm(4, dst);
1077         EmitI32(src.Value());
1078     }
1079 }
1080 
And(Register src, Register dst)1081 void AssemblerX64::And(Register src, Register dst)
1082 {
1083     EmitRexPrefix(src, dst);
1084     // 21 : And r/m64, r64
1085     EmitU8(0x21);
1086     EmitModrm(src, dst);
1087 }
1088 
Or(Immediate src, Register dst)1089 void AssemblerX64::Or(Immediate src, Register dst)
1090 {
1091     EmitRexPrefixW(dst);
1092     if (InRange8(src.Value())) {
1093         // 83: or r/m64, imm8
1094         EmitU8(0x83);
1095         // 1: 83 /1 ib
1096         EmitModrm(1, dst);
1097         EmitI8(static_cast<int8_t>(src.Value()));
1098     } else if (dst == rax) {
1099         // 0x0D: or rax, imm32
1100         EmitU8(0x0D);
1101         EmitI32(src.Value());
1102     } else {
1103         // 81: or r/m64, imm32
1104         EmitU8(0x81);
1105         // 1: 81 /1 id
1106         EmitModrm(1, dst);
1107         EmitI32(src.Value());
1108     }
1109 }
1110 
Orq(Register src, Register dst)1111 void AssemblerX64::Orq(Register src, Register dst)
1112 {
1113     EmitRexPrefix(src, dst);
1114     // 09 : Or r/m64, r64
1115     EmitU8(0x09);
1116     EmitModrm(src, dst);
1117 }
1118 
Jnz(Label *target, Distance distance)1119 void AssemblerX64::Jnz(Label *target, Distance distance)
1120 {
1121     if (target->IsBound()) {
1122         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1123         EmitJnz(offset);
1124         return;
1125     }
1126     auto pos = GetCurrentPosition();
1127     int32_t emitPos = 0;
1128     if (distance == Distance::Near) {
1129         if (target->IsLinkedNear()) {
1130             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1131         }
1132         // +1: skip opcode
1133         target->LinkNearPos(pos + 1);
1134         ASSERT(InRange8(emitPos));
1135         // 75 : Jnz rel8;
1136         EmitU8(0x75);
1137         EmitI8(static_cast<int8_t>(emitPos));
1138     } else {
1139         if (target->IsLinked()) {
1140             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1141         }
1142         // 2: skip opcode
1143         target->LinkTo(pos + 2);
1144         // 0F 85 : Jnz rel32
1145         EmitU8(0x0F);
1146         EmitU8(0x85);
1147         EmitI32(emitPos);
1148     }
1149 }
1150 
Jle(Label *target, Distance distance)1151 void AssemblerX64::Jle(Label *target, Distance distance)
1152 {
1153     if (target->IsBound()) {
1154         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1155         EmitJle(offset);
1156         return;
1157     }
1158     auto pos = GetCurrentPosition();
1159     int32_t emitPos = 0;
1160     if (distance == Distance::Near) {
1161         if (target->IsLinkedNear()) {
1162             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1163         }
1164         // +1: skip opcode
1165         target->LinkNearPos(pos + 1);
1166         ASSERT(InRange8(emitPos));
1167         // 7E : Jle rel8;
1168         EmitU8(0x7E);
1169         EmitI8(static_cast<int8_t>(emitPos));
1170     } else {
1171         if (target->IsLinked()) {
1172             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1173         }
1174         // 2: skip opcode
1175         target->LinkTo(pos + 2);
1176         // 0F 8E: Jle rel32
1177         EmitU8(0x0F);
1178         EmitU8(0x8E);
1179         EmitI32(emitPos);
1180     }
1181 }
1182 
Jae(Label *target, Distance distance)1183 void AssemblerX64::Jae(Label *target, Distance distance)
1184 {
1185     if (target->IsBound()) {
1186         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1187         EmitJae(offset);
1188         return;
1189     }
1190     auto pos = GetCurrentPosition();
1191     int32_t emitPos = 0;
1192     if (distance == Distance::Near) {
1193         if (target->IsLinkedNear()) {
1194             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1195         }
1196         // +1: skip opcode
1197         target->LinkNearPos(pos + 1);
1198         ASSERT(InRange8(emitPos));
1199         // 73 : Jae rel8
1200         EmitU8(0x73);
1201         EmitI8(static_cast<int8_t>(emitPos));
1202     } else {
1203         if (target->IsLinked()) {
1204             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1205         }
1206         // 2: skip opcode
1207         target->LinkTo(pos + 2);
1208         // 0F 83: Jae rel32
1209         EmitU8(0x0F);
1210         EmitU8(0x83);
1211         EmitI32(emitPos);
1212     }
1213 }
1214 
Jg(Label *target, Distance distance)1215 void AssemblerX64::Jg(Label *target, Distance distance)
1216 {
1217     if (target->IsBound()) {
1218         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1219         EmitJg(offset);
1220         return;
1221     }
1222     auto pos = GetCurrentPosition();
1223     int32_t emitPos = 0;
1224     if (distance == Distance::Near) {
1225         if (target->IsLinkedNear()) {
1226             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1227         }
1228         // +1: skip opcode
1229         target->LinkNearPos(pos + 1);
1230         ASSERT(InRange8(emitPos));
1231         // 7F : Jg rel8
1232         EmitU8(0x7F);
1233         EmitI8(static_cast<int8_t>(emitPos));
1234     } else {
1235         if (target->IsLinked()) {
1236             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1237         }
1238         // 2: skip opcode
1239         target->LinkTo(pos + 2);
1240         // 0F 8F: Jae rel32
1241         EmitU8(0x0F);
1242         EmitU8(0x8F);
1243         EmitI32(emitPos);
1244     }
1245 }
1246 
Jge(Label *target, Distance distance)1247 void AssemblerX64::Jge(Label *target, Distance distance)
1248 {
1249     if (target->IsBound()) {
1250         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1251         EmitJge(offset);
1252         return;
1253     }
1254     auto pos = GetCurrentPosition();
1255     int32_t emitPos = 0;
1256     if (distance == Distance::Near) {
1257         if (target->IsLinkedNear()) {
1258             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1259         }
1260         // +1: skip opcode
1261         target->LinkNearPos(pos + 1);
1262         ASSERT(InRange8(emitPos));
1263         // 7F : Jg rel8
1264         EmitU8(0x7D);
1265         EmitI8(static_cast<int8_t>(emitPos));
1266     } else {
1267         if (target->IsLinked()) {
1268             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1269         }
1270         // 2: skip opcode
1271         target->LinkTo(pos + 2);
1272         // 0F 8F: Jae rel32
1273         EmitU8(0x0F);
1274         EmitU8(0x8D);
1275         EmitI32(emitPos);
1276     }
1277 }
1278 
Movzbq(const Operand &src, Register dst)1279 void AssemblerX64::Movzbq(const Operand &src, Register dst)
1280 {
1281     EmitRexPrefix(dst, src);
1282     // 0F B6 : Movzx r64, r/m16
1283     EmitU8(0x0F);
1284     EmitU8(0xB6);
1285     // 0F B6 /r: Movzx r64, r/m16
1286     EmitOperand(dst, src);
1287 }
1288 
Movzbl(const Operand &src, Register dst)1289 void AssemblerX64::Movzbl(const Operand &src, Register dst)
1290 {
1291     EmitRexPrefixl(dst, src);
1292     // 0F B6 : Movzx r64, r/m16
1293     EmitU8(0x0F);
1294     EmitU8(0xB6);
1295     // 0F B6 /r: Movzx r64, r/m16
1296     EmitOperand(dst, src);
1297 }
1298 
Movzbl(Register src, Register dst)1299 void AssemblerX64::Movzbl(Register src, Register dst)
1300 {
1301     EmitRexPrefixl(dst, src);
1302     // 0F B6 : Movzx r64, r/m16
1303     EmitU8(0x0F);
1304     EmitU8(0xB6);
1305     // 0F B6 /r: Movzx r64, r/m16
1306     EmitModrm(dst, src);
1307 }
1308 
Btq(Immediate src, Register dst)1309 void AssemblerX64::Btq(Immediate src, Register dst)
1310 {
1311     EmitRexPrefixW(dst);
1312     // 0F BA: bt r/m32, imm8;
1313     EmitU8(0x0F);
1314     EmitU8(0xBA);
1315     // /4: 0F BA bt r/m32, imm8
1316     EmitModrm(4, dst);
1317     EmitI8(static_cast<int8_t>(src.Value()));
1318 }
Btl(Immediate src, Register dst)1319 void AssemblerX64::Btl(Immediate src, Register dst)
1320 {
1321     EmitRexPrefix(dst);
1322     // 0F BA: bt r/m32, imm8;
1323     EmitU8(0x0F);
1324     EmitU8(0xBA);
1325     // /4: 0F BA bt r/m32, imm8
1326     EmitModrm(4, dst);
1327     EmitI8(static_cast<int8_t>(src.Value()));
1328 }
1329 
Movabs(uint64_t src, Register dst)1330 void AssemblerX64::Movabs(uint64_t src, Register dst)
1331 {
1332     // REX.W + B8 + rd io : Mov r64, imm64
1333     EmitRexPrefixW(dst);
1334     EmitU8(0xB8 | LowBits(dst));
1335     EmitU64(src);
1336 }
1337 
Shll(Immediate src, Register dst)1338 void AssemblerX64::Shll(Immediate src, Register dst)
1339 {
1340     EmitRexPrefix(dst);
1341     // C1 : shl r/m32, imm8
1342     EmitU8(0xC1);
1343     // C1 /4
1344     EmitModrm(4, dst);
1345     EmitI8(static_cast<int8_t>(src.Value()));
1346 }
1347 
Shlq(Immediate src, Register dst)1348 void AssemblerX64::Shlq(Immediate src, Register dst)
1349 {
1350     EmitRexPrefixW(dst);
1351     // C1 : shl r/m64, imm8
1352     EmitU8(0xC1);
1353     // C1 /4
1354     EmitModrm(4, dst);
1355     EmitI8(static_cast<int8_t>(src.Value()));
1356 }
1357 
Btsl(Register src, Register dst)1358 void AssemblerX64::Btsl(Register src, Register dst)
1359 {
1360     EmitRexPrefixl(src, dst);
1361     // 0F AB: bts r32, r32;
1362     EmitU8(0x0F);
1363     EmitU8(0xAB);
1364 
1365     EmitModrm(src, dst);
1366 }
1367 
Int3()1368 void AssemblerX64::Int3()
1369 {
1370     // CC :: INT3
1371     EmitU8(0xCC);
1372 }
1373 
Movzwq(const Operand &src, Register dst)1374 void AssemblerX64::Movzwq(const Operand &src, Register dst)
1375 {
1376     EmitRexPrefix(dst, src);
1377     EmitU8(0x0F);
1378     EmitU8(0xB7);
1379     EmitOperand(dst, src);
1380 }
1381 
Jnb(Label *target, Distance distance)1382 void AssemblerX64::Jnb(Label *target, Distance distance)
1383 {
1384     if (target->IsBound()) {
1385         int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1386         EmitJnb(offset);
1387         return;
1388     }
1389     auto pos = GetCurrentPosition();
1390     int32_t emitPos = 0;
1391     if (distance == Distance::Near) {
1392         if (target->IsLinkedNear()) {
1393             emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1394         }
1395         // +1: skip opcode
1396         target->LinkNearPos(pos + 1);
1397         ASSERT(InRange8(emitPos));
1398         // 73 : Jnb rel8
1399         EmitU8(0x73);
1400         EmitI8(static_cast<int8_t>(emitPos));
1401     } else {
1402         if (target->IsLinked()) {
1403             emitPos = static_cast<int32_t>(target->GetLinkedPos());
1404         }
1405         // 2: skip opcode
1406         target->LinkTo(pos + 2);
1407         // 0F 83: Jnb rel32
1408         EmitU8(0x0F);
1409         EmitU8(0x83);
1410         EmitI32(emitPos);
1411     }
1412 }
1413 }  // panda::ecmascript::x64
1414