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