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