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