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