1 /**
2 * Copyright (c) 2021-2024 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 <gtest/gtest.h>
17
18 #include <vector>
19
20 #include "assembly-parser.h"
21 #include "libpandafile/value.h"
22 #include "runtime/entrypoints/entrypoints.h"
23 #include "runtime/include/method.h"
24 #include "runtime/include/runtime.h"
25
26 namespace ark::test {
27
Separator()28 inline std::string Separator()
29 {
30 #ifdef _WIN32
31 return "\\";
32 #else
33 return "/";
34 #endif
35 }
36
37 class PandaExceptionTest : public testing::Test {
38 protected:
39 enum class ExType { INT = 0, JIT };
40
PandaExceptionTest()41 PandaExceptionTest()
42 {
43 // NOLINTNEXTLINE(readability-magic-numbers)
44 options_.SetHeapSizeLimit(64_MB);
45 // NOLINTNEXTLINE(readability-magic-numbers)
46 options_.SetInternalMemorySizeLimit(64_MB);
47
48 options_.SetShouldInitializeIntrinsics(false);
49
50 options_.SetLoadRuntimes({"core"});
51
52 options_.SetGcType("gen-gc");
53
54 auto execPath = ark::os::file::File::GetExecutablePath();
55 std::string pandaStdLib =
56 execPath.Value() + Separator() + ".." + Separator() + "pandastdlib" + Separator() + "pandastdlib.bin";
57 options_.SetBootPandaFiles({pandaStdLib});
58 }
59
~PandaExceptionTest()60 ~PandaExceptionTest() override
61 {
62 thread_->ManagedCodeEnd();
63 Runtime::Destroy();
64 }
65
66 NO_COPY_SEMANTIC(PandaExceptionTest);
67 NO_MOVE_SEMANTIC(PandaExceptionTest);
68
CreateRuntime(ExType exType)69 inline void CreateRuntime(ExType exType)
70 {
71 switch (exType) {
72 case ExType::INT: {
73 options_.SetCompilerEnableJit(false);
74 break;
75 }
76
77 case ExType::JIT: {
78 options_.SetCompilerEnableJit(true);
79 options_.SetCompilerHotnessThreshold(0);
80 break;
81 }
82 }
83
84 Runtime::Create(options_);
85
86 thread_ = ark::MTManagedThread::GetCurrent();
87 thread_->ManagedCodeBegin();
88 }
89
90 private:
91 ark::MTManagedThread *thread_ {};
92 RuntimeOptions options_;
93 };
94
95 /**
96 * This test is a core test that's supposed
97 * to provoke the AbstractMethodException, to catch it,
98 * and to return 0 as the result.
99 */
100 static auto g_abstractMethodStaticCallShortIntSource = R"(
101 .record panda.AbstractMethodError <external>
102
103 .record panda.Exception <external>
104
105 .record R {}
106
107 .function void R.ctor(R a0) <ctor> {
108 return.void
109 }
110
111 .function void R.CauseAbstractMethodException(R a0) <noimpl>
112
113 .record ProvokeAbstractMethodException {
114 }
115
116 .function i32 ProvokeAbstractMethodException.main() <static> {
117 try_begin:
118 initobj R.ctor
119 sta.obj v0
120 call.short R.CauseAbstractMethodException, v0
121 try_end:
122 jmp no_exceptions
123 handler_begin_incorrect:
124 movi v0, 0x2
125 lda v0
126 return
127 handler_begin_correct:
128 movi v0, 0x0
129 lda v0
130 return
131 no_exceptions:
132 movi v0, 0xffffffffffffffff
133 lda v0
134 return
135
136 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
137 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
138 }
139 )";
140
TEST_F(PandaExceptionTest,AbstractMethodStaticCallShortINT)141 TEST_F(PandaExceptionTest, AbstractMethodStaticCallShortINT)
142 {
143 auto source = g_abstractMethodStaticCallShortIntSource;
144
145 CreateRuntime(ExType::INT);
146 pandasm::Parser parser;
147 auto res = parser.Parse(source);
148 ASSERT_TRUE(res);
149 auto pf = pandasm::AsmEmitter::Emit(res.Value());
150 ASSERT_NE(pf, nullptr);
151
152 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
153
154 classLinker->AddPandaFile(std::move(pf));
155
156 PandaString descriptor;
157
158 Class *klass =
159 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
160 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
161 ASSERT_NE(klass, nullptr);
162
163 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
164 ASSERT_NE(method, nullptr);
165
166 std::vector<Value> args;
167 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
168
169 int64_t expectedResult = 0;
170 int64_t unexpectedException = 2;
171 int64_t noExceptions = -1;
172
173 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
174 << "AbstractMethod exception should have been thrown, but another has";
175 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
176 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
177 }
178
179 /**
180 * This test is a core test that's supposed
181 * to provoke the AbstractMethodException, to catch it,
182 * and to return 0 as the result.
183 */
184 static auto g_abstractMethodStaticCallShortJitSource = R"(
185 .record panda.AbstractMethodError <external>
186
187 .record panda.Exception <external>
188
189 .record R {}
190
191 .function void R.ctor(R a0) <ctor> {
192 return.void
193 }
194
195 .function void R.CauseAbstractMethodException(R a0) <noimpl>
196
197 .record ProvokeAbstractMethodException {
198 }
199
200 .function i32 ProvokeAbstractMethodException.main() <static> {
201 try_begin:
202 initobj R.ctor
203 sta.obj v0
204 call.short R.CauseAbstractMethodException, v0
205 try_end:
206 jmp no_exceptions
207 handler_begin_incorrect:
208 movi v0, 0x2
209 lda v0
210 return
211 handler_begin_correct:
212 movi v0, 0x0
213 lda v0
214 return
215 no_exceptions:
216 movi v0, 0xffffffffffffffff
217 lda v0
218 return
219
220 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
221 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
222 }
223 )";
224
TEST_F(PandaExceptionTest,AbstractMethodStaticCallShortJIT)225 TEST_F(PandaExceptionTest, AbstractMethodStaticCallShortJIT)
226 {
227 CreateRuntime(ExType::JIT);
228
229 auto source = g_abstractMethodStaticCallShortJitSource;
230
231 pandasm::Parser parser;
232 auto res = parser.Parse(source);
233 ASSERT_TRUE(res);
234 auto pf = pandasm::AsmEmitter::Emit(res.Value());
235 ASSERT_NE(pf, nullptr);
236
237 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
238
239 classLinker->AddPandaFile(std::move(pf));
240
241 PandaString descriptor;
242
243 Class *klass =
244 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
245 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
246 ASSERT_NE(klass, nullptr);
247
248 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
249 ASSERT_NE(method, nullptr);
250
251 std::vector<Value> args;
252 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
253
254 int64_t expectedResult = 0;
255 int64_t unexpectedException = 2;
256 int64_t noExceptions = -1;
257
258 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
259 << "AbstractMethod exception should have been thrown, but another has";
260 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
261 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
262 }
263
264 /**
265 * This test is a core test that's supposed
266 * to provoke the AbstractMethodException, to catch it,
267 * and to return 0 as the result.
268 */
269 static auto g_abstractMethodStaticCallIntSource = R"(
270 .record panda.AbstractMethodError <external>
271
272 .record panda.Exception <external>
273
274 .record R {}
275
276 .function void R.ctor(R a0) <ctor> {
277 return.void
278 }
279
280 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
281
282 .record ProvokeAbstractMethodException {
283 }
284
285 .function i32 ProvokeAbstractMethodException.main() <static> {
286 try_begin:
287 movi v1, 1
288 movi v2, 2
289 movi v3, 3
290 initobj R.ctor
291 sta.obj v0
292 call R.CauseAbstractMethodException, v0, v1, v2, v3
293 try_end:
294 jmp no_exceptions
295 handler_begin_incorrect:
296 movi v0, 0x2
297 lda v0
298 return
299 handler_begin_correct:
300 movi v0, 0x0
301 lda v0
302 return
303 no_exceptions:
304 movi v0, 0xffffffffffffffff
305 lda v0
306 return
307
308 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
309 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
310 }
311 )";
312
TEST_F(PandaExceptionTest,AbstractMethodStaticCallINT)313 TEST_F(PandaExceptionTest, AbstractMethodStaticCallINT)
314 {
315 CreateRuntime(ExType::INT);
316
317 auto source = g_abstractMethodStaticCallIntSource;
318
319 pandasm::Parser parser;
320 auto res = parser.Parse(source);
321 ASSERT_TRUE(res);
322 auto pf = pandasm::AsmEmitter::Emit(res.Value());
323 ASSERT_NE(pf, nullptr);
324
325 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
326
327 classLinker->AddPandaFile(std::move(pf));
328
329 PandaString descriptor;
330
331 Class *klass =
332 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
333 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
334 ASSERT_NE(klass, nullptr);
335
336 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
337 ASSERT_NE(method, nullptr);
338
339 std::vector<Value> args;
340 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
341
342 int64_t expectedResult = 0;
343 int64_t unexpectedException = 2;
344 int64_t noExceptions = -1;
345
346 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
347 << "AbstractMethod exception should have been thrown, but another has";
348 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
349 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
350 }
351
352 /**
353 * This test is a core test that's supposed
354 * to provoke the AbstractMethodException, to catch it,
355 * and to return 0 as the result.
356 */
357
358 static auto g_abstractMethodStaticCallJitSource = R"(
359 .record panda.AbstractMethodError <external>
360
361 .record panda.Exception <external>
362
363 .record R {}
364
365 .function void R.ctor(R a0) <ctor> {
366 return.void
367 }
368
369 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
370
371 .record ProvokeAbstractMethodException {
372 }
373
374 .function i32 ProvokeAbstractMethodException.main() <static> {
375 try_begin:
376 movi v1, 1
377 movi v2, 2
378 movi v3, 3
379 initobj R.ctor
380 sta.obj v0
381 call R.CauseAbstractMethodException, v0, v1, v2, v3
382 try_end:
383 jmp no_exceptions
384 handler_begin_incorrect:
385 movi v0, 0x2
386 lda v0
387 return
388 handler_begin_correct:
389 movi v0, 0x0
390 lda v0
391 return
392 no_exceptions:
393 movi v0, 0xffffffffffffffff
394 lda v0
395 return
396
397 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
398 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
399 }
400 )";
401
TEST_F(PandaExceptionTest,AbstractMethodStaticCallJIT)402 TEST_F(PandaExceptionTest, AbstractMethodStaticCallJIT)
403 {
404 CreateRuntime(ExType::JIT);
405
406 auto source = g_abstractMethodStaticCallJitSource;
407
408 pandasm::Parser parser;
409 auto res = parser.Parse(source);
410 ASSERT_TRUE(res);
411 auto pf = pandasm::AsmEmitter::Emit(res.Value());
412 ASSERT_NE(pf, nullptr);
413
414 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
415
416 classLinker->AddPandaFile(std::move(pf));
417
418 PandaString descriptor;
419
420 Class *klass =
421 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
422 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
423 ASSERT_NE(klass, nullptr);
424
425 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
426 ASSERT_NE(method, nullptr);
427
428 std::vector<Value> args;
429 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
430
431 int64_t expectedResult = 0;
432 int64_t unexpectedException = 2;
433 int64_t noExceptions = -1;
434
435 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
436 << "AbstractMethod exception should have been thrown, but another has";
437 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
438 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
439 }
440
441 /**
442 * This test is a core test that's supposed
443 * to provoke the AbstractMethodException, to catch it,
444 * and to return 0 as the result.
445 */
446
447 static auto g_abstractMethodStaticCallRangeIntSource = R"(
448 .record panda.AbstractMethodError <external>
449
450 .record panda.Exception <external>
451
452 .record R {}
453
454 .function void R.ctor(R a0) <ctor> {
455 return.void
456 }
457
458 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
459
460 .record ProvokeAbstractMethodException {
461 }
462
463 .function i32 ProvokeAbstractMethodException.main() <static> {
464 try_begin:
465 initobj R.ctor
466 sta.obj v0
467 movi v1, 1
468 movi v2, 2
469 movi v3, 3
470 movi v4, 4
471 call.range R.CauseAbstractMethodException, v0
472 try_end:
473 jmp no_exceptions
474 handler_begin_incorrect:
475 movi v0, 0x2
476 lda v0
477 return
478 handler_begin_correct:
479 movi v0, 0x0
480 lda v0
481 return
482 no_exceptions:
483 movi v0, 0xffffffffffffffff
484 lda v0
485 return
486
487 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
488 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
489 }
490 )";
491
TEST_F(PandaExceptionTest,AbstractMethodStaticCallRangeINT)492 TEST_F(PandaExceptionTest, AbstractMethodStaticCallRangeINT)
493 {
494 CreateRuntime(ExType::INT);
495
496 auto source = g_abstractMethodStaticCallRangeIntSource;
497
498 pandasm::Parser parser;
499 auto res = parser.Parse(source);
500 ASSERT_TRUE(res);
501 auto pf = pandasm::AsmEmitter::Emit(res.Value());
502 ASSERT_NE(pf, nullptr);
503
504 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
505
506 classLinker->AddPandaFile(std::move(pf));
507
508 PandaString descriptor;
509
510 Class *klass =
511 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
512 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
513 ASSERT_NE(klass, nullptr);
514
515 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
516 ASSERT_NE(method, nullptr);
517
518 std::vector<Value> args;
519 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
520
521 int64_t expectedResult = 0;
522 int64_t unexpectedException = 2;
523 int64_t noExceptions = -1;
524
525 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
526 << "AbstractMethod exception should have been thrown, but another has";
527 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
528 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
529 }
530
531 /**
532 * This test is a core test that's supposed
533 * to provoke the AbstractMethodException, to catch it,
534 * and to return 0 as the result.
535 */
536
537 static auto g_abstractMethodStaticCallRangeJitSource = R"(
538 .record panda.AbstractMethodError <external>
539
540 .record panda.Exception <external>
541
542 .record R {}
543
544 .function void R.ctor(R a0) <ctor> {
545 return.void
546 }
547
548 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
549
550 .record ProvokeAbstractMethodException {
551 }
552
553 .function i32 ProvokeAbstractMethodException.main() <static> {
554 try_begin:
555 initobj R.ctor
556 sta.obj v0
557 movi v1, 1
558 movi v2, 2
559 movi v3, 3
560 movi v4, 4
561 call.range R.CauseAbstractMethodException, v0
562 try_end:
563 jmp no_exceptions
564 handler_begin_incorrect:
565 movi v0, 0x2
566 lda v0
567 return
568 handler_begin_correct:
569 movi v0, 0x0
570 lda v0
571 return
572 no_exceptions:
573 movi v0, 0xffffffffffffffff
574 lda v0
575 return
576
577 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
578 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
579 }
580 )";
581
TEST_F(PandaExceptionTest,AbstractMethodStaticCallRangeJIT)582 TEST_F(PandaExceptionTest, AbstractMethodStaticCallRangeJIT)
583 {
584 CreateRuntime(ExType::JIT);
585
586 auto source = g_abstractMethodStaticCallRangeJitSource;
587
588 pandasm::Parser parser;
589 auto res = parser.Parse(source);
590 ASSERT_TRUE(res);
591 auto pf = pandasm::AsmEmitter::Emit(res.Value());
592 ASSERT_NE(pf, nullptr);
593
594 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
595
596 classLinker->AddPandaFile(std::move(pf));
597
598 PandaString descriptor;
599
600 Class *klass =
601 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
602 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
603 ASSERT_NE(klass, nullptr);
604
605 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
606 ASSERT_NE(method, nullptr);
607
608 std::vector<Value> args;
609 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
610
611 int64_t expectedResult = 0;
612 int64_t unexpectedException = 2;
613 int64_t noExceptions = -1;
614
615 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
616 << "AbstractMethod exception should have been thrown, but another has";
617 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
618 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
619 }
620
621 /**
622 * This test is a core test that's supposed
623 * to provoke the AbstractMethodException, to catch it,
624 * and to return 0 as the result.
625 */
626
627 static auto g_abstractMethodStaticCallAccShortintSource = R"(
628 .record panda.AbstractMethodError <external>
629
630 .record panda.Exception <external>
631
632 .record R {}
633
634 .function void R.ctor(R a0) <ctor> {
635 return.void
636 }
637
638 .function void R.CauseAbstractMethodException(R a0) <noimpl>
639
640 .record ProvokeAbstractMethodException {
641 }
642
643 .function i32 ProvokeAbstractMethodException.main() <static> {
644 try_begin:
645 movi v0, 1
646 initobj R.ctor
647 call.acc.short R.CauseAbstractMethodException, v0, 0
648 try_end:
649 jmp no_exceptions
650 handler_begin_incorrect:
651 movi v0, 0x2
652 lda v0
653 return
654 handler_begin_correct:
655 movi v0, 0x0
656 lda v0
657 return
658 no_exceptions:
659 movi v0, 0xffffffffffffffff
660 lda v0
661 return
662
663 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
664 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
665 }
666 )";
667
TEST_F(PandaExceptionTest,AbstractMethodStaticCallAccShortINT)668 TEST_F(PandaExceptionTest, AbstractMethodStaticCallAccShortINT)
669 {
670 CreateRuntime(ExType::INT);
671
672 auto source = g_abstractMethodStaticCallAccShortintSource;
673
674 pandasm::Parser parser;
675 auto res = parser.Parse(source);
676 ASSERT_TRUE(res);
677 auto pf = pandasm::AsmEmitter::Emit(res.Value());
678 ASSERT_NE(pf, nullptr);
679
680 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
681
682 classLinker->AddPandaFile(std::move(pf));
683
684 PandaString descriptor;
685
686 Class *klass =
687 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
688 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
689 ASSERT_NE(klass, nullptr);
690
691 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
692 ASSERT_NE(method, nullptr);
693
694 std::vector<Value> args;
695 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
696
697 int64_t expectedResult = 0;
698 int64_t unexpectedException = 2;
699 int64_t noExceptions = -1;
700
701 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
702 << "AbstractMethod exception should have been thrown, but another has";
703 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
704 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
705 }
706
707 /**
708 * This test is a core test that's supposed
709 * to provoke the AbstractMethodException, to catch it,
710 * and to return 0 as the result.
711 */
712
713 static auto g_abstractMethodStaticCallAccShortJitSource = R"(
714 .record panda.AbstractMethodError <external>
715
716 .record panda.Exception <external>
717
718 .record R {}
719
720 .function void R.ctor(R a0) <ctor> {
721 return.void
722 }
723
724 .function void R.CauseAbstractMethodException(R a0) <noimpl>
725
726 .record ProvokeAbstractMethodException {
727 }
728
729 .function i32 ProvokeAbstractMethodException.main() <static> {
730 try_begin:
731 movi v0, 1
732 initobj R.ctor
733 call.acc.short R.CauseAbstractMethodException, v0, 0
734 try_end:
735 jmp no_exceptions
736 handler_begin_incorrect:
737 movi v0, 0x2
738 lda v0
739 return
740 handler_begin_correct:
741 movi v0, 0x0
742 lda v0
743 return
744 no_exceptions:
745 movi v0, 0xffffffffffffffff
746 lda v0
747 return
748
749 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
750 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
751 }
752 )";
753
TEST_F(PandaExceptionTest,AbstractMethodStaticCallAccShortJIT)754 TEST_F(PandaExceptionTest, AbstractMethodStaticCallAccShortJIT)
755 {
756 CreateRuntime(ExType::JIT);
757
758 auto source = g_abstractMethodStaticCallAccShortJitSource;
759
760 pandasm::Parser parser;
761 auto res = parser.Parse(source);
762 ASSERT_TRUE(res);
763 auto pf = pandasm::AsmEmitter::Emit(res.Value());
764 ASSERT_NE(pf, nullptr);
765
766 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
767
768 classLinker->AddPandaFile(std::move(pf));
769
770 PandaString descriptor;
771
772 Class *klass =
773 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
774 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
775 ASSERT_NE(klass, nullptr);
776
777 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
778 ASSERT_NE(method, nullptr);
779
780 std::vector<Value> args;
781 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
782
783 int64_t expectedResult = 0;
784 int64_t unexpectedException = 2;
785 int64_t noExceptions = -1;
786
787 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
788 << "AbstractMethod exception should have been thrown, but another has";
789 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
790 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
791 }
792
793 /**
794 * This test is a core test that's supposed
795 * to provoke the AbstractMethodException, to catch it,
796 * and to return 0 as the result.
797 */
798
799 static auto g_abstractMethodStaticCallAccIntSource = R"(
800 .record panda.AbstractMethodError <external>
801
802 .record panda.Exception <external>
803
804 .record R {}
805
806 .function void R.ctor(R a0) <ctor> {
807 return.void
808 }
809
810 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
811
812 .record ProvokeAbstractMethodException {
813 }
814
815 .function i32 ProvokeAbstractMethodException.main() <static> {
816 try_begin:
817 movi v0, 1
818 movi v1, 2
819 movi v2, 3
820 initobj R.ctor
821 call.acc R.CauseAbstractMethodException, v0, v1, v2, 0
822 try_end:
823 jmp no_exceptions
824 handler_begin_incorrect:
825 movi v0, 0x2
826 lda v0
827 return
828 handler_begin_correct:
829 movi v0, 0x0
830 lda v0
831 return
832 no_exceptions:
833 movi v0, 0xffffffffffffffff
834 lda v0
835 return
836
837 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
838 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
839 }
840 )";
841
TEST_F(PandaExceptionTest,AbstractMethodStaticCallAccINT)842 TEST_F(PandaExceptionTest, AbstractMethodStaticCallAccINT)
843 {
844 CreateRuntime(ExType::INT);
845
846 auto source = g_abstractMethodStaticCallAccIntSource;
847
848 pandasm::Parser parser;
849 auto res = parser.Parse(source);
850 ASSERT_TRUE(res);
851 auto pf = pandasm::AsmEmitter::Emit(res.Value());
852 ASSERT_NE(pf, nullptr);
853
854 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
855
856 classLinker->AddPandaFile(std::move(pf));
857
858 PandaString descriptor;
859
860 Class *klass =
861 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
862 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
863 ASSERT_NE(klass, nullptr);
864
865 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
866 ASSERT_NE(method, nullptr);
867
868 std::vector<Value> args;
869 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
870
871 int64_t expectedResult = 0;
872 int64_t unexpectedException = 2;
873 int64_t noExceptions = -1;
874
875 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
876 << "AbstractMethod exception should have been thrown, but another has";
877 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
878 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
879 }
880
881 /**
882 * This test is a core test that's supposed
883 * to provoke the AbstractMethodException, to catch it,
884 * and to return 0 as the result.
885 */
886
887 static auto g_abstractMethodStaticCallAccJitSource = R"(
888 .record panda.AbstractMethodError <external>
889
890 .record panda.Exception <external>
891
892 .record R {}
893
894 .function void R.ctor(R a0) <ctor> {
895 return.void
896 }
897
898 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
899
900 .record ProvokeAbstractMethodException {
901 }
902
903 .function i32 ProvokeAbstractMethodException.main() <static> {
904 try_begin:
905 movi v0, 1
906 movi v1, 2
907 movi v2, 3
908 initobj R.ctor
909 call.acc R.CauseAbstractMethodException, v0, v1, v2, 0
910 try_end:
911 jmp no_exceptions
912 handler_begin_incorrect:
913 movi v0, 0x2
914 lda v0
915 return
916 handler_begin_correct:
917 movi v0, 0x0
918 lda v0
919 return
920 no_exceptions:
921 movi v0, 0xffffffffffffffff
922 lda v0
923 return
924
925 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
926 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
927 }
928 )";
929
TEST_F(PandaExceptionTest,AbstractMethodStaticCallAccJIT)930 TEST_F(PandaExceptionTest, AbstractMethodStaticCallAccJIT)
931 {
932 CreateRuntime(ExType::JIT);
933
934 auto source = g_abstractMethodStaticCallAccJitSource;
935
936 pandasm::Parser parser;
937 auto res = parser.Parse(source);
938 ASSERT_TRUE(res);
939 auto pf = pandasm::AsmEmitter::Emit(res.Value());
940 ASSERT_NE(pf, nullptr);
941
942 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
943
944 classLinker->AddPandaFile(std::move(pf));
945
946 PandaString descriptor;
947
948 Class *klass =
949 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
950 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
951 ASSERT_NE(klass, nullptr);
952
953 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
954 ASSERT_NE(method, nullptr);
955
956 std::vector<Value> args;
957 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
958
959 int64_t expectedResult = 0;
960 int64_t unexpectedException = 2;
961 int64_t noExceptions = -1;
962
963 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
964 << "AbstractMethod exception should have been thrown, but another has";
965 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
966 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
967 }
968
969 /**
970 * This test is a core test that's supposed
971 * to provoke the AbstractMethodException, to catch it,
972 * and to return 0 as the result.
973 */
974
975 static auto g_abstractMethodVirtualCallShortIntSource = R"(
976 .record panda.AbstractMethodError <external>
977
978 .record panda.Exception <external>
979
980 .record R {}
981
982 .function void R.ctor(R a0) <ctor> {
983 return.void
984 }
985
986 .function void R.CauseAbstractMethodException(R a0) <noimpl>
987
988 .record ProvokeAbstractMethodException {
989 }
990
991 .function i32 ProvokeAbstractMethodException.main() <static> {
992 try_begin:
993 initobj R.ctor
994 sta.obj v0
995 call.virt.short R.CauseAbstractMethodException, v0
996 try_end:
997 jmp no_exceptions
998 handler_begin_incorrect:
999 movi v0, 0x2
1000 lda v0
1001 return
1002 handler_begin_correct:
1003 movi v0, 0x0
1004 lda v0
1005 return
1006 no_exceptions:
1007 movi v0, 0xffffffffffffffff
1008 lda v0
1009 return
1010
1011 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1012 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1013 }
1014 )";
1015
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallShortINT)1016 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallShortINT)
1017 {
1018 CreateRuntime(ExType::INT);
1019
1020 auto source = g_abstractMethodVirtualCallShortIntSource;
1021
1022 pandasm::Parser parser;
1023 auto res = parser.Parse(source);
1024 ASSERT_TRUE(res);
1025 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1026 ASSERT_NE(pf, nullptr);
1027
1028 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1029
1030 classLinker->AddPandaFile(std::move(pf));
1031
1032 PandaString descriptor;
1033
1034 Class *klass =
1035 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1036 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1037 ASSERT_NE(klass, nullptr);
1038
1039 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1040 ASSERT_NE(method, nullptr);
1041
1042 std::vector<Value> args;
1043 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1044
1045 int64_t expectedResult = 0;
1046 int64_t unexpectedException = 2;
1047 int64_t noExceptions = -1;
1048
1049 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1050 << "AbstractMethod exception should have been thrown, but another has";
1051 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1052 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1053 }
1054
1055 /**
1056 * This test is a core test that's supposed
1057 * to provoke the AbstractMethodException, to catch it,
1058 * and to return 0 as the result.
1059 */
1060
1061 static auto g_abstractMethodVirtualCallShortJitSource = R"(
1062 .record panda.AbstractMethodError <external>
1063
1064 .record panda.Exception <external>
1065
1066 .record R {}
1067
1068 .function void R.ctor(R a0) <ctor> {
1069 return.void
1070 }
1071
1072 .function void R.CauseAbstractMethodException(R a0) <noimpl>
1073
1074 .record ProvokeAbstractMethodException {
1075 }
1076
1077 .function i32 ProvokeAbstractMethodException.main() <static> {
1078 try_begin:
1079 initobj R.ctor
1080 sta.obj v0
1081 call.virt.short R.CauseAbstractMethodException, v0
1082 try_end:
1083 jmp no_exceptions
1084 handler_begin_incorrect:
1085 movi v0, 0x2
1086 lda v0
1087 return
1088 handler_begin_correct:
1089 movi v0, 0x0
1090 lda v0
1091 return
1092 no_exceptions:
1093 movi v0, 0xffffffffffffffff
1094 lda v0
1095 return
1096
1097 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1098 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1099 }
1100 )";
1101
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallShortJIT)1102 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallShortJIT)
1103 {
1104 CreateRuntime(ExType::JIT);
1105
1106 auto source = g_abstractMethodVirtualCallShortJitSource;
1107
1108 pandasm::Parser parser;
1109 auto res = parser.Parse(source);
1110 ASSERT_TRUE(res);
1111 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1112 ASSERT_NE(pf, nullptr);
1113
1114 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1115
1116 classLinker->AddPandaFile(std::move(pf));
1117
1118 PandaString descriptor;
1119
1120 Class *klass =
1121 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1122 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1123 ASSERT_NE(klass, nullptr);
1124
1125 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1126 ASSERT_NE(method, nullptr);
1127
1128 std::vector<Value> args;
1129 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1130
1131 int64_t expectedResult = 0;
1132 int64_t unexpectedException = 2;
1133 int64_t noExceptions = -1;
1134
1135 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1136 << "AbstractMethod exception should have been thrown, but another has";
1137 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1138 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1139 }
1140
1141 /**
1142 * This test is a core test that's supposed
1143 * to provoke the AbstractMethodException, to catch it,
1144 * and to return 0 as the result.
1145 */
1146
1147 static auto g_abstractMethodVirtualCallIntSource = R"(
1148 .record panda.AbstractMethodError <external>
1149
1150 .record panda.Exception <external>
1151
1152 .record R {}
1153
1154 .function void R.ctor(R a0) <ctor> {
1155 return.void
1156 }
1157
1158 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
1159
1160 .record ProvokeAbstractMethodException {
1161 }
1162
1163 .function i32 ProvokeAbstractMethodException.main() <static> {
1164 try_begin:
1165 movi v1, 1
1166 movi v2, 2
1167 movi v3, 3
1168 initobj R.ctor
1169 sta.obj v0
1170 call.virt R.CauseAbstractMethodException, v0, v1, v2, v3
1171 try_end:
1172 jmp no_exceptions
1173 handler_begin_incorrect:
1174 movi v0, 0x2
1175 lda v0
1176 return
1177 handler_begin_correct:
1178 movi v0, 0x0
1179 lda v0
1180 return
1181 no_exceptions:
1182 movi v0, 0xffffffffffffffff
1183 lda v0
1184 return
1185
1186 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1187 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1188 }
1189 )";
1190
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallINT)1191 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallINT)
1192 {
1193 CreateRuntime(ExType::INT);
1194
1195 auto source = g_abstractMethodVirtualCallIntSource;
1196
1197 pandasm::Parser parser;
1198 auto res = parser.Parse(source);
1199 ASSERT_TRUE(res);
1200 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1201 ASSERT_NE(pf, nullptr);
1202
1203 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1204
1205 classLinker->AddPandaFile(std::move(pf));
1206
1207 PandaString descriptor;
1208
1209 Class *klass =
1210 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1211 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1212 ASSERT_NE(klass, nullptr);
1213
1214 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1215 ASSERT_NE(method, nullptr);
1216
1217 std::vector<Value> args;
1218 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1219
1220 int64_t expectedResult = 0;
1221 int64_t unexpectedException = 2;
1222 int64_t noExceptions = -1;
1223
1224 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1225 << "AbstractMethod exception should have been thrown, but another has";
1226 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1227 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1228 }
1229
1230 /**
1231 * This test is a core test that's supposed
1232 * to provoke the AbstractMethodException, to catch it,
1233 * and to return 0 as the result.
1234 */
1235
1236 static auto g_abstractMethodVirtualCallJitSource = R"(
1237 .record panda.AbstractMethodError <external>
1238
1239 .record panda.Exception <external>
1240
1241 .record R {}
1242
1243 .function void R.ctor(R a0) <ctor> {
1244 return.void
1245 }
1246
1247 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
1248
1249 .record ProvokeAbstractMethodException {
1250 }
1251
1252 .function i32 ProvokeAbstractMethodException.main() <static> {
1253 try_begin:
1254 movi v1, 1
1255 movi v2, 2
1256 movi v3, 3
1257 initobj R.ctor
1258 sta.obj v0
1259 call.virt R.CauseAbstractMethodException, v0, v1, v2, v3
1260 try_end:
1261 jmp no_exceptions
1262 handler_begin_incorrect:
1263 movi v0, 0x2
1264 lda v0
1265 return
1266 handler_begin_correct:
1267 movi v0, 0x0
1268 lda v0
1269 return
1270 no_exceptions:
1271 movi v0, 0xffffffffffffffff
1272 lda v0
1273 return
1274
1275 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1276 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1277 }
1278 )";
1279
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallJIT)1280 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallJIT)
1281 {
1282 CreateRuntime(ExType::JIT);
1283
1284 auto source = g_abstractMethodVirtualCallJitSource;
1285
1286 pandasm::Parser parser;
1287 auto res = parser.Parse(source);
1288 ASSERT_TRUE(res);
1289 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1290 ASSERT_NE(pf, nullptr);
1291
1292 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1293
1294 classLinker->AddPandaFile(std::move(pf));
1295
1296 PandaString descriptor;
1297
1298 Class *klass =
1299 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1300 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1301 ASSERT_NE(klass, nullptr);
1302
1303 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1304 ASSERT_NE(method, nullptr);
1305
1306 std::vector<Value> args;
1307 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1308
1309 int64_t expectedResult = 0;
1310 int64_t unexpectedException = 2;
1311 int64_t noExceptions = -1;
1312
1313 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1314 << "AbstractMethod exception should have been thrown, but another has";
1315 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1316 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1317 }
1318
1319 /**
1320 * This test is a core test that's supposed
1321 * to provoke the AbstractMethodException, to catch it,
1322 * and to return 0 as the result.
1323 */
1324
1325 static auto g_abstractMethodVirtualCallRangeIntSource = R"(
1326 .record panda.AbstractMethodError <external>
1327
1328 .record panda.Exception <external>
1329
1330 .record R {}
1331
1332 .function void R.ctor(R a0) <ctor> {
1333 return.void
1334 }
1335
1336 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
1337
1338 .record ProvokeAbstractMethodException {
1339 }
1340
1341 .function i32 ProvokeAbstractMethodException.main() <static> {
1342 try_begin:
1343 initobj R.ctor
1344 sta.obj v0
1345 movi v1, 1
1346 movi v2, 2
1347 movi v3, 3
1348 movi v4, 4
1349 call.virt.range R.CauseAbstractMethodException, v0
1350 try_end:
1351 jmp no_exceptions
1352 handler_begin_incorrect:
1353 movi v0, 0x2
1354 lda v0
1355 return
1356 handler_begin_correct:
1357 movi v0, 0x0
1358 lda v0
1359 return
1360 no_exceptions:
1361 movi v0, 0xffffffffffffffff
1362 lda v0
1363 return
1364
1365 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1366 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1367 }
1368 )";
1369
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallRangeINT)1370 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallRangeINT)
1371 {
1372 CreateRuntime(ExType::INT);
1373
1374 auto source = g_abstractMethodVirtualCallRangeIntSource;
1375
1376 pandasm::Parser parser;
1377 auto res = parser.Parse(source);
1378 ASSERT_TRUE(res);
1379 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1380 ASSERT_NE(pf, nullptr);
1381
1382 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1383
1384 classLinker->AddPandaFile(std::move(pf));
1385
1386 PandaString descriptor;
1387
1388 Class *klass =
1389 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1390 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1391 ASSERT_NE(klass, nullptr);
1392
1393 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1394 ASSERT_NE(method, nullptr);
1395
1396 std::vector<Value> args;
1397 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1398
1399 int64_t expectedResult = 0;
1400 int64_t unexpectedException = 2;
1401 int64_t noExceptions = -1;
1402
1403 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1404 << "AbstractMethod exception should have been thrown, but another has";
1405 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1406 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1407 }
1408
1409 /**
1410 * This test is a core test that's supposed
1411 * to provoke the AbstractMethodException, to catch it,
1412 * and to return 0 as the result.
1413 */
1414
1415 static auto g_abstractMethodVirtualCallRangeJitSource = R"(
1416 .record panda.AbstractMethodError <external>
1417
1418 .record panda.Exception <external>
1419
1420 .record R {}
1421
1422 .function void R.ctor(R a0) <ctor> {
1423 return.void
1424 }
1425
1426 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
1427
1428 .record ProvokeAbstractMethodException {
1429 }
1430
1431 .function i32 ProvokeAbstractMethodException.main() <static> {
1432 try_begin:
1433 initobj R.ctor
1434 sta.obj v0
1435 movi v1, 1
1436 movi v2, 2
1437 movi v3, 3
1438 movi v4, 4
1439 call.virt.range R.CauseAbstractMethodException, v0
1440 try_end:
1441 jmp no_exceptions
1442 handler_begin_incorrect:
1443 movi v0, 0x2
1444 lda v0
1445 return
1446 handler_begin_correct:
1447 movi v0, 0x0
1448 lda v0
1449 return
1450 no_exceptions:
1451 movi v0, 0xffffffffffffffff
1452 lda v0
1453 return
1454
1455 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1456 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1457 }
1458 )";
1459
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallRangeJIT)1460 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallRangeJIT)
1461 {
1462 CreateRuntime(ExType::JIT);
1463
1464 auto source = g_abstractMethodVirtualCallRangeJitSource;
1465
1466 pandasm::Parser parser;
1467 auto res = parser.Parse(source);
1468 ASSERT_TRUE(res);
1469 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1470 ASSERT_NE(pf, nullptr);
1471
1472 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1473
1474 classLinker->AddPandaFile(std::move(pf));
1475
1476 PandaString descriptor;
1477
1478 Class *klass =
1479 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1480 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1481 ASSERT_NE(klass, nullptr);
1482
1483 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1484 ASSERT_NE(method, nullptr);
1485
1486 std::vector<Value> args;
1487 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1488
1489 int64_t expectedResult = 0;
1490 int64_t unexpectedException = 2;
1491 int64_t noExceptions = -1;
1492
1493 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1494 << "AbstractMethod exception should have been thrown, but another has";
1495 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1496 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1497 }
1498
1499 /**
1500 * This test is a core test that's supposed
1501 * to provoke the AbstractMethodException, to catch it,
1502 * and to return 0 as the result.
1503 */
1504
1505 static auto g_abstractMethodVirtualCallAccShortIntSource = R"(
1506 .record panda.AbstractMethodError <external>
1507
1508 .record panda.Exception <external>
1509
1510 .record R {}
1511
1512 .function void R.ctor(R a0) <ctor> {
1513 return.void
1514 }
1515
1516 .function void R.CauseAbstractMethodException(R a0) <noimpl>
1517
1518 .record ProvokeAbstractMethodException {
1519 }
1520
1521 .function i32 ProvokeAbstractMethodException.main() <static> {
1522 try_begin:
1523 movi v0, 1
1524 initobj R.ctor
1525 call.virt.acc.short R.CauseAbstractMethodException, v0, 0
1526 try_end:
1527 jmp no_exceptions
1528 handler_begin_incorrect:
1529 movi v0, 0x2
1530 lda v0
1531 return
1532 handler_begin_correct:
1533 movi v0, 0x0
1534 lda v0
1535 return
1536 no_exceptions:
1537 movi v0, 0xffffffffffffffff
1538 lda v0
1539 return
1540
1541 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1542 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1543 }
1544 )";
1545
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallAccShortINT)1546 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallAccShortINT)
1547 {
1548 CreateRuntime(ExType::INT);
1549
1550 auto source = g_abstractMethodVirtualCallAccShortIntSource;
1551
1552 pandasm::Parser parser;
1553 auto res = parser.Parse(source);
1554 ASSERT_TRUE(res);
1555 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1556 ASSERT_NE(pf, nullptr);
1557
1558 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1559
1560 classLinker->AddPandaFile(std::move(pf));
1561
1562 PandaString descriptor;
1563
1564 Class *klass =
1565 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1566 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1567 ASSERT_NE(klass, nullptr);
1568
1569 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1570 ASSERT_NE(method, nullptr);
1571
1572 std::vector<Value> args;
1573 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1574
1575 int64_t expectedResult = 0;
1576 int64_t unexpectedException = 2;
1577 int64_t noExceptions = -1;
1578
1579 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1580 << "AbstractMethod exception should have been thrown, but another has";
1581 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1582 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1583 }
1584
1585 /**
1586 * This test is a core test that's supposed
1587 * to provoke the AbstractMethodException, to catch it,
1588 * and to return 0 as the result.
1589 */
1590
1591 static auto g_abstractMethodVirtualCallAccShortJitSource = R"(
1592 .record panda.AbstractMethodError <external>
1593
1594 .record panda.Exception <external>
1595
1596 .record R {}
1597
1598 .function void R.ctor(R a0) <ctor> {
1599 return.void
1600 }
1601
1602 .function void R.CauseAbstractMethodException(R a0) <noimpl>
1603
1604 .record ProvokeAbstractMethodException {
1605 }
1606
1607 .function i32 ProvokeAbstractMethodException.main() <static> {
1608 try_begin:
1609 movi v0, 1
1610 initobj R.ctor
1611 call.virt.acc.short R.CauseAbstractMethodException, v0, 0
1612 try_end:
1613 jmp no_exceptions
1614 handler_begin_incorrect:
1615 movi v0, 0x2
1616 lda v0
1617 return
1618 handler_begin_correct:
1619 movi v0, 0x0
1620 lda v0
1621 return
1622 no_exceptions:
1623 movi v0, 0xffffffffffffffff
1624 lda v0
1625 return
1626
1627 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1628 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1629 }
1630 )";
1631
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallAccShortJIT)1632 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallAccShortJIT)
1633 {
1634 CreateRuntime(ExType::JIT);
1635
1636 auto source = g_abstractMethodVirtualCallAccShortJitSource;
1637
1638 pandasm::Parser parser;
1639 auto res = parser.Parse(source);
1640 ASSERT_TRUE(res);
1641 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1642 ASSERT_NE(pf, nullptr);
1643
1644 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1645
1646 classLinker->AddPandaFile(std::move(pf));
1647
1648 PandaString descriptor;
1649
1650 Class *klass =
1651 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1652 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1653 ASSERT_NE(klass, nullptr);
1654
1655 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1656 ASSERT_NE(method, nullptr);
1657
1658 std::vector<Value> args;
1659 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1660
1661 int64_t expectedResult = 0;
1662 int64_t unexpectedException = 2;
1663 int64_t noExceptions = -1;
1664
1665 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1666 << "AbstractMethod exception should have been thrown, but another has";
1667 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1668 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1669 }
1670
1671 /**
1672 * This test is a core test that's supposed
1673 * to provoke the AbstractMethodException, to catch it,
1674 * and to return 0 as the result.
1675 */
1676
1677 static auto g_abstractMethodVirtualCallAccIntSource = R"(
1678 .record panda.AbstractMethodError <external>
1679
1680 .record panda.Exception <external>
1681
1682 .record R {}
1683
1684 .function void R.ctor(R a0) <ctor> {
1685 return.void
1686 }
1687
1688 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
1689
1690 .record ProvokeAbstractMethodException {
1691 }
1692
1693 .function i32 ProvokeAbstractMethodException.main() <static> {
1694 try_begin:
1695 movi v0, 1
1696 movi v1, 2
1697 movi v2, 3
1698 initobj R.ctor
1699 call.virt.acc R.CauseAbstractMethodException, v0, v1, v2, 0
1700 try_end:
1701 jmp no_exceptions
1702 handler_begin_incorrect:
1703 movi v0, 0x2
1704 lda v0
1705 return
1706 handler_begin_correct:
1707 movi v0, 0x0
1708 lda v0
1709 return
1710 no_exceptions:
1711 movi v0, 0xffffffffffffffff
1712 lda v0
1713 return
1714
1715 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1716 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1717 }
1718 )";
1719
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallAccINT)1720 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallAccINT)
1721 {
1722 CreateRuntime(ExType::INT);
1723
1724 auto source = g_abstractMethodVirtualCallAccIntSource;
1725
1726 pandasm::Parser parser;
1727 auto res = parser.Parse(source);
1728 ASSERT_TRUE(res);
1729 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1730 ASSERT_NE(pf, nullptr);
1731
1732 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1733
1734 classLinker->AddPandaFile(std::move(pf));
1735
1736 PandaString descriptor;
1737
1738 Class *klass =
1739 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1740 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1741 ASSERT_NE(klass, nullptr);
1742
1743 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1744 ASSERT_NE(method, nullptr);
1745
1746 std::vector<Value> args;
1747 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1748
1749 int64_t expectedResult = 0;
1750 int64_t unexpectedException = 2;
1751 int64_t noExceptions = -1;
1752
1753 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1754 << "AbstractMethod exception should have been thrown, but another has";
1755 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1756 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1757 }
1758
1759 /**
1760 * This test is a core test that's supposed
1761 * to provoke the AbstractMethodException, to catch it,
1762 * and to return 0 as the result.
1763 */
1764
1765 static auto g_abstractMethodVirtualCallAccJitSource = R"(
1766 .record panda.AbstractMethodError <external>
1767
1768 .record panda.Exception <external>
1769
1770 .record R {}
1771
1772 .function void R.ctor(R a0) <ctor> {
1773 return.void
1774 }
1775
1776 .function void R.CauseAbstractMethodException(R a0, i32 a1, i32 a2, i32 a3) <noimpl>
1777
1778 .record ProvokeAbstractMethodException {
1779 }
1780
1781 .function i32 ProvokeAbstractMethodException.main() <static> {
1782 try_begin:
1783 movi v0, 1
1784 movi v1, 2
1785 movi v2, 3
1786 initobj R.ctor
1787 call.virt.acc R.CauseAbstractMethodException, v0, v1, v2, 0
1788 try_end:
1789 jmp no_exceptions
1790 handler_begin_incorrect:
1791 movi v0, 0x2
1792 lda v0
1793 return
1794 handler_begin_correct:
1795 movi v0, 0x0
1796 lda v0
1797 return
1798 no_exceptions:
1799 movi v0, 0xffffffffffffffff
1800 lda v0
1801 return
1802
1803 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1804 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1805 }
1806 )";
1807
TEST_F(PandaExceptionTest,AbstractMethodVirtualCallAccJIT)1808 TEST_F(PandaExceptionTest, AbstractMethodVirtualCallAccJIT)
1809 {
1810 CreateRuntime(ExType::JIT);
1811
1812 auto source = g_abstractMethodVirtualCallAccJitSource;
1813
1814 pandasm::Parser parser;
1815 auto res = parser.Parse(source);
1816 ASSERT_TRUE(res);
1817 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1818 ASSERT_NE(pf, nullptr);
1819
1820 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1821
1822 classLinker->AddPandaFile(std::move(pf));
1823
1824 PandaString descriptor;
1825
1826 Class *klass =
1827 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1828 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1829 ASSERT_NE(klass, nullptr);
1830
1831 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1832 ASSERT_NE(method, nullptr);
1833
1834 std::vector<Value> args;
1835 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1836
1837 int64_t expectedResult = 0;
1838 int64_t unexpectedException = 2;
1839 int64_t noExceptions = -1;
1840
1841 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1842 << "AbstractMethod exception should have been thrown, but another has";
1843 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1844 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1845 }
1846
1847 /**
1848 * This test is a core test that's supposed
1849 * to provoke the AbstractMethodException, to catch it,
1850 * and to return 0 as the result.
1851 */
1852
1853 static auto g_abstractMethodInitObjectShortIntSource = R"(
1854 .record panda.AbstractMethodError <external>
1855
1856 .record panda.Exception <external>
1857
1858 .record R {}
1859
1860 .function void R.ctor(R a0) <noimpl>
1861
1862 .record ProvokeAbstractMethodException {
1863 }
1864
1865 .function i32 ProvokeAbstractMethodException.main() <static> {
1866 try_begin:
1867 initobj.short R.ctor
1868 sta.obj v0
1869 try_end:
1870 jmp no_exceptions
1871 handler_begin_incorrect:
1872 movi v0, 0x2
1873 lda v0
1874 return
1875 handler_begin_correct:
1876 movi v0, 0x0
1877 lda v0
1878 return
1879 no_exceptions:
1880 movi v0, 0xffffffffffffffff
1881 lda v0
1882 return
1883
1884 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1885 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1886 }
1887 )";
1888
TEST_F(PandaExceptionTest,AbstractMethodInitObjectShortINT)1889 TEST_F(PandaExceptionTest, AbstractMethodInitObjectShortINT)
1890 {
1891 CreateRuntime(ExType::INT);
1892
1893 auto source = g_abstractMethodInitObjectShortIntSource;
1894
1895 pandasm::Parser parser;
1896 auto res = parser.Parse(source);
1897 ASSERT_TRUE(res);
1898 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1899 ASSERT_NE(pf, nullptr);
1900
1901 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1902
1903 classLinker->AddPandaFile(std::move(pf));
1904
1905 PandaString descriptor;
1906
1907 Class *klass =
1908 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1909 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1910 ASSERT_NE(klass, nullptr);
1911
1912 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1913 ASSERT_NE(method, nullptr);
1914
1915 std::vector<Value> args;
1916 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1917
1918 int64_t expectedResult = 0;
1919 int64_t unexpectedException = 2;
1920 int64_t noExceptions = -1;
1921
1922 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
1923 << "AbstractMethod exception should have been thrown, but another has";
1924 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
1925 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
1926 }
1927
1928 /**
1929 * This test is a core test that's supposed
1930 * to provoke the AbstractMethodException, to catch it,
1931 * and to return 0 as the result.
1932 */
1933
1934 static auto g_abstractMethodInitObjectShortJitSource = R"(
1935 .record panda.AbstractMethodError <external>
1936
1937 .record panda.Exception <external>
1938
1939 .record R {}
1940
1941 .function void R.ctor(R a0) <noimpl>
1942
1943 .record ProvokeAbstractMethodException {
1944 }
1945
1946 .function i32 ProvokeAbstractMethodException.main() <static> {
1947 try_begin:
1948 initobj.short R.ctor
1949 sta.obj v0
1950 try_end:
1951 jmp no_exceptions
1952 handler_begin_incorrect:
1953 movi v0, 0x2
1954 lda v0
1955 return
1956 handler_begin_correct:
1957 movi v0, 0x0
1958 lda v0
1959 return
1960 no_exceptions:
1961 movi v0, 0xffffffffffffffff
1962 lda v0
1963 return
1964
1965 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
1966 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
1967 }
1968 )";
1969
TEST_F(PandaExceptionTest,AbstractMethodInitObjectShortJIT)1970 TEST_F(PandaExceptionTest, AbstractMethodInitObjectShortJIT)
1971 {
1972 CreateRuntime(ExType::JIT);
1973
1974 auto source = g_abstractMethodInitObjectShortJitSource;
1975
1976 pandasm::Parser parser;
1977 auto res = parser.Parse(source);
1978 ASSERT_TRUE(res);
1979 auto pf = pandasm::AsmEmitter::Emit(res.Value());
1980 ASSERT_NE(pf, nullptr);
1981
1982 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
1983
1984 classLinker->AddPandaFile(std::move(pf));
1985
1986 PandaString descriptor;
1987
1988 Class *klass =
1989 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
1990 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
1991 ASSERT_NE(klass, nullptr);
1992
1993 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
1994 ASSERT_NE(method, nullptr);
1995
1996 std::vector<Value> args;
1997 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
1998
1999 int64_t expectedResult = 0;
2000 int64_t unexpectedException = 2;
2001 int64_t noExceptions = -1;
2002
2003 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
2004 << "AbstractMethod exception should have been thrown, but another has";
2005 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
2006 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
2007 }
2008
2009 /**
2010 * This test is a core test that's supposed
2011 * to provoke the AbstractMethodException, to catch it,
2012 * and to return 0 as the result.
2013 */
2014
2015 static auto g_abstractMethodInitObjectIntSource = R"(
2016 .record panda.AbstractMethodError <external>
2017
2018 .record panda.Exception <external>
2019
2020 .record R {}
2021
2022 .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
2023
2024 .record ProvokeAbstractMethodException {
2025 }
2026
2027 .function i32 ProvokeAbstractMethodException.main() <static> {
2028 try_begin:
2029 movi v0, 0
2030 movi v1, 1
2031 movi v2, 2
2032 movi v3, 3
2033 initobj R.ctor, v0, v1, v2, v3
2034 sta.obj v0
2035 try_end:
2036 jmp no_exceptions
2037 handler_begin_incorrect:
2038 movi v0, 0x2
2039 lda v0
2040 return
2041 handler_begin_correct:
2042 movi v0, 0x0
2043 lda v0
2044 return
2045 no_exceptions:
2046 movi v0, 0xffffffffffffffff
2047 lda v0
2048 return
2049
2050 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
2051 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
2052 }
2053 )";
2054
TEST_F(PandaExceptionTest,AbstractMethodInitObjectINT)2055 TEST_F(PandaExceptionTest, AbstractMethodInitObjectINT)
2056 {
2057 CreateRuntime(ExType::INT);
2058
2059 auto source = g_abstractMethodInitObjectIntSource;
2060
2061 pandasm::Parser parser;
2062 auto res = parser.Parse(source);
2063 ASSERT_TRUE(res);
2064 auto pf = pandasm::AsmEmitter::Emit(res.Value());
2065 ASSERT_NE(pf, nullptr);
2066
2067 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
2068
2069 classLinker->AddPandaFile(std::move(pf));
2070
2071 PandaString descriptor;
2072
2073 Class *klass =
2074 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
2075 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
2076 ASSERT_NE(klass, nullptr);
2077
2078 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
2079 ASSERT_NE(method, nullptr);
2080
2081 std::vector<Value> args;
2082 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
2083
2084 int64_t expectedResult = 0;
2085 int64_t unexpectedException = 2;
2086 int64_t noExceptions = -1;
2087
2088 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
2089 << "AbstractMethod exception should have been thrown, but another has";
2090 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
2091 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
2092 }
2093
2094 /**
2095 * This test is a core test that's supposed
2096 * to provoke the AbstractMethodException, to catch it,
2097 * and to return 0 as the result.
2098 */
2099
2100 static auto g_abstractMethodInitObjectJitSource = R"(
2101 .record panda.AbstractMethodError <external>
2102
2103 .record panda.Exception <external>
2104
2105 .record R {}
2106
2107 .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <noimpl>
2108
2109 .record ProvokeAbstractMethodException {
2110 }
2111
2112 .function i32 ProvokeAbstractMethodException.main() <static> {
2113 try_begin:
2114 movi v0, 0
2115 movi v1, 1
2116 movi v2, 2
2117 movi v3, 3
2118 initobj R.ctor, v0, v1, v2, v3
2119 sta.obj v0
2120 try_end:
2121 jmp no_exceptions
2122 handler_begin_incorrect:
2123 movi v0, 0x2
2124 lda v0
2125 return
2126 handler_begin_correct:
2127 movi v0, 0x0
2128 lda v0
2129 return
2130 no_exceptions:
2131 movi v0, 0xffffffffffffffff
2132 lda v0
2133 return
2134
2135 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
2136 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
2137 }
2138 )";
2139
TEST_F(PandaExceptionTest,AbstractMethodInitObjectJIT)2140 TEST_F(PandaExceptionTest, AbstractMethodInitObjectJIT)
2141 {
2142 CreateRuntime(ExType::JIT);
2143
2144 auto source = g_abstractMethodInitObjectJitSource;
2145
2146 pandasm::Parser parser;
2147 auto res = parser.Parse(source);
2148 ASSERT_TRUE(res);
2149 auto pf = pandasm::AsmEmitter::Emit(res.Value());
2150 ASSERT_NE(pf, nullptr);
2151
2152 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
2153
2154 classLinker->AddPandaFile(std::move(pf));
2155
2156 PandaString descriptor;
2157
2158 Class *klass =
2159 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
2160 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
2161 ASSERT_NE(klass, nullptr);
2162
2163 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
2164 ASSERT_NE(method, nullptr);
2165
2166 std::vector<Value> args;
2167 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
2168
2169 int64_t expectedResult = 0;
2170 int64_t unexpectedException = 2;
2171 int64_t noExceptions = -1;
2172
2173 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
2174 << "AbstractMethod exception should have been thrown, but another has";
2175 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
2176 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
2177 }
2178
2179 /**
2180 * This test is a core test that's supposed
2181 * to provoke the AbstractMethodException, to catch it,
2182 * and to return 0 as the result.
2183 */
2184
2185 static auto g_abstractMethodInitObjectRangeIntSource = R"(
2186 .record panda.AbstractMethodError <external>
2187
2188 .record panda.Exception <external>
2189
2190 .record R {}
2191
2192 .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5) <noimpl>
2193
2194 .record ProvokeAbstractMethodException {
2195 }
2196
2197 .function i32 ProvokeAbstractMethodException.main() <static> {
2198 try_begin:
2199 movi v0, 0
2200 movi v1, 1
2201 movi v2, 2
2202 movi v3, 3
2203 movi v4, 4
2204 initobj.range R.ctor, v0
2205 sta.obj v0
2206 try_end:
2207 jmp no_exceptions
2208 handler_begin_incorrect:
2209 movi v0, 0x2
2210 lda v0
2211 return
2212 handler_begin_correct:
2213 movi v0, 0x0
2214 lda v0
2215 return
2216 no_exceptions:
2217 movi v0, 0xffffffffffffffff
2218 lda v0
2219 return
2220
2221 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
2222 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
2223 }
2224 )";
2225
TEST_F(PandaExceptionTest,AbstractMethodInitObjectRangeINT)2226 TEST_F(PandaExceptionTest, AbstractMethodInitObjectRangeINT)
2227 {
2228 CreateRuntime(ExType::INT);
2229
2230 auto source = g_abstractMethodInitObjectRangeIntSource;
2231
2232 pandasm::Parser parser;
2233 auto res = parser.Parse(source);
2234 ASSERT_TRUE(res);
2235 auto pf = pandasm::AsmEmitter::Emit(res.Value());
2236 ASSERT_NE(pf, nullptr);
2237
2238 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
2239
2240 classLinker->AddPandaFile(std::move(pf));
2241
2242 PandaString descriptor;
2243
2244 Class *klass =
2245 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
2246 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
2247 ASSERT_NE(klass, nullptr);
2248
2249 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
2250 ASSERT_NE(method, nullptr);
2251
2252 std::vector<Value> args;
2253 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
2254
2255 int64_t expectedResult = 0;
2256 int64_t unexpectedException = 2;
2257 int64_t noExceptions = -1;
2258
2259 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
2260 << "AbstractMethod exception should have been thrown, but another has";
2261 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
2262 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
2263 }
2264
2265 /**
2266 * This test is a core test that's supposed
2267 * to provoke the AbstractMethodException, to catch it,
2268 * and to return 0 as the result.
2269 */
2270
2271 static auto g_abstractMethodInitObjectRangeJitSource = R"(
2272 .record panda.AbstractMethodError <external>
2273
2274 .record panda.Exception <external>
2275
2276 .record R {}
2277
2278 .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5) <noimpl>
2279
2280 .record ProvokeAbstractMethodException {
2281 }
2282
2283 .function i32 ProvokeAbstractMethodException.main() <static> {
2284 try_begin:
2285 movi v0, 0
2286 movi v1, 1
2287 movi v2, 2
2288 movi v3, 3
2289 movi v4, 4
2290 initobj.range R.ctor, v0
2291 sta.obj v0
2292 try_end:
2293 jmp no_exceptions
2294 handler_begin_incorrect:
2295 movi v0, 0x2
2296 lda v0
2297 return
2298 handler_begin_correct:
2299 movi v0, 0x0
2300 lda v0
2301 return
2302 no_exceptions:
2303 movi v0, 0xffffffffffffffff
2304 lda v0
2305 return
2306
2307 .catch panda.AbstractMethodError, try_begin, try_end, handler_begin_correct
2308 .catch panda.Exception, try_begin, try_end, handler_begin_incorrect
2309 }
2310 )";
2311
TEST_F(PandaExceptionTest,AbstractMethodInitObjectRangeJIT)2312 TEST_F(PandaExceptionTest, AbstractMethodInitObjectRangeJIT)
2313 {
2314 CreateRuntime(ExType::JIT);
2315
2316 auto source = g_abstractMethodInitObjectRangeJitSource;
2317
2318 pandasm::Parser parser;
2319 auto res = parser.Parse(source);
2320 ASSERT_TRUE(res);
2321 auto pf = pandasm::AsmEmitter::Emit(res.Value());
2322 ASSERT_NE(pf, nullptr);
2323
2324 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
2325
2326 classLinker->AddPandaFile(std::move(pf));
2327
2328 PandaString descriptor;
2329
2330 Class *klass =
2331 classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
2332 ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("ProvokeAbstractMethodException"), &descriptor));
2333 ASSERT_NE(klass, nullptr);
2334
2335 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
2336 ASSERT_NE(method, nullptr);
2337
2338 std::vector<Value> args;
2339 Value result = method->Invoke(ManagedThread::GetCurrent(), args.data());
2340
2341 int64_t expectedResult = 0;
2342 int64_t unexpectedException = 2;
2343 int64_t noExceptions = -1;
2344
2345 ASSERT_NE(result.GetAs<int64_t>(), unexpectedException)
2346 << "AbstractMethod exception should have been thrown, but another has";
2347 ASSERT_NE(result.GetAs<int64_t>(), noExceptions) << "No exceptions were thrown";
2348 ASSERT_EQ(result.GetAs<int64_t>(), expectedResult) << "Unexpected error";
2349 }
2350
2351 } // namespace ark::test