• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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