1 /*
2 * Copyright (c) 2021-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 <array>
17 #include <functional>
18 #include <limits>
19 #include <tuple>
20 #include <vector>
21
22 #include <gtest/gtest.h>
23
24 #include "bytecode_emitter.h"
25
26 using namespace panda;
27 using Opcode = BytecodeInstruction::Opcode;
28
29 typedef std::tuple<uint8_t, uint8_t> Tuple16;
30 typedef std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> Tuple32;
31 typedef std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t> Tuple64;
32
33 namespace globals {
34 constexpr static const int64_t IMM_2 = 2;
35 constexpr static const int64_t IMM_3 = 3;
36 constexpr static const int64_t IMM_4 = 4;
37 constexpr static const int64_t IMM_5 = 5;
38 constexpr static const int64_t IMM_6 = 6;
39 constexpr static const int64_t IMM_7 = 7;
40 constexpr static const int64_t IMM_8 = 8;
41 constexpr static const int64_t IMM_9 = 9;
42 constexpr static const int64_t IMM_11 = 11;
43 constexpr static const int64_t IMM_12 = 12;
44 constexpr static const int64_t IMM_15 = 15;
45 constexpr static const int64_t IMM_16 = 16;
46 constexpr static const int64_t IMM_24 = 24;
47 constexpr static const int64_t IMM_32 = 32;
48 constexpr static const int64_t IMM_40 = 40;
49 constexpr static const int64_t IMM_48 = 48;
50 constexpr static const int64_t IMM_56 = 56;
51 } // namespace globals
52
operator <<(std::vector<uint8_t> & out,uint8_t val)53 static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, uint8_t val)
54 {
55 out.push_back(val);
56 return out;
57 }
58
59 static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Opcode op);
60
operator <<(std::vector<uint8_t> & out,Tuple16 val)61 static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Tuple16 val)
62 {
63 return out << std::get<0>(val) << std::get<1>(val);
64 }
65
operator <<(std::vector<uint8_t> & out,Tuple32 val)66 static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Tuple32 val)
67 {
68 return out << std::get<0>(val) << std::get<1>(val) << std::get<globals::IMM_2>(val)
69 << std::get<globals::IMM_3>(val);
70 }
71
operator <<(std::vector<uint8_t> & out,Tuple64 val)72 static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Tuple64 val)
73 {
74 return out << std::get<0>(val) << std::get<1>(val) << std::get<globals::IMM_2>(val) << std::get<globals::IMM_3>(val)
75 << std::get<globals::IMM_4>(val) << std::get<globals::IMM_5>(val) << std::get<globals::IMM_6>(val)
76 << std::get<globals::IMM_7>(val);
77 }
78
Split16(uint16_t val)79 static Tuple16 Split16(uint16_t val)
80 {
81 return Tuple16 {val & 0xFF, val >> 8};
82 }
83
Split32(uint32_t val)84 static Tuple32 Split32(uint32_t val)
85 {
86 return Tuple32 {val & 0xFF, (val >> globals::IMM_8) & 0xFF, (val >> globals::IMM_16) & 0xFF,
87 (val >> globals::IMM_24) & 0xFF};
88 }
89
Split64(uint64_t val)90 static Tuple64 Split64(uint64_t val)
91 {
92 return Tuple64 {val & 0xFF,
93 (val >> globals::IMM_8) & 0xFF,
94 (val >> globals::IMM_16) & 0xFF,
95 (val >> globals::IMM_24) & 0xFF,
96 (val >> globals::IMM_32) & 0xFF,
97 (val >> globals::IMM_40) & 0xFF,
98 (val >> globals::IMM_48) & 0xFF,
99 (val >> globals::IMM_56) & 0xFF};
100 }
101
102 HWTEST(BytecodeEmitter, JmpBwd_IMM8, testing::ext::TestSize.Level0)
103 {
104 BytecodeEmitter emitter;
105 Label label = emitter.CreateLabel();
106 emitter.Bind(label);
107 int num_ret = -std::numeric_limits<int8_t>::min();
108 for (int i = 0; i < num_ret; ++i) {
109 emitter.Return();
110 }
111 emitter.Jmp(label);
112 std::vector<uint8_t> out;
113 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
114 std::vector<uint8_t> expected;
115 for (int i = 0; i < num_ret; ++i) {
116 expected << Opcode::RETURN;
117 }
118 expected << Opcode::JMP_IMM8 << -num_ret;
119 ASSERT_EQ(expected, out);
120 }
121
122 HWTEST(BytecodeEmitter, JmpFwd_IMM8, testing::ext::TestSize.Level0)
123 {
124 BytecodeEmitter emitter;
125 Label label = emitter.CreateLabel();
126 emitter.Jmp(label);
127 // -5 because 2 bytes takes jmp itself and
128 // emitter estimate length of jmp by 3 greater the it is actually
129 int num_ret = std::numeric_limits<int8_t>::max() - globals::IMM_5;
130 for (int i = 0; i < num_ret; ++i) {
131 emitter.Return();
132 }
133 emitter.Bind(label);
134 emitter.Return();
135 std::vector<uint8_t> out;
136 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
137 std::vector<uint8_t> expected;
138 expected << Opcode::JMP_IMM8 << num_ret + globals::IMM_2;
139 for (int i = 0; i < num_ret + 1; ++i) {
140 expected << Opcode::RETURN;
141 }
142 ASSERT_EQ(expected, out);
143 }
144
145 HWTEST(BytecodeEmitter, JmpBwd_IMM16, testing::ext::TestSize.Level0)
146 {
147 {
148 BytecodeEmitter emitter;
149 Label label = emitter.CreateLabel();
150 emitter.Bind(label);
151 int num_ret = -std::numeric_limits<int8_t>::min() + 1;
152 for (int i = 0; i < num_ret; ++i) {
153 emitter.Return();
154 }
155 emitter.Jmp(label);
156 std::vector<uint8_t> out;
157 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
158 std::vector<uint8_t> expected;
159 for (int i = 0; i < num_ret; ++i) {
160 expected << Opcode::RETURN;
161 }
162 expected << Opcode::JMP_IMM16 << Split16(-num_ret);
163 ASSERT_EQ(expected, out);
164 }
165 {
166 BytecodeEmitter emitter;
167 Label label = emitter.CreateLabel();
168 emitter.Bind(label);
169 int num_ret = -std::numeric_limits<int16_t>::min();
170 for (int i = 0; i < num_ret; ++i) {
171 emitter.Return();
172 }
173 emitter.Jmp(label);
174 std::vector<uint8_t> out;
175 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
176 std::vector<uint8_t> expected;
177 for (int i = 0; i < num_ret; ++i) {
178 expected << Opcode::RETURN;
179 }
180 expected << Opcode::JMP_IMM16 << Split16(-num_ret);
181 ASSERT_EQ(expected, out);
182 }
183 }
184
185 HWTEST(BytecodeEmitter, JmpFwd_IMM16, testing::ext::TestSize.Level0)
186 {
187 {
188 BytecodeEmitter emitter;
189 Label label = emitter.CreateLabel();
190 emitter.Jmp(label);
191 // -4 because 2 bytes takes jmp itself and
192 // emitter estimate length of jmp by 3 greater the it is actually
193 // and plus one byte to make 8bit overflow
194 int num_ret = std::numeric_limits<int8_t>::max() - globals::IMM_4;
195 for (int i = 0; i < num_ret; ++i) {
196 emitter.Return();
197 }
198 emitter.Bind(label);
199 emitter.Return();
200 std::vector<uint8_t> out;
201 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
202 std::vector<uint8_t> expected;
203 expected << Opcode::JMP_IMM16 << Split16(num_ret + globals::IMM_3);
204 for (int i = 0; i < num_ret + 1; ++i) {
205 expected << Opcode::RETURN;
206 }
207 ASSERT_EQ(expected, out);
208 }
209 {
210 BytecodeEmitter emitter;
211 Label label = emitter.CreateLabel();
212 emitter.Jmp(label);
213 // -5 because 2 bytes takes jmp itself and
214 // emitter estimate length of jmp by 3 greater the it is actually
215 int num_ret = std::numeric_limits<int16_t>::max() - globals::IMM_5;
216 for (int i = 0; i < num_ret; ++i) {
217 emitter.Return();
218 }
219 emitter.Bind(label);
220 emitter.Return();
221 std::vector<uint8_t> out;
222 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
223 std::vector<uint8_t> expected;
224 expected << Opcode::JMP_IMM16 << Split16(num_ret + globals::IMM_3);
225 for (int i = 0; i < num_ret + 1; ++i) {
226 expected << Opcode::RETURN;
227 }
228 ASSERT_EQ(expected, out);
229 }
230 }
231
EmitJmp(Opcode op,int32_t imm,std::vector<uint8_t> * out)232 static void EmitJmp(Opcode op, int32_t imm, std::vector<uint8_t> *out)
233 {
234 *out << op;
235 switch (op) {
236 case Opcode::JMP_IMM8:
237 *out << static_cast<int8_t>(imm);
238 break;
239 case Opcode::JMP_IMM16:
240 *out << Split16(imm);
241 break;
242 default:
243 *out << Split32(imm);
244 break;
245 }
246 }
247
GetOpcode(size_t inst_size)248 static Opcode GetOpcode(size_t inst_size)
249 {
250 switch (inst_size) {
251 case globals::IMM_2:
252 return Opcode::JMP_IMM8;
253 case globals::IMM_3:
254 return Opcode::JMP_IMM16;
255 default:
256 return Opcode::JMP_IMM32;
257 }
258 }
259
260 /*
261 * Emit bytecode for the following program:
262 *
263 * label1:
264 * jmp label2
265 * ... <- n1 return.void instructions
266 * jmp label1
267 * ... <- n2 return.void instructions
268 * label2:
269 * return.void
270 */
EmitJmpFwdBwd(size_t n1,size_t n2)271 static std::vector<uint8_t> EmitJmpFwdBwd(size_t n1, size_t n2)
272 {
273 std::array<std::tuple<size_t, int32_t, int32_t>, 3> jmps {
274 std::tuple {globals::IMM_2, std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max()},
275 std::tuple {globals::IMM_3, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max()},
276 std::tuple {globals::IMM_5, std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max()}};
277
278 std::vector<uint8_t> out;
279
280 size_t jmp_size1;
281 size_t jmp_size2;
282 int32_t imm_max1;
283 int32_t imm_min2;
284
285 for (const auto &t1 : jmps) {
286 std::tie(jmp_size1, std::ignore, imm_max1) = t1;
287
288 for (const auto &t2 : jmps) {
289 std::tie(jmp_size2, imm_min2, std::ignore) = t2;
290
291 int32_t imm1 = jmp_size1 + n1 + jmp_size2 + n2;
292 int32_t imm2 = jmp_size1 + n1;
293
294 if (imm1 <= imm_max1 && -imm2 >= imm_min2) {
295 EmitJmp(GetOpcode(jmp_size1), imm1, &out);
296
297 for (size_t i = 0; i < n1; i++) {
298 out << Opcode::RETURN;
299 }
300
301 EmitJmp(GetOpcode(jmp_size2), -imm2, &out);
302
303 for (size_t i = 0; i < n2; i++) {
304 out << Opcode::RETURN;
305 }
306
307 out << Opcode::RETURN;
308
309 return out;
310 }
311 }
312 }
313
314 return out;
315 }
316
317 /*
318 * Test following control flow:
319 *
320 * label1:
321 * jmp label2
322 * ... <- n1 return.void instructions
323 * jmp label1
324 * ... <- n2 return.void instructions
325 * label2:
326 * return.void
327 */
TestJmpFwdBwd(size_t n1,size_t n2)328 void TestJmpFwdBwd(size_t n1, size_t n2)
329 {
330 BytecodeEmitter emitter;
331 Label label1 = emitter.CreateLabel();
332 Label label2 = emitter.CreateLabel();
333
334 emitter.Bind(label1);
335 emitter.Jmp(label2);
336 for (size_t i = 0; i < n1; ++i) {
337 emitter.Return();
338 }
339 emitter.Jmp(label1);
340 for (size_t i = 0; i < n2; ++i) {
341 emitter.Return();
342 }
343 emitter.Bind(label2);
344 emitter.Return();
345
346 std::vector<uint8_t> out;
347 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out)) << "n1 = " << n1 << " n2 = " << n2;
348
349 ASSERT_EQ(EmitJmpFwdBwd(n1, n2), out) << "n1 = " << n1 << " n2 = " << n2;
350 }
351
352 HWTEST(BytecodeEmitter, JmpFwdBwd, testing::ext::TestSize.Level0)
353 {
354 // fwd jmp imm16
355 // bwd jmp imm8
356 TestJmpFwdBwd(0, std::numeric_limits<int8_t>::max());
357
358 // fwd jmp imm16
359 // bwd jmp imm16
360 TestJmpFwdBwd(std::numeric_limits<int8_t>::max(), 0);
361
362 // fwd jmp imm32
363 // bwd jmp imm8
364 TestJmpFwdBwd(0, std::numeric_limits<int16_t>::max());
365
366 // fwd jmp imm32
367 // bwd jmp imm16
368 TestJmpFwdBwd(std::numeric_limits<int8_t>::max(), std::numeric_limits<int16_t>::max());
369
370 // fwd jmp imm32
371 // bwd jmp imm32
372 TestJmpFwdBwd(std::numeric_limits<int16_t>::max(), 0);
373 }
374
375 HWTEST(BytecodeEmitter, JmpBwd_IMM32, testing::ext::TestSize.Level0)
376 {
377 BytecodeEmitter emitter;
378 Label label = emitter.CreateLabel();
379 emitter.Bind(label);
380 int num_ret = -std::numeric_limits<int16_t>::min() + 1;
381 for (int i = 0; i < num_ret; ++i) {
382 emitter.Return();
383 }
384 emitter.Jmp(label);
385 std::vector<uint8_t> out;
386 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
387 std::vector<uint8_t> expected;
388 for (int i = 0; i < num_ret; ++i) {
389 expected << Opcode::RETURN;
390 }
391 expected << Opcode::JMP_IMM32 << Split32(-num_ret);
392 ASSERT_EQ(expected, out);
393 }
394
395 HWTEST(BytecodeEmitter, JmpFwd_IMM32, testing::ext::TestSize.Level0)
396 {
397 BytecodeEmitter emitter;
398 Label label = emitter.CreateLabel();
399 emitter.Jmp(label);
400 // -4 because 2 bytes takes jmp itself and
401 // emitter estimate length of jmp by 3 greater the it is actually
402 // and plus one byte to make 16bit overflow
403 int num_ret = std::numeric_limits<int16_t>::max() - globals::IMM_4;
404 for (int i = 0; i < num_ret; ++i) {
405 emitter.Return();
406 }
407 emitter.Bind(label);
408 emitter.Return();
409 std::vector<uint8_t> out;
410 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
411 std::vector<uint8_t> expected;
412 expected << Opcode::JMP_IMM32 << Split32(num_ret + globals::IMM_5);
413 for (int i = 0; i < num_ret + 1; ++i) {
414 expected << Opcode::RETURN;
415 }
416 ASSERT_EQ(expected, out);
417 }
418
419 HWTEST(BytecodeEmitter, Jne_V8_IMM8, testing::ext::TestSize.Level0)
420 {
421 BytecodeEmitter emitter;
422 Label label = emitter.CreateLabel();
423 emitter.Jne(0, label);
424 emitter.Bind(label);
425 emitter.Return();
426 std::vector<uint8_t> out;
427 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
428 std::vector<uint8_t> expected;
429 expected << Opcode::JNE_V8_IMM8 << 0 << globals::IMM_3 << Opcode::RETURN;
430 ASSERT_EQ(expected, out);
431 }
432
433 HWTEST(BytecodeEmitter, Jne_V8_IMM16, testing::ext::TestSize.Level0)
434 {
435 BytecodeEmitter emitter;
436 Label label = emitter.CreateLabel();
437 static constexpr uint8_t JNE_REG = 16;
438 static constexpr size_t N_NOPS = 256;
439 static constexpr size_t INSN_SZ = 4;
440 emitter.Jne(JNE_REG, label);
441 for (size_t i = 0; i < N_NOPS; ++i) {
442 emitter.Nop();
443 }
444 emitter.Bind(label);
445 emitter.Return();
446 std::vector<uint8_t> out;
447 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
448 std::vector<uint8_t> expected;
449 expected << Opcode::JNE_V8_IMM16 << JNE_REG << Split16(INSN_SZ + N_NOPS);
450 for (size_t i = 0; i < N_NOPS; ++i) {
451 expected << Opcode::NOP;
452 }
453 expected << Opcode::RETURN;
454 ASSERT_EQ(expected, out);
455 }
456
457 HWTEST(BytecodeEmitter, JmpFwdCrossRef, testing::ext::TestSize.Level0)
458 {
459 // Situation:
460 // +---------+
461 // +----|----+ |
462 // | | | |
463 // | | v v
464 // ---*----*----*----*----
465 // lbl1 lbl2
466 BytecodeEmitter emitter;
467 Label lbl1 = emitter.CreateLabel();
468 Label lbl2 = emitter.CreateLabel();
469 emitter.Jeq(0, lbl1);
470 emitter.Jeq(0, lbl2);
471 emitter.Return();
472 emitter.Bind(lbl1);
473 emitter.Return();
474 for (int i = 0; i < globals::IMM_6; ++i) {
475 emitter.Return();
476 }
477 emitter.Bind(lbl2);
478 emitter.Return();
479 std::vector<uint8_t> out;
480 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
481
482 std::vector<uint8_t> expected;
483 expected << Opcode::JEQ_V8_IMM8 << 0u << globals::IMM_7 << Opcode::JEQ_V8_IMM8 << 0u << globals::IMM_11;
484 for (int i = 0; i < globals::IMM_9; ++i) {
485 expected << Opcode::RETURN;
486 }
487 ASSERT_EQ(expected, out);
488 }
489
490 HWTEST(BytecodeEmitter, JmpBwdCrossRef, testing::ext::TestSize.Level0)
491 {
492 // Situation:
493 // +---------+
494 // | |
495 // +---------+ |
496 // | | | |
497 // v | | v
498 // ---*----*----*----*----
499 // lbl1 lbl2
500 BytecodeEmitter emitter;
501 Label lbl1 = emitter.CreateLabel();
502 Label lbl2 = emitter.CreateLabel();
503 emitter.Bind(lbl1);
504 emitter.Return();
505 emitter.Jeq(0, lbl2);
506 for (int i = 0; i < globals::IMM_5; ++i) {
507 emitter.Return();
508 }
509 emitter.Jeq(0, lbl1);
510 emitter.Bind(lbl2);
511 emitter.Return();
512
513 std::vector<uint8_t> out;
514 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
515
516 std::vector<uint8_t> expected;
517 expected << Opcode::RETURN << Opcode::JEQ_V8_IMM8 << 0u << globals::IMM_11;
518 for (int i = 0; i < globals::IMM_5; ++i) {
519 expected << Opcode::RETURN;
520 }
521 expected << Opcode::JEQ_V8_IMM8 << 0u << static_cast<uint8_t>(-globals::IMM_9) << Opcode::RETURN;
522 ASSERT_EQ(expected, out);
523 }
524
525 HWTEST(BytecodeEmitter, Jmp3FwdCrossRefs, testing::ext::TestSize.Level0)
526 {
527 // Situation:
528 // +--------+
529 // +|--------+
530 // ||+-------+---+
531 // ||| v v
532 // ---***-------*---*
533 // lbl1 lbl2
534 BytecodeEmitter emitter;
535 Label lbl1 = emitter.CreateLabel();
536 Label lbl2 = emitter.CreateLabel();
537
538 emitter.Jmp(lbl1);
539 emitter.Jmp(lbl1);
540 emitter.Jmp(lbl2);
541
542 constexpr int32_t INT8T_MAX = std::numeric_limits<int8_t>::max();
543
544 size_t n = INT8T_MAX - globals::IMM_4;
545 for (size_t i = 0; i < n; i++) {
546 emitter.Return();
547 }
548
549 emitter.Bind(lbl1);
550 emitter.Return();
551 emitter.Return();
552 emitter.Bind(lbl2);
553
554 std::vector<uint8_t> out;
555 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
556
557 std::vector<uint8_t> expected;
558 expected << Opcode::JMP_IMM16 << Split16(INT8T_MAX + globals::IMM_5);
559 expected << Opcode::JMP_IMM16 << Split16(INT8T_MAX + globals::IMM_2);
560 expected << Opcode::JMP_IMM16 << Split16(INT8T_MAX + 1);
561 for (size_t i = 0; i < n + globals::IMM_2; i++) {
562 expected << Opcode::RETURN;
563 }
564 ASSERT_EQ(expected, out);
565 }
566
567 HWTEST(BytecodeEmitter, UnboundLabel, testing::ext::TestSize.Level0)
568 {
569 BytecodeEmitter emitter;
570 Label label = emitter.CreateLabel();
571 emitter.Bind(label);
572 std::vector<uint8_t> out;
573 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
574 }
575
576 HWTEST(BytecodeEmitter, JumpToUnboundLabel, testing::ext::TestSize.Level0)
577 {
578 BytecodeEmitter emitter;
579 Label label = emitter.CreateLabel();
580 emitter.Jmp(label);
581 std::vector<uint8_t> out;
582 ASSERT_EQ(BytecodeEmitter::ErrorCode::UNBOUND_LABELS, emitter.Build(&out));
583 }
584
585 HWTEST(BytecodeEmitter, JumpToUnboundLabel2, testing::ext::TestSize.Level0)
586 {
587 BytecodeEmitter emitter;
588 Label label1 = emitter.CreateLabel();
589 Label label2 = emitter.CreateLabel();
590 emitter.Jmp(label1);
591 emitter.Bind(label2);
592 emitter.Mov(0, 1);
593 std::vector<uint8_t> out;
594 ASSERT_EQ(BytecodeEmitter::ErrorCode::UNBOUND_LABELS, emitter.Build(&out));
595 }
596
597 HWTEST(BytecodeEmitter, TwoJumpsToOneLabel, testing::ext::TestSize.Level0)
598 {
599 BytecodeEmitter emitter;
600 Label label = emitter.CreateLabel();
601 emitter.Bind(label);
602 emitter.Mov(0, 1);
603 emitter.Jmp(label);
604 emitter.Jmp(label);
605 std::vector<uint8_t> out;
606 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
607 }
608
Jmpz_IMM8(Opcode opcode,std::function<void (BytecodeEmitter *,const Label & label)> emit_jcmp)609 static void Jmpz_IMM8(Opcode opcode, std::function<void(BytecodeEmitter *, const Label &label)> emit_jcmp)
610 {
611 BytecodeEmitter emitter;
612 Label label = emitter.CreateLabel();
613 emit_jcmp(&emitter, label);
614 emitter.Bind(label);
615 emitter.Return();
616 }
617
Jmpz_IMM16(Opcode opcode,std::function<void (BytecodeEmitter *,const Label & label)> emit_jcmp)618 static void Jmpz_IMM16(Opcode opcode, std::function<void(BytecodeEmitter *, const Label &label)> emit_jcmp)
619 {
620 BytecodeEmitter emitter;
621 Label label = emitter.CreateLabel();
622 emit_jcmp(&emitter, label);
623 for (int i = 0; i < std::numeric_limits<uint8_t>::max() - globals::IMM_2; ++i) {
624 emitter.Return();
625 }
626 emitter.Bind(label);
627 emitter.Return();
628 }
629
Jmp_V8_IMM8(Opcode opcode,std::function<void (BytecodeEmitter *,uint8_t,const Label & label)> emit_jcmp)630 static void Jmp_V8_IMM8(Opcode opcode, std::function<void(BytecodeEmitter *, uint8_t, const Label &label)> emit_jcmp)
631 {
632 BytecodeEmitter emitter;
633 Label label = emitter.CreateLabel();
634 emit_jcmp(&emitter, globals::IMM_12, label);
635 emitter.Bind(label);
636 emitter.Return();
637 }
638
Jmp_V8_IMM16(Opcode opcode,std::function<void (BytecodeEmitter *,uint8_t,const Label & label)> emit_jcmp)639 static void Jmp_V8_IMM16(Opcode opcode, std::function<void(BytecodeEmitter *, uint8_t, const Label &label)> emit_jcmp)
640 {
641 BytecodeEmitter emitter;
642 Label label = emitter.CreateLabel();
643 emit_jcmp(&emitter, globals::IMM_15, label);
644 for (int i = 0; i < std::numeric_limits<uint8_t>::max() - globals::IMM_2; ++i) {
645 emitter.Return();
646 }
647 emitter.Bind(label);
648 emitter.Return();
649 }
650
Jmpz_IMM32(Opcode opcode,std::function<void (BytecodeEmitter *,const Label & label)> emit_jcmp)651 static void Jmpz_IMM32(Opcode opcode, std::function<void(BytecodeEmitter *, const Label &label)> emit_jcmp)
652 {
653 BytecodeEmitter emitter;
654 Label label = emitter.CreateLabel();
655 emit_jcmp(&emitter, label);
656 for (int i = 0; i < std::numeric_limits<uint8_t>::max() - globals::IMM_2; ++i) {
657 emitter.Return();
658 }
659 emitter.Bind(label);
660 emitter.Return();
661 }
662
TestNoneFormat(Opcode opcode,std::function<void (BytecodeEmitter *)> emit)663 static void TestNoneFormat(Opcode opcode, std::function<void(BytecodeEmitter *)> emit)
664 {
665 BytecodeEmitter emitter;
666 emit(&emitter);
667 std::vector<uint8_t> out;
668 ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
669 std::vector<uint8_t> expected;
670 expected << opcode;
671 ASSERT_EQ(expected, out);
672 }
673
674 #include <tests/bytecode_emitter_tests_gen.h>
675