• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gmock/gmock.h>
17 #include <gtest/gtest.h>
18 
19 #include "assembly-parser.h"
20 #include "libpandabase/mem/pool_manager.h"
21 #include "libpandabase/utils/utf.h"
22 #include "libpandabase/utils/utils.h"
23 #include "libpandafile/bytecode_emitter.h"
24 #include "libpandafile/file.h"
25 #include "libpandafile/file_items.h"
26 #include "libpandafile/value.h"
27 #include "runtime/bridge/bridge.h"
28 #include "runtime/include/class_linker.h"
29 #include "runtime/include/compiler_interface.h"
30 #include "runtime/include/mem/allocator.h"
31 #include "runtime/include/method.h"
32 #include "runtime/include/runtime.h"
33 #include "runtime/include/runtime_options.h"
34 #include "runtime/include/thread_scopes.h"
35 #include "runtime/interpreter/frame.h"
36 #include "runtime/mem/gc/gc.h"
37 #include "runtime/mem/internal_allocator.h"
38 #include "runtime/core/core_class_linker_extension.h"
39 #include "runtime/tests/class_linker_test_extension.h"
40 #include "runtime/tests/interpreter/test_interpreter.h"
41 #include "runtime/tests/interpreter/test_runtime_interface.h"
42 #include "runtime/include/coretypes/dyn_objects.h"
43 #include "runtime/include/hclass.h"
44 #include "runtime/handle_base-inl.h"
45 #include "runtime/handle_scope-inl.h"
46 #include "runtime/include/coretypes/native_pointer.h"
47 #include "runtime/tests/test_utils.h"
48 #include "libpandabase/test_utilities.h"
49 
50 // NOLINTBEGIN(readability-magic-numbers)
51 
52 namespace panda::interpreter::test {
53 
54 using DynClass = panda::coretypes::DynClass;
55 using DynObject = panda::coretypes::DynObject;
56 
57 class InterpreterTest : public testing::Test {
58 public:
InterpreterTest()59     InterpreterTest()
60     {
61         RuntimeOptions options;
62         options.SetShouldLoadBootPandaFiles(false);
63         options.SetShouldInitializeIntrinsics(false);
64         options.SetRunGcInPlace(true);
65         options.SetVerifyCallStack(false);
66         options.SetGcType("epsilon");
67         Runtime::Create(options);
68         thread_ = panda::MTManagedThread::GetCurrent();
69         thread_->ManagedCodeBegin();
70     }
71 
~InterpreterTest()72     ~InterpreterTest() override
73     {
74         thread_->ManagedCodeEnd();
75         Runtime::Destroy();
76     }
77 
78     NO_COPY_SEMANTIC(InterpreterTest);
79     NO_MOVE_SEMANTIC(InterpreterTest);
80 
81 private:
82     panda::MTManagedThread *thread_;
83 };
84 
CreateFrame(uint32_t nregs,Method * method,Frame * prev)85 auto CreateFrame(uint32_t nregs, Method *method, Frame *prev)
86 {
87     auto frameDeleter = [](Frame *frame) { RuntimeInterface::FreeFrame(ManagedThread::GetCurrent(), frame); };
88     std::unique_ptr<Frame, decltype(frameDeleter)> frame(
89         RuntimeInterface::template CreateFrame<false>(nregs, method, prev), frameDeleter);
90     return frame;
91 }
92 
InitializeFrame(Frame * f)93 static void InitializeFrame(Frame *f)
94 {
95     ManagedThread::GetCurrent()->SetCurrentFrame(f);
96     auto frameHandler = StaticFrameHandler(f);
97     for (size_t i = 0; i < f->GetSize(); i++) {
98         frameHandler.GetVReg(i).Set(static_cast<int64_t>(0));
99     }
100 }
101 
CreateClass(panda_file::SourceLang lang)102 static Class *CreateClass(panda_file::SourceLang lang)
103 {
104     const std::string className("Foo");
105     auto runtime = Runtime::GetCurrent();
106     auto etx = runtime->GetClassLinker()->GetExtension(runtime->GetLanguageContext(lang));
107     auto klass = etx->CreateClass(reinterpret_cast<const uint8_t *>(className.data()), 0, 0,
108                                   AlignUp(sizeof(Class), OBJECT_POINTER_SIZE));
109     return klass;
110 }
111 
CreateMethod(Class * klass,uint32_t accessFlags,uint32_t nargs,uint32_t nregs,uint16_t * shorty,const std::vector<uint8_t> & bytecode)112 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateMethod(
113     Class *klass, uint32_t accessFlags, uint32_t nargs, uint32_t nregs, uint16_t *shorty,
114     const std::vector<uint8_t> &bytecode)
115 {
116     // Create panda_file
117 
118     panda_file::ItemContainer container;
119     panda_file::ClassItem *classItem = container.GetOrCreateGlobalClassItem();
120     classItem->SetAccessFlags(ACC_PUBLIC);
121 
122     panda_file::StringItem *methodName = container.GetOrCreateStringItem("test");
123     panda_file::PrimitiveTypeItem *retType = container.GetOrCreatePrimitiveTypeItem(panda_file::Type::TypeId::VOID);
124     std::vector<panda_file::MethodParamItem> params;
125     panda_file::ProtoItem *protoItem = container.GetOrCreateProtoItem(retType, params);
126     panda_file::MethodItem *methodItem = classItem->AddMethod(methodName, protoItem, ACC_PUBLIC | ACC_STATIC, params);
127 
128     auto *codeItem = container.CreateItem<panda_file::CodeItem>(nregs, nargs, bytecode);
129     methodItem->SetCode(codeItem);
130 
131     panda_file::MemoryWriter memWriter;
132     container.Write(&memWriter);
133 
134     auto data = memWriter.GetData();
135 
136     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
137     auto buf = allocator->AllocArray<uint8_t>(data.size());
138     memcpy_s(buf, data.size(), data.data(), data.size());
139 
140     os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(buf), data.size(), [](std::byte *buffer, size_t) noexcept {
141         auto a = Runtime::GetCurrent()->GetInternalAllocator();
142         a->Free(buffer);
143     });
144     auto pf = panda_file::File::OpenFromMemory(std::move(ptr));
145 
146     // Create method
147 
148     auto method = MakePandaUnique<Method>(klass, pf.get(), methodItem->GetFileId(), codeItem->GetFileId(),
149                                           accessFlags | ACC_PUBLIC | ACC_STATIC, nargs, shorty);
150     method->SetInterpreterEntryPoint();
151     return {std::move(method), std::move(pf)};
152 }
153 
CreateMethod(Class * klass,Frame * f,const std::vector<uint8_t> & bytecode)154 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateMethod(
155     Class *klass, Frame *f, const std::vector<uint8_t> &bytecode)
156 {
157     return CreateMethod(klass, 0, 0, f->GetSize(), nullptr, bytecode);
158 }
159 
CreateClassLinker(ManagedThread * thread)160 static std::unique_ptr<ClassLinker> CreateClassLinker([[maybe_unused]] ManagedThread *thread)
161 {
162     std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
163     extensions.push_back(std::make_unique<CoreClassLinkerExtension>());
164 
165     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
166     auto classLinker = std::make_unique<ClassLinker>(allocator, std::move(extensions));
167     if (!classLinker->Initialize()) {
168         return nullptr;
169     }
170 
171     return classLinker;
172 }
173 
TEST_F(InterpreterTest,TestMov)174 TEST_F(InterpreterTest, TestMov)
175 {
176     BytecodeEmitter emitter;
177 
178     constexpr int64_t IMM4_MAX = 7;
179     constexpr int64_t IMM8_MAX = std::numeric_limits<int8_t>::max();
180     constexpr int64_t IMM16_MAX = std::numeric_limits<int16_t>::max();
181     constexpr int64_t IMM32_MAX = std::numeric_limits<int32_t>::max();
182     constexpr int64_t IMM64_MAX = std::numeric_limits<int64_t>::max();
183 
184     constexpr uint16_t V4_MAX = 15;
185     constexpr uint16_t V8_MAX = std::numeric_limits<uint8_t>::max();
186     constexpr uint16_t V16_MAX = std::numeric_limits<uint16_t>::max();
187 
188     ObjectHeader *obj1 = panda::mem::AllocateNullifiedPayloadString(1);
189     ObjectHeader *obj2 = panda::mem::AllocateNullifiedPayloadString(100);
190     ObjectHeader *obj3 = panda::mem::AllocateNullifiedPayloadString(200);
191 
192     emitter.Movi(0U, IMM4_MAX);
193     emitter.Movi(1U, IMM8_MAX);
194     emitter.Movi(2U, IMM16_MAX);
195     emitter.Movi(3U, IMM32_MAX);
196     emitter.MoviWide(4U, IMM64_MAX);
197 
198     emitter.Mov(V4_MAX, V4_MAX - 1);
199     emitter.Mov(V8_MAX, V8_MAX - 1);
200     emitter.Mov(V16_MAX, V16_MAX - 1);
201 
202     emitter.MovWide(V4_MAX - 2U, V4_MAX - 3L);
203     emitter.MovWide(V16_MAX - 2U, V16_MAX - 3L);
204 
205     emitter.MovObj(V4_MAX - 4U, V4_MAX - 5L);
206     emitter.MovObj(V8_MAX - 4U, V8_MAX - 5L);
207     emitter.MovObj(V16_MAX - 4U, V16_MAX - 5L);
208 
209     emitter.ReturnVoid();
210 
211     std::vector<uint8_t> bytecode;
212     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
213 
214     auto f = CreateFrame(std::numeric_limits<uint16_t>::max() + 1, nullptr, nullptr);
215     InitializeFrame(f.get());
216     auto frameHandler = StaticFrameHandler(f.get());
217 
218     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
219     auto methodData = CreateMethod(cls, f.get(), bytecode);
220     auto method = std::move(methodData.first);
221     f->SetMethod(method.get());
222 
223     frameHandler.GetVReg(V4_MAX - 1).SetPrimitive(IMM64_MAX - 1L);
224     frameHandler.GetVReg(V8_MAX - 1).SetPrimitive(IMM64_MAX - 2L);
225     frameHandler.GetVReg(V16_MAX - 1).SetPrimitive(IMM64_MAX - 3L);
226 
227     frameHandler.GetVReg(V4_MAX - 3U).SetPrimitive(IMM64_MAX - 4L);
228     frameHandler.GetVReg(V16_MAX - 3U).SetPrimitive(IMM64_MAX - 5L);
229 
230     frameHandler.GetVReg(V4_MAX - 5U).SetReference(obj1);
231     frameHandler.GetVReg(V8_MAX - 5U).SetReference(obj2);
232     frameHandler.GetVReg(V16_MAX - 5U).SetReference(obj3);
233 
234     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
235 
236     // Check movi
237 
238     EXPECT_EQ(frameHandler.GetVReg(0).GetLong(), IMM4_MAX);
239     EXPECT_FALSE(frameHandler.GetVReg(0).HasObject());
240 
241     EXPECT_EQ(frameHandler.GetVReg(1).GetLong(), IMM8_MAX);
242     EXPECT_FALSE(frameHandler.GetVReg(1).HasObject());
243 
244     EXPECT_EQ(frameHandler.GetVReg(2U).GetLong(), IMM16_MAX);
245     EXPECT_FALSE(frameHandler.GetVReg(2U).HasObject());
246 
247     EXPECT_EQ(frameHandler.GetVReg(3U).GetLong(), IMM32_MAX);
248     EXPECT_FALSE(frameHandler.GetVReg(3U).HasObject());
249 
250     EXPECT_EQ(frameHandler.GetVReg(4U).GetLong(), IMM64_MAX);
251     EXPECT_FALSE(frameHandler.GetVReg(4U).HasObject());
252 
253     // Check mov
254 
255     EXPECT_EQ(frameHandler.GetVReg(V4_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 1));
256     EXPECT_FALSE(frameHandler.GetVReg(V4_MAX).HasObject());
257 
258     EXPECT_EQ(frameHandler.GetVReg(V8_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 2L));
259     EXPECT_FALSE(frameHandler.GetVReg(V8_MAX).HasObject());
260 
261     EXPECT_EQ(frameHandler.GetVReg(V16_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 3L));
262     EXPECT_FALSE(frameHandler.GetVReg(V16_MAX).HasObject());
263 
264     // Check mov.64
265 
266     EXPECT_EQ(frameHandler.GetVReg(V4_MAX - 2U).GetLong(), IMM64_MAX - 4L);
267     EXPECT_FALSE(frameHandler.GetVReg(V4_MAX - 2U).HasObject());
268 
269     EXPECT_EQ(frameHandler.GetVReg(V16_MAX - 2U).GetLong(), IMM64_MAX - 5L);
270     EXPECT_FALSE(frameHandler.GetVReg(V16_MAX - 2U).HasObject());
271 
272     // Check mov.obj
273 
274     EXPECT_EQ(frameHandler.GetVReg(V4_MAX - 4U).GetReference(), obj1);
275     EXPECT_TRUE(frameHandler.GetVReg(V4_MAX - 4U).HasObject());
276 
277     EXPECT_EQ(frameHandler.GetVReg(V8_MAX - 4U).GetReference(), obj2);
278     EXPECT_TRUE(frameHandler.GetVReg(V8_MAX - 4U).HasObject());
279 
280     EXPECT_EQ(frameHandler.GetVReg(V16_MAX - 4U).GetReference(), obj3);
281     EXPECT_TRUE(frameHandler.GetVReg(V16_MAX - 4U).HasObject());
282 }
283 
TEST_F(InterpreterTest,TestLoadStoreAccumulator)284 TEST_F(InterpreterTest, TestLoadStoreAccumulator)
285 {
286     BytecodeEmitter emitter;
287 
288     constexpr int64_t IMM8_MAX = std::numeric_limits<int8_t>::max();
289     constexpr int64_t IMM16_MAX = std::numeric_limits<int16_t>::max();
290     constexpr int64_t IMM32_MAX = std::numeric_limits<int32_t>::max();
291     constexpr int64_t IMM64_MAX = std::numeric_limits<int64_t>::max();
292 
293     ObjectHeader *obj = panda::mem::AllocateNullifiedPayloadString(10U);
294 
295     emitter.Ldai(IMM8_MAX);
296     emitter.Sta(0U);
297 
298     emitter.Ldai(IMM16_MAX);
299     emitter.Sta(1U);
300 
301     emitter.Ldai(IMM32_MAX);
302     emitter.Sta(2U);
303 
304     emitter.LdaiWide(IMM64_MAX);
305     emitter.StaWide(3U);
306 
307     emitter.Lda(4U);
308     emitter.Sta(5U);
309 
310     emitter.LdaWide(6U);
311     emitter.StaWide(7U);
312 
313     emitter.LdaObj(8U);
314     emitter.StaObj(9U);
315 
316     emitter.ReturnVoid();
317 
318     std::vector<uint8_t> bytecode;
319     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
320 
321     auto f = CreateFrame(16U, nullptr, nullptr);
322     InitializeFrame(f.get());
323     auto frameHandler = StaticFrameHandler(f.get());
324 
325     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
326     auto methodData = CreateMethod(cls, f.get(), bytecode);
327     auto method = std::move(methodData.first);
328     f->SetMethod(method.get());
329 
330     frameHandler.GetVReg(4U).SetPrimitive(IMM64_MAX - 1L);
331     frameHandler.GetVReg(6U).SetPrimitive(IMM64_MAX - 2L);
332     frameHandler.GetVReg(8U).SetReference(obj);
333 
334     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
335 
336     EXPECT_EQ(frameHandler.GetVReg(0).Get(), static_cast<int32_t>(IMM8_MAX));
337     EXPECT_FALSE(frameHandler.GetVReg(0).HasObject());
338 
339     EXPECT_EQ(frameHandler.GetVReg(1).Get(), static_cast<int32_t>(IMM16_MAX));
340     EXPECT_FALSE(frameHandler.GetVReg(1).HasObject());
341 
342     EXPECT_EQ(frameHandler.GetVReg(2U).Get(), static_cast<int32_t>(IMM32_MAX));
343     EXPECT_FALSE(frameHandler.GetVReg(2U).HasObject());
344 
345     EXPECT_EQ(frameHandler.GetVReg(3U).GetLong(), IMM64_MAX);
346     EXPECT_FALSE(frameHandler.GetVReg(3U).HasObject());
347 
348     EXPECT_EQ(frameHandler.GetVReg(5U).Get(), static_cast<int32_t>(IMM64_MAX - 1));
349     EXPECT_FALSE(frameHandler.GetVReg(5U).HasObject());
350 
351     EXPECT_EQ(frameHandler.GetVReg(7U).GetLong(), IMM64_MAX - 2L);
352     EXPECT_FALSE(frameHandler.GetVReg(7U).HasObject());
353 
354     EXPECT_EQ(frameHandler.GetVReg(9U).GetReference(), obj);
355     EXPECT_TRUE(frameHandler.GetVReg(9U).HasObject());
356 }
357 
TEST_F(InterpreterTest,TestLoadString)358 TEST_F(InterpreterTest, TestLoadString)
359 {
360     pandasm::Parser p;
361     std::string source = R"(
362     .record panda.String <external>
363     .function panda.String foo(){
364         lda.str "TestLoadString"
365         return.obj
366     }
367     )";
368 
369     auto res = p.Parse(source);
370     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
371 
372     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
373     ASSERT_NE(classLinker, nullptr);
374 
375     classLinker->AddPandaFile(std::move(classPf));
376 
377     PandaString descriptor;
378     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
379 
380     Class *cls = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
381     Method *method = cls->GetClassMethod(utf::CStringAsMutf8("foo"));
382     const uint8_t *methodData = method->GetInstructions();
383 
384     auto f = CreateFrame(16U, nullptr, nullptr);
385     InitializeFrame(f.get());
386     f->SetMethod(method);
387 
388     Execute(ManagedThread::GetCurrent(), methodData, f.get());
389     EXPECT_TRUE(f->GetAccAsVReg().HasObject());
390 
391     PandaString strSample = "TestLoadString";
392     panda::coretypes::String *strCore = panda::coretypes::String::Cast(f->GetAccAsVReg().GetReference());
393 
394     const char *str = reinterpret_cast<const char *>(strCore->GetDataMUtf8());
395     size_t strLen = strCore->GetMUtf8Length() - 1;  // Reserved zero.
396     PandaString strTst(str, strLen);
397 
398     EXPECT_EQ(strSample, strTst);
399 }
400 
TestUnimpelemented(const std::function<void (BytecodeEmitter *)> & emit)401 void TestUnimpelemented(const std::function<void(BytecodeEmitter *)> &emit)
402 {
403     BytecodeEmitter emitter;
404 
405     emit(&emitter);
406 
407     std::vector<uint8_t> bytecode;
408     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
409 
410     auto f = CreateFrame(16U, nullptr, nullptr);
411     InitializeFrame(f.get());
412 
413     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
414     auto methodData = CreateMethod(cls, f.get(), bytecode);
415     auto method = std::move(methodData.first);
416     f->SetMethod(method.get());
417 
418     EXPECT_DEATH_IF_SUPPORTED(Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get()), "");
419 }
420 
TEST_F(InterpreterTest,LoadType)421 TEST_F(InterpreterTest, LoadType)
422 {
423     BytecodeEmitter emitter;
424 
425     pandasm::Parser p;
426     auto source = R"(
427         .record R {}
428     )";
429 
430     auto res = p.Parse(source);
431     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
432 
433     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
434     ASSERT_NE(classLinker, nullptr);
435 
436     classLinker->AddPandaFile(std::move(classPf));
437 
438     PandaString descriptor;
439     auto *thread = ManagedThread::GetCurrent();
440     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
441     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
442     ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
443 
444     emitter.LdaType(RuntimeInterface::TYPE_ID.AsIndex());
445     emitter.ReturnObj();
446 
447     std::vector<uint8_t> bytecode;
448     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
449 
450     auto f = CreateFrame(16U, nullptr, nullptr);
451     InitializeFrame(f.get());
452 
453     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
454     auto methodData = CreateMethod(cls, f.get(), bytecode);
455     auto method = std::move(methodData.first);
456     f->SetMethod(method.get());
457 
458     RuntimeInterface::SetupResolvedClass(objectClass);
459 
460     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
461 
462     RuntimeInterface::SetupResolvedClass(nullptr);
463 
464     EXPECT_EQ(coretypes::Class::FromRuntimeClass(objectClass), f->GetAccAsVReg().GetReference());
465 }
466 
TestFcmp(double v1,double v2,int64_t value,bool isCmpg=false)467 void TestFcmp(double v1, double v2, int64_t value, bool isCmpg = false)
468 {
469     std::ostringstream ss;
470     if (isCmpg) {
471         ss << "Test fcmpg.64";
472     } else {
473         ss << "Test fcmpl.64";
474     }
475     ss << ", v1 = " << v1 << ", v2 = " << v2;
476 
477     BytecodeEmitter emitter;
478 
479     if (isCmpg) {
480         emitter.FcmpgWide(0);
481     } else {
482         emitter.FcmplWide(0);
483     }
484     emitter.ReturnWide();
485 
486     std::vector<uint8_t> bytecode;
487     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
488 
489     auto f = CreateFrame(16U, nullptr, nullptr);
490     InitializeFrame(f.get());
491 
492     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
493     auto methodData = CreateMethod(cls, f.get(), bytecode);
494     auto method = std::move(methodData.first);
495     f->SetMethod(method.get());
496 
497     f->GetAccAsVReg().SetPrimitive(v1);
498     auto frameHandler = StaticFrameHandler(f.get());
499     frameHandler.GetVReg(0).SetPrimitive(v2);
500 
501     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
502 
503     EXPECT_EQ(f->GetAccAsVReg().GetLong(), value) << ss.str();
504     EXPECT_FALSE(f->GetAccAsVReg().HasObject()) << ss.str();
505 }
506 
TEST_F(InterpreterTest,TestFcmp)507 TEST_F(InterpreterTest, TestFcmp)
508 {
509     TestFcmp(nan(""), 1.0, 1, true);
510     TestFcmp(1.0, nan(""), 1, true);
511     TestFcmp(nan(""), nan(""), 1, true);
512     TestFcmp(1.0, 2.0F, -1, true);
513     TestFcmp(1.0, 1.0, 0, true);
514     TestFcmp(3.0F, 2.0F, 1, true);
515 
516     TestFcmp(nan(""), 1.0, -1);
517     TestFcmp(1.0, nan(""), -1);
518     TestFcmp(nan(""), nan(""), -1);
519     TestFcmp(1.0, 2.0F, -1);
520     TestFcmp(1.0, 1.0, 0);
521     TestFcmp(3.0F, 2.0F, 1);
522 }
523 
TestConditionalJmp(const std::string & mnemonic,int64_t v1,int64_t v2,int64_t r,const std::function<void (BytecodeEmitter *,uint8_t,const Label &)> & emit)524 void TestConditionalJmp(const std::string &mnemonic, int64_t v1, int64_t v2, int64_t r,
525                         const std::function<void(BytecodeEmitter *, uint8_t, const Label &)> &emit)
526 {
527     std::ostringstream ss;
528     ss << "Test " << mnemonic << " with v1 = " << v1 << ", v2 = " << v2;
529 
530     {
531         BytecodeEmitter emitter;
532         Label label = emitter.CreateLabel();
533 
534         emit(&emitter, 0, label);
535         emitter.MoviWide(1, -1);
536         emitter.ReturnVoid();
537         emitter.Bind(label);
538         emitter.MoviWide(1, 1);
539         emitter.ReturnVoid();
540 
541         std::vector<uint8_t> bytecode;
542         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
543 
544         auto f = CreateFrame(16U, nullptr, nullptr);
545         InitializeFrame(f.get());
546 
547         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
548         auto methodData = CreateMethod(cls, f.get(), bytecode);
549         auto method = std::move(methodData.first);
550         f->SetMethod(method.get());
551 
552         f->GetAccAsVReg().SetPrimitive(v1);
553         auto frameHandler = StaticFrameHandler(f.get());
554         frameHandler.GetVReg(0).SetPrimitive(v2);
555 
556         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
557 
558         EXPECT_EQ(frameHandler.GetVReg(1).GetLong(), r) << ss.str();
559     }
560 
561     {
562         BytecodeEmitter emitter;
563         Label label1 = emitter.CreateLabel();
564         Label label2 = emitter.CreateLabel();
565 
566         emitter.Jmp(label1);
567         emitter.Bind(label2);
568         emitter.MoviWide(1, 1);
569         emitter.ReturnVoid();
570         emitter.Bind(label1);
571         emit(&emitter, 0, label2);
572         emitter.MoviWide(1, -1);
573         emitter.ReturnVoid();
574 
575         std::vector<uint8_t> bytecode;
576         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
577 
578         auto f = CreateFrame(16U, nullptr, nullptr);
579         InitializeFrame(f.get());
580 
581         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
582         auto methodData = CreateMethod(cls, f.get(), bytecode);
583         auto method = std::move(methodData.first);
584         f->SetMethod(method.get());
585 
586         f->GetAccAsVReg().SetPrimitive(v1);
587         auto frameHandler = StaticFrameHandler(f.get());
588         frameHandler.GetVReg(0).SetPrimitive(v2);
589 
590         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
591 
592         EXPECT_EQ(frameHandler.GetVReg(1).GetLong(), r) << ss.str();
593         EXPECT_EQ(method->GetHotnessCounter(),
594                   (r == 1 ? (Runtime::GetCurrent()->IsJitEnabled() ? 1499U : std::numeric_limits<int16_t>::max() - 1)
595                           : (Runtime::GetCurrent()->IsJitEnabled() ? 1500U : std::numeric_limits<int16_t>::max())))
596             << ss.str();
597     }
598 }
599 
TestConditionalJmpz(const std::string & mnemonic,int64_t v,int64_t r,const std::function<void (BytecodeEmitter *,const Label &)> & emit)600 void TestConditionalJmpz(const std::string &mnemonic, int64_t v, int64_t r,
601                          const std::function<void(BytecodeEmitter *, const Label &)> &emit)
602 {
603     std::ostringstream ss;
604     ss << "Test " << mnemonic << " with v = " << v;
605 
606     {
607         BytecodeEmitter emitter;
608         Label label = emitter.CreateLabel();
609 
610         emit(&emitter, label);
611         emitter.MoviWide(0, -1);
612         emitter.ReturnVoid();
613         emitter.Bind(label);
614         emitter.MoviWide(0, 1);
615         emitter.ReturnVoid();
616 
617         std::vector<uint8_t> bytecode;
618         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
619 
620         auto f = CreateFrame(16U, nullptr, nullptr);
621         InitializeFrame(f.get());
622 
623         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
624         auto methodData = CreateMethod(cls, f.get(), bytecode);
625         auto method = std::move(methodData.first);
626         f->SetMethod(method.get());
627 
628         f->GetAccAsVReg().SetPrimitive(v);
629 
630         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
631 
632         auto frameHandler = StaticFrameHandler(f.get());
633         EXPECT_EQ(frameHandler.GetVReg(0).GetLong(), r) << ss.str();
634     }
635 
636     {
637         BytecodeEmitter emitter;
638         Label label1 = emitter.CreateLabel();
639         Label label2 = emitter.CreateLabel();
640 
641         emitter.Jmp(label1);
642         emitter.Bind(label2);
643         emitter.MoviWide(0, 1);
644         emitter.ReturnVoid();
645         emitter.Bind(label1);
646         emit(&emitter, label2);
647         emitter.MoviWide(0, -1);
648         emitter.ReturnVoid();
649 
650         std::vector<uint8_t> bytecode;
651         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
652 
653         auto f = CreateFrame(16U, nullptr, nullptr);
654         InitializeFrame(f.get());
655 
656         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
657         auto methodData = CreateMethod(cls, f.get(), bytecode);
658         auto method = std::move(methodData.first);
659         f->SetMethod(method.get());
660 
661         f->GetAccAsVReg().SetPrimitive(v);
662 
663         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
664 
665         auto frameHandler = StaticFrameHandler(f.get());
666         EXPECT_EQ(frameHandler.GetVReg(0).GetLong(), r) << ss.str();
667         EXPECT_EQ(method->GetHotnessCounter(),
668                   (r == 1 ? (Runtime::GetCurrent()->IsJitEnabled() ? 1499U : std::numeric_limits<int16_t>::max() - 1)
669                           : (Runtime::GetCurrent()->IsJitEnabled() ? 1500U : std::numeric_limits<int16_t>::max())))
670             << ss.str();
671     }
672 }
673 
TEST_F(InterpreterTest,TestConditionalJumps)674 TEST_F(InterpreterTest, TestConditionalJumps)
675 {
676     // Test jmpz
677 
678     TestConditionalJmpz("jeqz", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
679     TestConditionalJmpz("jeqz", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
680     TestConditionalJmpz("jeqz", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
681 
682     TestConditionalJmpz("jnez", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
683     TestConditionalJmpz("jnez", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
684     TestConditionalJmpz("jnez", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
685 
686     TestConditionalJmpz("jltz", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
687     TestConditionalJmpz("jltz", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
688     TestConditionalJmpz("jltz", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
689 
690     TestConditionalJmpz("jgtz", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
691     TestConditionalJmpz("jgtz", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
692     TestConditionalJmpz("jgtz", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
693 
694     TestConditionalJmpz("jlez", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
695     TestConditionalJmpz("jlez", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
696     TestConditionalJmpz("jlez", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
697 
698     TestConditionalJmpz("jgez", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
699     TestConditionalJmpz("jgez", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
700     TestConditionalJmpz("jgez", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
701 
702     // Test jmp
703 
704     TestConditionalJmp("jeq", 2L, 2L, 1L,
705                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
706     TestConditionalJmp("jeq", 1L, 2L, -1L,
707                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
708     TestConditionalJmp("jeq", 2L, 1L, -1L,
709                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
710 
711     TestConditionalJmp("jne", 2L, 2L, -1L,
712                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
713     TestConditionalJmp("jne", 1L, 2L, 1L,
714                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
715     TestConditionalJmp("jne", 2L, 1L, 1L,
716                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
717 
718     TestConditionalJmp("jlt", 2L, 2L, -1L,
719                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
720     TestConditionalJmp("jlt", 1L, 2L, 1L,
721                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
722     TestConditionalJmp("jlt", 2L, 1L, -1L,
723                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
724 
725     TestConditionalJmp("jgt", 2L, 2L, -1L,
726                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
727     TestConditionalJmp("jgt", 1L, 2L, -1L,
728                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
729     TestConditionalJmp("jgt", 2L, 1L, 1L,
730                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
731 
732     TestConditionalJmp("jle", 2L, 2L, 1L,
733                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
734     TestConditionalJmp("jle", 1L, 2L, 1L,
735                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
736     TestConditionalJmp("jle", 2L, 1L, -1L,
737                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
738 
739     TestConditionalJmp("jge", 2L, 2L, 1L,
740                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
741     TestConditionalJmp("jge", 1L, 2L, -1L,
742                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
743     TestConditionalJmp("jge", 2L, 1L, 1L,
744                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
745 }
746 
747 template <class T, class R>
TestUnaryOp(const std::string & mnemonic,T v,R r,const std::function<void (BytecodeEmitter *)> & emit)748 void TestUnaryOp(const std::string &mnemonic, T v, R r, const std::function<void(BytecodeEmitter *)> &emit)
749 {
750     std::ostringstream ss;
751     ss << "Test " << mnemonic << " with v = " << v;
752 
753     BytecodeEmitter emitter;
754 
755     emit(&emitter);
756     emitter.ReturnWide();
757 
758     std::vector<uint8_t> bytecode;
759     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
760 
761     auto f = CreateFrame(16U, nullptr, nullptr);
762     InitializeFrame(f.get());
763 
764     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
765     auto methodData = CreateMethod(cls, f.get(), bytecode);
766     auto method = std::move(methodData.first);
767     f->SetMethod(method.get());
768 
769     f->GetAccAsVReg().SetPrimitive(v);
770 
771     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
772 
773     EXPECT_EQ(f->GetAccAsVReg().GetAs<R>(), r) << ss.str();
774 }
775 
TEST_F(InterpreterTest,TestUnaryOp)776 TEST_F(InterpreterTest, TestUnaryOp)
777 {
778     constexpr int64_t I32_MIN = std::numeric_limits<int32_t>::min();
779     constexpr int64_t I64_MIN = std::numeric_limits<int64_t>::min();
780 
781     TestUnaryOp<int64_t, int64_t>("neg", I64_MIN + 1, -(I64_MIN + 1),
782                                   [](BytecodeEmitter *emitter) { emitter->NegWide(); });
783 
784     TestUnaryOp<int32_t, int64_t>("neg", I32_MIN + 1, -(I32_MIN + 1), [](BytecodeEmitter *emitter) { emitter->Neg(); });
785 
786     TestUnaryOp<double, double>("fneg", 1.0, -1.0, [](BytecodeEmitter *emitter) { emitter->FnegWide(); });
787 
788     TestUnaryOp<int64_t, int64_t>("not", 0, 0xffffffffffffffff, [](BytecodeEmitter *emitter) { emitter->NotWide(); });
789 
790     TestUnaryOp<int32_t, int32_t>("not", 0, 0xffffffff, [](BytecodeEmitter *emitter) { emitter->Not(); });
791 }
792 
TEST_F(InterpreterTest,TestInci)793 TEST_F(InterpreterTest, TestInci)
794 {
795     BytecodeEmitter emitter;
796     emitter.Inci(0, 2_I);
797     emitter.Inci(1, -3_I);
798     emitter.ReturnWide();
799 
800     std::vector<uint8_t> bytecode;
801     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
802 
803     auto f = CreateFrame(16U, nullptr, nullptr);
804     InitializeFrame(f.get());
805 
806     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
807     auto methodData = CreateMethod(cls, f.get(), bytecode);
808     auto method = std::move(methodData.first);
809     f->SetMethod(method.get());
810 
811     auto frameHandler = StaticFrameHandler(f.get());
812     frameHandler.GetVReg(0).SetPrimitive(-2_I);
813     frameHandler.GetVReg(1).SetPrimitive(3_I);
814 
815     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
816 
817     EXPECT_EQ(frameHandler.GetVReg(0).GetAs<int32_t>(), 0);
818     EXPECT_EQ(frameHandler.GetVReg(1).GetAs<int32_t>(), 0);
819 }
820 
TEST_F(InterpreterTest,TestCast)821 TEST_F(InterpreterTest, TestCast)
822 {
823     constexpr int64_t I64_MAX = std::numeric_limits<int64_t>::max();
824     constexpr int32_t I32_MAX = std::numeric_limits<int32_t>::max();
825     constexpr int64_t I64_MIN = std::numeric_limits<int64_t>::min();
826     constexpr int32_t I32_MIN = std::numeric_limits<int32_t>::min();
827 
828     constexpr double F64_MAX = std::numeric_limits<double>::max();
829     constexpr double F64_PINF = std::numeric_limits<double>::infinity();
830     constexpr double F64_NINF = -F64_PINF;
831 
832     double f64 = 64.0;
833 
834     TestUnaryOp("i32toi64", I32_MAX, static_cast<int64_t>(I32_MAX),
835                 [](BytecodeEmitter *emitter) { emitter->I32toi64(); });
836 
837     TestUnaryOp("i32tof64", I32_MAX, static_cast<double>(I32_MAX),
838                 [](BytecodeEmitter *emitter) { emitter->I32tof64(); });
839 
840     TestUnaryOp("i64toi32", I64_MAX, static_cast<int32_t>(I64_MAX),
841                 [](BytecodeEmitter *emitter) { emitter->I64toi32(); });
842 
843     TestUnaryOp("i64tof64", I64_MAX, static_cast<double>(I64_MAX),
844                 [](BytecodeEmitter *emitter) { emitter->I64tof64(); });
845 
846     TestUnaryOp("F64toi32", F64_MAX, I32_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
847     TestUnaryOp("F64toi32", F64_PINF, I32_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
848     TestUnaryOp("F64toi32", -F64_MAX, I32_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
849     TestUnaryOp("F64toi32", F64_NINF, I32_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
850     TestUnaryOp("F64toi32", nan(""), 0, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
851     TestUnaryOp("F64toi32", f64, static_cast<int32_t>(f64), [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
852 
853     TestUnaryOp("F64toi64", F64_MAX, I64_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
854     TestUnaryOp("F64toi64", F64_PINF, I64_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
855     TestUnaryOp("F64toi64", -F64_MAX, I64_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
856     TestUnaryOp("F64toi64", F64_NINF, I64_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
857     TestUnaryOp("F64toi64", nan(""), 0, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
858     TestUnaryOp("F64toi64", f64, static_cast<int64_t>(f64), [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
859 }
860 
861 // clang-format off
862 
863 template <panda_file::Type::TypeId TYPE_ID>
864 struct ArrayComponentTypeHelper {
865     using Type = std::conditional_t<TYPE_ID == panda_file::Type::TypeId::U1, uint8_t,
866                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::I8, int8_t,
867                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::U8, uint8_t,
868                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::I16, int16_t,
869                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::U16, uint16_t,
870                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::I32, int32_t,
871                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::U32, uint32_t,
872                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::I64, int64_t,
873                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::U64, uint64_t,
874                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::F32, float,
875                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::F64, double,
876                  std::conditional_t<TYPE_ID == panda_file::Type::TypeId::REFERENCE, ObjectHeader*, void>>>>>>>>>>>>;
877 };
878 
879 // clang-format on
880 
881 template <panda_file::Type::TypeId TYPE_ID>
882 using ArrayComponentTypeHelperT = typename ArrayComponentTypeHelper<TYPE_ID>::Type;
883 
884 template <panda_file::Type::TypeId TYPE_ID>
885 struct ArrayStoredTypeHelperT {
886     using Type = typename ArrayComponentTypeHelper<TYPE_ID>::Type;
887 };
888 
889 template <>
890 struct ArrayStoredTypeHelperT<panda_file::Type::TypeId::REFERENCE> {
891     using Type = ObjectPointerType;
892 };
893 
894 template <panda_file::Type::TypeId TYPE_ID>
CastIfRef(ArrayComponentTypeHelperT<TYPE_ID> value)895 typename ArrayStoredTypeHelperT<TYPE_ID>::Type CastIfRef(ArrayComponentTypeHelperT<TYPE_ID> value)
896 {
897     if constexpr (TYPE_ID == panda_file::Type::TypeId::REFERENCE) {
898         return static_cast<ObjectPointerType>(reinterpret_cast<uintptr_t>(value));
899     } else {
900         return value;
901     }
902 }
903 
AllocArray(Class * cls,size_t elemSize,size_t length)904 coretypes::Array *AllocArray(Class *cls, [[maybe_unused]] size_t elemSize, size_t length)
905 {
906     return coretypes::Array::Create(cls, length);
907 }
908 
AllocObject(Class * cls)909 ObjectHeader *AllocObject(Class *cls)
910 {
911     return ObjectHeader::Create(cls);
912 }
913 
914 template <class T>
GetStoreValue(Class * cls)915 static T GetStoreValue([[maybe_unused]] Class *cls)
916 {
917     if constexpr (std::is_same_v<T, ObjectHeader *>) {
918         return AllocObject(cls);
919     }
920 
921     return std::numeric_limits<T>::max();
922 }
923 
924 template <class T>
GetLoadValue(Class * cls)925 static T GetLoadValue([[maybe_unused]] Class *cls)
926 {
927     if constexpr (std::is_same_v<T, ObjectHeader *>) {
928         return AllocObject(cls);
929     }
930 
931     return std::numeric_limits<T>::min() + 1;
932 }
933 
GetArrayClassName(panda_file::Type::TypeId componentTypeId)934 PandaString GetArrayClassName(panda_file::Type::TypeId componentTypeId)
935 {
936     PandaString descriptor;
937 
938     if (componentTypeId == panda_file::Type::TypeId::REFERENCE) {
939         ClassHelper::GetArrayDescriptor(utf::CStringAsMutf8("panda.Object"), 1, &descriptor);
940         return descriptor;
941     }
942 
943     ClassHelper::GetPrimitiveArrayDescriptor(panda_file::Type(componentTypeId), 1, &descriptor);
944     return descriptor;
945 }
946 
947 template <panda_file::Type::TypeId COMPONENT_TYPE_ID>
TestArray()948 static void TestArray()
949 {
950     std::ostringstream ss;
951     ss << "Test with component type id " << static_cast<uint32_t>(COMPONENT_TYPE_ID);
952 
953     using ComponentType = ArrayComponentTypeHelperT<COMPONENT_TYPE_ID>;
954     using StoredType = typename ArrayStoredTypeHelperT<COMPONENT_TYPE_ID>::Type;
955 
956     BytecodeEmitter emitter;
957 
958     constexpr int64_t ARRAY_LENGTH = 10;
959     constexpr size_t STORE_IDX = ARRAY_LENGTH - 1;
960     constexpr size_t LOAD_IDX = 0;
961 
962     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
963     ASSERT_NE(classLinker, nullptr) << ss.str();
964 
965     auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
966     PandaString arrayClassName = GetArrayClassName(COMPONENT_TYPE_ID);
967     Class *arrayClass = classLinker->GetExtension(ctx)->GetClass(utf::CStringAsMutf8(arrayClassName.c_str()));
968     Class *elemClass = arrayClass->GetComponentType();
969 
970     const auto storeValue = GetStoreValue<ComponentType>(elemClass);
971     const auto loadValue = GetLoadValue<ComponentType>(elemClass);
972 
973     emitter.Movi(0, ARRAY_LENGTH);
974     emitter.Newarr(1, 0, RuntimeInterface::TYPE_ID.AsIndex());
975 
976     if constexpr (COMPONENT_TYPE_ID == panda_file::Type::TypeId::REFERENCE) {
977         emitter.LdaObj(4U);
978     } else if constexpr (COMPONENT_TYPE_ID == panda_file::Type::TypeId::F32) {
979         emitter.Fldai(bit_cast<int32_t>(storeValue));
980     } else if constexpr (COMPONENT_TYPE_ID == panda_file::Type::TypeId::F64) {
981         emitter.FldaiWide(bit_cast<int64_t>(storeValue));
982     } else {
983         emitter.LdaiWide(static_cast<int64_t>(storeValue));
984     }
985 
986     emitter.Movi(2U, STORE_IDX);
987 
988     if constexpr (COMPONENT_TYPE_ID != panda_file::Type::TypeId::REFERENCE) {
989         switch (COMPONENT_TYPE_ID) {
990             case panda_file::Type::TypeId::U1:
991             case panda_file::Type::TypeId::U8: {
992                 emitter.Starr8(1, 2U);
993                 emitter.Ldai(LOAD_IDX);
994                 emitter.Ldarru8(1);
995                 break;
996             }
997             case panda_file::Type::TypeId::I8: {
998                 emitter.Starr8(1, 2U);
999                 emitter.Ldai(LOAD_IDX);
1000                 emitter.Ldarr8(1);
1001                 break;
1002             }
1003             case panda_file::Type::TypeId::U16: {
1004                 emitter.Starr16(1, 2U);
1005                 emitter.Ldai(LOAD_IDX);
1006                 emitter.Ldarru16(1);
1007                 break;
1008             }
1009             case panda_file::Type::TypeId::I16: {
1010                 emitter.Starr16(1, 2U);
1011                 emitter.Ldai(LOAD_IDX);
1012                 emitter.Ldarr16(1);
1013                 break;
1014             }
1015             case panda_file::Type::TypeId::U32:
1016             case panda_file::Type::TypeId::I32: {
1017                 emitter.Starr(1, 2U);
1018                 emitter.Ldai(LOAD_IDX);
1019                 emitter.Ldarr(1);
1020                 break;
1021             }
1022             case panda_file::Type::TypeId::U64:
1023             case panda_file::Type::TypeId::I64: {
1024                 emitter.StarrWide(1, 2U);
1025                 emitter.Ldai(LOAD_IDX);
1026                 emitter.LdarrWide(1);
1027                 break;
1028             }
1029             case panda_file::Type::TypeId::F32: {
1030                 emitter.Fstarr32(1, 2U);
1031                 emitter.Ldai(LOAD_IDX);
1032                 emitter.Fldarr32(1);
1033                 break;
1034             }
1035             case panda_file::Type::TypeId::F64: {
1036                 emitter.FstarrWide(1, 2U);
1037                 emitter.Ldai(LOAD_IDX);
1038                 emitter.FldarrWide(1);
1039                 break;
1040             }
1041             default: {
1042                 UNREACHABLE();
1043                 break;
1044             }
1045         }
1046     } else {
1047         emitter.StarrObj(1, 2U);
1048         emitter.Ldai(LOAD_IDX);
1049         emitter.LdarrObj(1);
1050     }
1051 
1052     if constexpr (COMPONENT_TYPE_ID != panda_file::Type::TypeId::REFERENCE) {
1053         emitter.StaWide(3U);
1054     } else {
1055         emitter.StaObj(3U);
1056     }
1057 
1058     emitter.Lenarr(1);
1059     emitter.Return();
1060 
1061     std::vector<uint8_t> bytecode;
1062     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
1063 
1064     auto f = CreateFrame(16U, nullptr, nullptr);
1065     InitializeFrame(f.get());
1066 
1067     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1068     auto methodData = CreateMethod(cls, f.get(), bytecode);
1069     auto method = std::move(methodData.first);
1070     f->SetMethod(method.get());
1071 
1072     auto frameHandler = StaticFrameHandler(f.get());
1073     if constexpr (COMPONENT_TYPE_ID == panda_file::Type::TypeId::REFERENCE) {
1074         frameHandler.GetVReg(4U).SetReference(storeValue);
1075     }
1076 
1077     coretypes::Array *array = AllocArray(arrayClass, sizeof(StoredType), ARRAY_LENGTH);
1078     array->Set<ComponentType>(LOAD_IDX, loadValue);
1079 
1080     RuntimeInterface::SetupResolvedClass(arrayClass);
1081     RuntimeInterface::SetupArrayClass(arrayClass);
1082     RuntimeInterface::SetupArrayLength(ARRAY_LENGTH);
1083     RuntimeInterface::SetupArrayObject(array);
1084 
1085     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1086 
1087     RuntimeInterface::SetupResolvedClass(nullptr);
1088     RuntimeInterface::SetupArrayClass(nullptr);
1089     RuntimeInterface::SetupArrayObject(nullptr);
1090 
1091     ASSERT_EQ(f->GetAccAsVReg().Get(), ARRAY_LENGTH) << ss.str();
1092 
1093     auto *result = static_cast<coretypes::Array *>(frameHandler.GetVReg(1).GetReference());
1094     EXPECT_EQ(result, array) << ss.str();
1095 
1096     EXPECT_EQ(frameHandler.GetVReg(3U).GetAs<ComponentType>(), loadValue) << ss.str();
1097 
1098     std::vector<StoredType> data(ARRAY_LENGTH);
1099     data[LOAD_IDX] = CastIfRef<COMPONENT_TYPE_ID>(loadValue);
1100     data[STORE_IDX] = CastIfRef<COMPONENT_TYPE_ID>(storeValue);
1101 
1102     EXPECT_THAT(data, ::testing::ElementsAreArray(reinterpret_cast<StoredType *>(array->GetData()), ARRAY_LENGTH))
1103         << ss.str();
1104 }
1105 
TEST_F(InterpreterTest,TestArray)1106 TEST_F(InterpreterTest, TestArray)
1107 {
1108     TestArray<panda_file::Type::TypeId::U1>();
1109     TestArray<panda_file::Type::TypeId::I8>();
1110     TestArray<panda_file::Type::TypeId::U8>();
1111     TestArray<panda_file::Type::TypeId::I16>();
1112     TestArray<panda_file::Type::TypeId::U16>();
1113     TestArray<panda_file::Type::TypeId::I32>();
1114     TestArray<panda_file::Type::TypeId::U32>();
1115     TestArray<panda_file::Type::TypeId::I64>();
1116     TestArray<panda_file::Type::TypeId::U64>();
1117     TestArray<panda_file::Type::TypeId::F32>();
1118     TestArray<panda_file::Type::TypeId::F64>();
1119     TestArray<panda_file::Type::TypeId::REFERENCE>();
1120 }
1121 
AllocObject(BaseClass * cls)1122 ObjectHeader *AllocObject(BaseClass *cls)
1123 {
1124     return ObjectHeader::Create(cls);
1125 }
1126 
TEST_F(InterpreterTest,TestNewobj)1127 TEST_F(InterpreterTest, TestNewobj)
1128 {
1129     BytecodeEmitter emitter;
1130 
1131     emitter.Newobj(0, RuntimeInterface::TYPE_ID.AsIndex());
1132     emitter.LdaObj(0);
1133     emitter.ReturnObj();
1134 
1135     std::vector<uint8_t> bytecode;
1136     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1137 
1138     auto f = CreateFrame(16U, nullptr, nullptr);
1139     InitializeFrame(f.get());
1140 
1141     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1142     auto methodData = CreateMethod(cls, f.get(), bytecode);
1143     auto method = std::move(methodData.first);
1144     f->SetMethod(method.get());
1145 
1146     pandasm::Parser p;
1147     auto source = R"(
1148         .record R {}
1149     )";
1150 
1151     auto res = p.Parse(source);
1152     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1153 
1154     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1155     ASSERT_NE(classLinker, nullptr);
1156 
1157     classLinker->AddPandaFile(std::move(classPf));
1158 
1159     PandaString descriptor;
1160     auto *thread = ManagedThread::GetCurrent();
1161     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1162     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1163     ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
1164 
1165     ObjectHeader *obj = AllocObject(objectClass);
1166 
1167     RuntimeInterface::SetupResolvedClass(objectClass);
1168     RuntimeInterface::SetupObjectClass(objectClass);
1169     RuntimeInterface::SetupObject(obj);
1170 
1171     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1172 
1173     RuntimeInterface::SetupResolvedClass(nullptr);
1174     RuntimeInterface::SetupObjectClass(nullptr);
1175     RuntimeInterface::SetupObject(nullptr);
1176 
1177     EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1178 }
1179 
TEST_F(InterpreterTest,TestInitobj)1180 TEST_F(InterpreterTest, TestInitobj)
1181 {
1182     {
1183         BytecodeEmitter emitter;
1184 
1185         emitter.InitobjShort(0, 2U, RuntimeInterface::METHOD_ID.AsIndex());
1186         emitter.ReturnObj();
1187 
1188         std::vector<uint8_t> bytecode;
1189         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1190 
1191         auto f = CreateFrame(16U, nullptr, nullptr);
1192         InitializeFrame(f.get());
1193 
1194         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1195         auto methodData = CreateMethod(cls, f.get(), bytecode);
1196         auto method = std::move(methodData.first);
1197         f->SetMethod(method.get());
1198 
1199         pandasm::Parser p;
1200         auto source = R"(
1201             .record R {}
1202 
1203             .function void R.ctor(R a0, i32 a1, i32 a2) <static> {
1204                 return.void
1205             }
1206         )";
1207 
1208         auto res = p.Parse(source);
1209         auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1210 
1211         auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1212         ASSERT_NE(classLinker, nullptr);
1213 
1214         classLinker->AddPandaFile(std::move(classPf));
1215 
1216         PandaString descriptor;
1217 
1218         auto *thread = ManagedThread::GetCurrent();
1219         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1220         Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1221         ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
1222 
1223         Method *ctor = objectClass->GetMethods().data();
1224         ObjectHeader *obj = AllocObject(objectClass);
1225 
1226         auto frameHandler = StaticFrameHandler(f.get());
1227         frameHandler.GetVReg(0).Set(10U);
1228         frameHandler.GetVReg(2U).Set(20U);
1229 
1230         bool hasErrors = false;
1231 
1232         RuntimeInterface::SetupInvokeMethodHandler(
1233             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1234                 if (m != ctor) {
1235                     hasErrors = true;
1236                     return Value(nullptr);
1237                 }
1238 
1239                 Span<Value> sp(args, m->GetNumArgs());
1240                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1241                     hasErrors = true;
1242                     return Value(nullptr);
1243                 }
1244 
1245                 if (sp[1].GetAs<int32_t>() != frameHandler.GetVReg(0).Get()) {
1246                     hasErrors = true;
1247                     return Value(nullptr);
1248                 }
1249 
1250                 if (sp[2U].GetAs<int32_t>() != frameHandler.GetVReg(2U).Get()) {
1251                     hasErrors = true;
1252                     return Value(nullptr);
1253                 }
1254 
1255                 return Value(nullptr);
1256             });
1257 
1258         RuntimeInterface::SetupResolvedMethod(ctor);
1259         RuntimeInterface::SetupResolvedClass(objectClass);
1260         RuntimeInterface::SetupObjectClass(objectClass);
1261         RuntimeInterface::SetupObject(obj);
1262 
1263         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1264 
1265         ASSERT_FALSE(hasErrors);
1266 
1267         RuntimeInterface::SetupInvokeMethodHandler({});
1268         RuntimeInterface::SetupResolvedMethod(nullptr);
1269         RuntimeInterface::SetupResolvedClass(nullptr);
1270         RuntimeInterface::SetupObjectClass(nullptr);
1271         RuntimeInterface::SetupObject(nullptr);
1272 
1273         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1274     }
1275 
1276     {
1277         BytecodeEmitter emitter;
1278 
1279         emitter.Initobj(0U, 2U, 3U, 5U, RuntimeInterface::METHOD_ID.AsIndex());
1280         emitter.ReturnObj();
1281 
1282         std::vector<uint8_t> bytecode;
1283         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1284 
1285         auto f = CreateFrame(16U, nullptr, nullptr);
1286         InitializeFrame(f.get());
1287 
1288         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1289         auto methodData = CreateMethod(cls, f.get(), bytecode);
1290         auto method = std::move(methodData.first);
1291         f->SetMethod(method.get());
1292 
1293         pandasm::Parser p;
1294         auto source = R"(
1295             .record R {}
1296 
1297             .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <static> {
1298                 return.void
1299             }
1300         )";
1301 
1302         auto res = p.Parse(source);
1303         auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1304 
1305         auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1306         ASSERT_NE(classLinker, nullptr);
1307 
1308         classLinker->AddPandaFile(std::move(classPf));
1309 
1310         PandaString descriptor;
1311 
1312         auto *thread = ManagedThread::GetCurrent();
1313         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1314         Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1315         ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
1316 
1317         Method *ctor = objectClass->GetMethods().data();
1318         ObjectHeader *obj = AllocObject(objectClass);
1319 
1320         auto frameHandler = StaticFrameHandler(f.get());
1321         frameHandler.GetVReg(0U).Set(10U);
1322         frameHandler.GetVReg(2U).Set(20U);
1323         frameHandler.GetVReg(3U).Set(30U);
1324         frameHandler.GetVReg(5U).Set(40U);
1325 
1326         bool hasErrors = false;
1327 
1328         RuntimeInterface::SetupInvokeMethodHandler(
1329             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1330                 if (m != ctor) {
1331                     hasErrors = true;
1332                     return Value(nullptr);
1333                 }
1334 
1335                 Span<Value> sp(args, m->GetNumArgs());
1336                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1337                     hasErrors = true;
1338                     return Value(nullptr);
1339                 }
1340 
1341                 if (sp[1].GetAs<int32_t>() != frameHandler.GetVReg(0).Get()) {
1342                     hasErrors = true;
1343                     return Value(nullptr);
1344                 }
1345 
1346                 if (sp[2U].GetAs<int32_t>() != frameHandler.GetVReg(2U).Get()) {
1347                     hasErrors = true;
1348                     return Value(nullptr);
1349                 }
1350 
1351                 if (sp[3U].GetAs<int32_t>() != frameHandler.GetVReg(3U).Get()) {
1352                     hasErrors = true;
1353                     return Value(nullptr);
1354                 }
1355 
1356                 if (sp[4U].GetAs<int32_t>() != frameHandler.GetVReg(5U).Get()) {
1357                     hasErrors = true;
1358                     return Value(nullptr);
1359                 }
1360 
1361                 return Value(nullptr);
1362             });
1363 
1364         RuntimeInterface::SetupResolvedMethod(ctor);
1365         RuntimeInterface::SetupResolvedClass(objectClass);
1366         RuntimeInterface::SetupObjectClass(objectClass);
1367         RuntimeInterface::SetupObject(obj);
1368 
1369         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1370 
1371         ASSERT_FALSE(hasErrors);
1372 
1373         RuntimeInterface::SetupInvokeMethodHandler({});
1374         RuntimeInterface::SetupResolvedMethod(nullptr);
1375         RuntimeInterface::SetupResolvedClass(nullptr);
1376         RuntimeInterface::SetupObjectClass(nullptr);
1377         RuntimeInterface::SetupObject(nullptr);
1378 
1379         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1380     }
1381 
1382     {
1383         BytecodeEmitter emitter;
1384 
1385         emitter.InitobjRange(2U, RuntimeInterface::METHOD_ID.AsIndex());
1386         emitter.ReturnObj();
1387 
1388         std::vector<uint8_t> bytecode;
1389         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1390 
1391         auto f = CreateFrame(16U, nullptr, nullptr);
1392         InitializeFrame(f.get());
1393 
1394         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1395         auto methodData = CreateMethod(cls, f.get(), bytecode);
1396         auto method = std::move(methodData.first);
1397         f->SetMethod(method.get());
1398 
1399         pandasm::Parser p;
1400         auto source = R"(
1401             .record R {}
1402 
1403             .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5) <static> {
1404                 return.void
1405             }
1406         )";
1407 
1408         auto res = p.Parse(source);
1409         auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1410 
1411         auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1412         ASSERT_NE(classLinker, nullptr);
1413 
1414         classLinker->AddPandaFile(std::move(classPf));
1415 
1416         PandaString descriptor;
1417 
1418         auto *thread = ManagedThread::GetCurrent();
1419         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1420         Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1421         ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
1422 
1423         Method *ctor = objectClass->GetMethods().data();
1424         ObjectHeader *obj = AllocObject(objectClass);
1425 
1426         auto frameHandler = StaticFrameHandler(f.get());
1427         frameHandler.GetVReg(2U).Set(10U);
1428         frameHandler.GetVReg(3U).Set(20U);
1429         frameHandler.GetVReg(4U).Set(30U);
1430         frameHandler.GetVReg(5U).Set(40U);
1431         frameHandler.GetVReg(6U).Set(50U);
1432 
1433         bool hasErrors = false;
1434 
1435         RuntimeInterface::SetupInvokeMethodHandler(
1436             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1437                 if (m != ctor) {
1438                     hasErrors = true;
1439                     return Value(nullptr);
1440                 }
1441 
1442                 Span<Value> sp(args, m->GetNumArgs());
1443                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1444                     hasErrors = true;
1445                     return Value(nullptr);
1446                 }
1447 
1448                 if (sp[1U].GetAs<int32_t>() != frameHandler.GetVReg(2U).Get()) {
1449                     hasErrors = true;
1450                     return Value(nullptr);
1451                 }
1452 
1453                 if (sp[2U].GetAs<int32_t>() != frameHandler.GetVReg(3U).Get()) {
1454                     hasErrors = true;
1455                     return Value(nullptr);
1456                 }
1457 
1458                 if (sp[3U].GetAs<int32_t>() != frameHandler.GetVReg(4U).Get()) {
1459                     hasErrors = true;
1460                     return Value(nullptr);
1461                 }
1462 
1463                 if (sp[4U].GetAs<int32_t>() != frameHandler.GetVReg(5U).Get()) {
1464                     hasErrors = true;
1465                     return Value(nullptr);
1466                 }
1467 
1468                 if (sp[5U].GetAs<int32_t>() != frameHandler.GetVReg(6U).Get()) {
1469                     hasErrors = true;
1470                     return Value(nullptr);
1471                 }
1472 
1473                 return Value(nullptr);
1474             });
1475 
1476         RuntimeInterface::SetupResolvedMethod(ctor);
1477         RuntimeInterface::SetupResolvedClass(objectClass);
1478         RuntimeInterface::SetupObjectClass(objectClass);
1479         RuntimeInterface::SetupObject(obj);
1480 
1481         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1482 
1483         ASSERT_FALSE(hasErrors);
1484 
1485         RuntimeInterface::SetupInvokeMethodHandler({});
1486         RuntimeInterface::SetupResolvedMethod(nullptr);
1487         RuntimeInterface::SetupResolvedClass(nullptr);
1488         RuntimeInterface::SetupObjectClass(nullptr);
1489         RuntimeInterface::SetupObject(nullptr);
1490 
1491         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1492     }
1493 }
1494 
TestLoadStoreField(bool isStatic)1495 void TestLoadStoreField(bool isStatic)
1496 {
1497     BytecodeEmitter emitter;
1498 
1499     if (isStatic) {
1500         emitter.Ldstatic(RuntimeInterface::FIELD_ID.AsIndex());
1501         emitter.StaWide(1U);
1502         emitter.LdaWide(2U);
1503         emitter.Ststatic(RuntimeInterface::FIELD_ID.AsIndex());
1504         emitter.Ldstatic(RuntimeInterface::FIELD_ID.AsIndex());
1505     } else {
1506         emitter.Ldobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1507         emitter.StaWide(1U);
1508         emitter.LdaWide(2U);
1509         emitter.Stobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1510         emitter.Ldobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1511     }
1512     emitter.ReturnWide();
1513 
1514     std::vector<uint8_t> bytecode;
1515     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1516 
1517     auto f = CreateFrame(16U, nullptr, nullptr);
1518     InitializeFrame(f.get());
1519 
1520     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1521     auto methodData = CreateMethod(cls, f.get(), bytecode);
1522     auto method = std::move(methodData.first);
1523     f->SetMethod(method.get());
1524 
1525     pandasm::Parser p;
1526     std::string source;
1527 
1528     if (isStatic) {
1529         source = R"(
1530             .record R {
1531                 u1  sf_u1  <static>
1532                 i8  sf_i8  <static>
1533                 u8  sf_u8  <static>
1534                 i16 sf_i16 <static>
1535                 u16 sf_u16 <static>
1536                 i32 sf_i32 <static>
1537                 u32 sf_u32 <static>
1538                 i64 sf_i64 <static>
1539                 u64 sf_u64 <static>
1540                 f32 sf_f32 <static>
1541                 f64 sf_f64 <static>
1542             }
1543         )";
1544     } else {
1545         source = R"(
1546             .record R {
1547                 u1  if_u1
1548                 i8  if_i8
1549                 u8  if_u8
1550                 i16 if_i16
1551                 u16 if_u16
1552                 i32 if_i32
1553                 u32 if_u32
1554                 i64 if_i64
1555                 u64 if_u64
1556                 f32 if_f32
1557                 f64 if_f64
1558             }
1559         )";
1560     }
1561 
1562     auto res = p.Parse(source);
1563     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1564 
1565     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1566     ASSERT_NE(classLinker, nullptr);
1567 
1568     classLinker->AddPandaFile(std::move(classPf));
1569 
1570     PandaString descriptor;
1571 
1572     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1573     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1574     ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), objectClass));
1575     ObjectHeader *obj = nullptr;
1576 
1577     auto frameHandler = StaticFrameHandler(f.get());
1578     if (!isStatic) {
1579         obj = AllocObject(objectClass);
1580         frameHandler.GetVReg(0).SetReference(obj);
1581     }
1582 
1583     std::vector<panda_file::Type::TypeId> types {
1584         panda_file::Type::TypeId::U1,  panda_file::Type::TypeId::I8,  panda_file::Type::TypeId::U8,
1585         panda_file::Type::TypeId::I16, panda_file::Type::TypeId::U16, panda_file::Type::TypeId::I32,
1586         panda_file::Type::TypeId::U32, panda_file::Type::TypeId::I64, panda_file::Type::TypeId::U64,
1587         panda_file::Type::TypeId::F32, panda_file::Type::TypeId::F64};
1588 
1589     Span<Field> fields = isStatic ? objectClass->GetStaticFields() : objectClass->GetInstanceFields();
1590     for (Field &field : fields) {
1591         std::ostringstream ss;
1592         ss << "Test field " << reinterpret_cast<const char *>(field.GetName().data);
1593 
1594         constexpr float FLOAT_VALUE = 1.0;
1595         constexpr double DOUBLE_VALUE = 2.0F;
1596         int64_t value = 0;
1597 
1598         switch (field.GetTypeId()) {
1599             case panda_file::Type::TypeId::U1: {
1600                 value = std::numeric_limits<uint8_t>::max();
1601                 frameHandler.GetVReg(2U).SetPrimitive(value);
1602                 break;
1603             }
1604             case panda_file::Type::TypeId::I8: {
1605                 value = std::numeric_limits<int8_t>::min();
1606                 frameHandler.GetVReg(2U).SetPrimitive(value);
1607                 break;
1608             }
1609             case panda_file::Type::TypeId::U8: {
1610                 value = std::numeric_limits<uint8_t>::max();
1611                 frameHandler.GetVReg(2U).SetPrimitive(value);
1612                 break;
1613             }
1614             case panda_file::Type::TypeId::I16: {
1615                 value = std::numeric_limits<int16_t>::min();
1616                 frameHandler.GetVReg(2U).SetPrimitive(value);
1617                 break;
1618             }
1619             case panda_file::Type::TypeId::U16: {
1620                 value = std::numeric_limits<uint16_t>::max();
1621                 frameHandler.GetVReg(2U).SetPrimitive(value);
1622                 break;
1623             }
1624             case panda_file::Type::TypeId::I32: {
1625                 value = std::numeric_limits<int32_t>::min();
1626                 frameHandler.GetVReg(2U).SetPrimitive(value);
1627                 break;
1628             }
1629             case panda_file::Type::TypeId::U32: {
1630                 value = std::numeric_limits<uint32_t>::max();
1631                 frameHandler.GetVReg(2U).SetPrimitive(value);
1632                 break;
1633             }
1634             case panda_file::Type::TypeId::I64: {
1635                 value = std::numeric_limits<int64_t>::min();
1636                 frameHandler.GetVReg(2U).SetPrimitive(value);
1637                 break;
1638             }
1639             case panda_file::Type::TypeId::U64: {
1640                 value = std::numeric_limits<uint64_t>::max();
1641                 frameHandler.GetVReg(2U).SetPrimitive(value);
1642                 break;
1643             }
1644             case panda_file::Type::TypeId::F32: {
1645                 frameHandler.GetVReg(2U).SetPrimitive(FLOAT_VALUE);
1646                 break;
1647             }
1648             case panda_file::Type::TypeId::F64: {
1649                 frameHandler.GetVReg(2U).SetPrimitive(DOUBLE_VALUE);
1650                 break;
1651             }
1652             default: {
1653                 UNREACHABLE();
1654                 break;
1655             }
1656         }
1657 
1658         RuntimeInterface::SetupResolvedField(&field);
1659 
1660         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1661 
1662         RuntimeInterface::SetupResolvedField(nullptr);
1663 
1664         switch (field.GetTypeId()) {
1665             case panda_file::Type::TypeId::F32: {
1666                 EXPECT_EQ(f->GetAccAsVReg().GetFloat(), FLOAT_VALUE) << ss.str();
1667                 break;
1668             }
1669             case panda_file::Type::TypeId::F64: {
1670                 EXPECT_EQ(f->GetAccAsVReg().GetDouble(), DOUBLE_VALUE) << ss.str();
1671                 break;
1672             }
1673             default: {
1674                 EXPECT_EQ(f->GetAccAsVReg().GetLong(), value) << ss.str();
1675                 break;
1676             }
1677         }
1678 
1679         EXPECT_EQ(frameHandler.GetVReg(1).GetLong(), 0) << ss.str();
1680     }
1681 }
1682 
TestLoadStoreObjectField(bool isStatic)1683 void TestLoadStoreObjectField(bool isStatic)
1684 {
1685     BytecodeEmitter emitter;
1686 
1687     std::ostringstream ss;
1688     ss << "Test load/store ";
1689     if (isStatic) {
1690         ss << "static ";
1691     }
1692     ss << "object field";
1693 
1694     if (isStatic) {
1695         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1696         emitter.StaObj(1U);
1697         emitter.LdaObj(2U);
1698         emitter.StstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1699         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1700     } else {
1701         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1702         emitter.StaObj(1U);
1703         emitter.LdaObj(2U);
1704         emitter.StobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1705         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1706     }
1707     emitter.ReturnObj();
1708 
1709     std::vector<uint8_t> bytecode;
1710     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
1711 
1712     auto f = CreateFrame(16U, nullptr, nullptr);
1713     InitializeFrame(f.get());
1714 
1715     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1716     auto methodData = CreateMethod(cls, f.get(), bytecode);
1717     auto method = std::move(methodData.first);
1718     f->SetMethod(method.get());
1719 
1720     pandasm::Parser p;
1721     std::string source;
1722 
1723     if (isStatic) {
1724         source = R"(
1725             .record R {
1726                 R sf_ref <static>
1727             }
1728         )";
1729     } else {
1730         source = R"(
1731             .record R {
1732                 R sf_ref
1733             }
1734         )";
1735     }
1736 
1737     auto res = p.Parse(source);
1738     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1739 
1740     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1741     ASSERT_NE(classLinker, nullptr) << ss.str();
1742 
1743     classLinker->AddPandaFile(std::move(classPf));
1744 
1745     PandaString descriptor;
1746 
1747     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1748     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1749     ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), objectClass)) << ss.str();
1750 
1751     ObjectHeader *obj = nullptr;
1752 
1753     auto frameHandler = StaticFrameHandler(f.get());
1754     if (!isStatic) {
1755         obj = AllocObject(objectClass);
1756         frameHandler.GetVReg(0).SetReference(obj);
1757     }
1758 
1759     Span<Field> fields = isStatic ? objectClass->GetStaticFields() : objectClass->GetInstanceFields();
1760     Field *field = &fields[0];
1761     ObjectHeader *refValue = panda::mem::AllocateNullifiedPayloadString(1);
1762 
1763     frameHandler.GetVReg(2U).SetReference(refValue);
1764 
1765     RuntimeInterface::SetupResolvedField(field);
1766 
1767     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1768 
1769     RuntimeInterface::SetupResolvedField(nullptr);
1770 
1771     EXPECT_EQ(f->GetAccAsVReg().GetReference(), refValue) << ss.str();
1772     EXPECT_EQ(frameHandler.GetVReg(1).GetReference(), nullptr) << ss.str();
1773 }
1774 
TEST_F(InterpreterTest,TestLoadStoreField)1775 TEST_F(InterpreterTest, TestLoadStoreField)
1776 {
1777     TestLoadStoreField(false);
1778     TestLoadStoreObjectField(false);
1779 }
1780 
TEST_F(InterpreterTest,TestLoadStoreStaticField)1781 TEST_F(InterpreterTest, TestLoadStoreStaticField)
1782 {
1783     TestLoadStoreField(true);
1784     TestLoadStoreObjectField(true);
1785 }
1786 
TEST_F(InterpreterTest,TestReturns)1787 TEST_F(InterpreterTest, TestReturns)
1788 {
1789     int64_t value = 0xaabbccdd11223344;
1790 
1791     {
1792         BytecodeEmitter emitter;
1793 
1794         emitter.Return();
1795 
1796         std::vector<uint8_t> bytecode;
1797         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1798 
1799         auto f = CreateFrame(16U, nullptr, nullptr);
1800         InitializeFrame(f.get());
1801 
1802         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1803         auto methodData = CreateMethod(cls, f.get(), bytecode);
1804         auto method = std::move(methodData.first);
1805         f->SetMethod(method.get());
1806 
1807         f->GetAccAsVReg().SetPrimitive(value);
1808 
1809         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1810 
1811         EXPECT_EQ(f->GetAccAsVReg().Get(), static_cast<int32_t>(value));
1812         EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1813     }
1814 
1815     {
1816         BytecodeEmitter emitter;
1817 
1818         emitter.ReturnWide();
1819 
1820         std::vector<uint8_t> bytecode;
1821         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1822 
1823         auto f = CreateFrame(16U, nullptr, nullptr);
1824         InitializeFrame(f.get());
1825 
1826         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1827         auto methodData = CreateMethod(cls, f.get(), bytecode);
1828         auto method = std::move(methodData.first);
1829         f->SetMethod(method.get());
1830 
1831         f->GetAccAsVReg().SetPrimitive(value);
1832 
1833         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1834 
1835         EXPECT_EQ(f->GetAccAsVReg().GetLong(), value);
1836         EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1837     }
1838 
1839     {
1840         BytecodeEmitter emitter;
1841 
1842         emitter.ReturnObj();
1843 
1844         std::vector<uint8_t> bytecode;
1845         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1846 
1847         auto f = CreateFrame(16U, nullptr, nullptr);
1848         InitializeFrame(f.get());
1849 
1850         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1851         auto methodData = CreateMethod(cls, f.get(), bytecode);
1852         auto method = std::move(methodData.first);
1853         f->SetMethod(method.get());
1854 
1855         ObjectHeader *obj = panda::mem::AllocateNullifiedPayloadString(1);
1856         f->GetAccAsVReg().SetReference(obj);
1857 
1858         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1859 
1860         EXPECT_EQ(f->GetAccAsVReg().GetReference(), obj);
1861         EXPECT_TRUE(f->GetAccAsVReg().HasObject());
1862     }
1863 }
1864 
AddProgramToClassLinker(std::string_view source,bool & failed)1865 auto AddProgramToClassLinker(std::string_view source, bool &failed)
1866 {
1867     pandasm::Parser p;
1868     auto res = p.Parse(source.data());
1869     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1870 
1871     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1872     if (classLinker == nullptr) {
1873         failed = true;
1874         return classLinker;
1875     }
1876 
1877     classLinker->AddPandaFile(std::move(classPf));
1878     return classLinker;
1879 }
1880 
InitObjectClass(ClassLinker * classLinker,const uint8_t * descriptor,bool & failed)1881 auto InitObjectClass(ClassLinker *classLinker, const uint8_t *descriptor, bool &failed)
1882 {
1883     auto *thread = ManagedThread::GetCurrent();
1884     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1885     auto *objectClass = ext->GetClass(descriptor);
1886     failed = !classLinker->InitializeClass(thread, objectClass);
1887     return objectClass;
1888 }
1889 
GetClassDescriptor(const char * name)1890 auto GetClassDescriptor(const char *name)
1891 {
1892     static PandaString descriptor;
1893     descriptor.clear();
1894     return ClassHelper::GetDescriptor(utf::CStringAsMutf8(name), &descriptor);
1895 }
1896 
GetArrayDescriptor(const char * name,int rank)1897 auto GetArrayDescriptor(const char *name, int rank)
1898 {
1899     static PandaString descriptor;
1900     descriptor.clear();
1901     return ClassHelper::GetArrayDescriptor(utf::CStringAsMutf8(name), rank, &descriptor);
1902 }
1903 
TEST_F(InterpreterTest,TestIsInstance)1904 TEST_F(InterpreterTest, TestIsInstance)
1905 {
1906     auto emitterFactory = []() {
1907         auto emitter = std::make_unique<BytecodeEmitter>();
1908         emitter->Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
1909         emitter->Return();
1910         return emitter;
1911     };
1912     auto source = R"(
1913         .record R {}
1914     )";
1915 
1916     {
1917         auto emitter = emitterFactory();
1918         std::vector<uint8_t> bytecode;
1919         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1920 
1921         auto f = CreateFrame(16U, nullptr, nullptr);
1922         InitializeFrame(f.get());
1923         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1924         auto methodData = CreateMethod(cls, f.get(), bytecode);
1925         auto method = std::move(methodData.first);
1926         f->SetMethod(method.get());
1927 
1928         bool failed = false;
1929         auto classLinker = AddProgramToClassLinker(source, failed);
1930         ASSERT_FALSE(failed);
1931 
1932         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
1933         ASSERT_FALSE(failed);
1934 
1935         f->GetAccAsVReg().SetReference(nullptr);
1936 
1937         RuntimeInterface::SetupResolvedClass(objectClass);
1938         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1939         RuntimeInterface::SetupResolvedClass(nullptr);
1940         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
1941     }
1942 
1943     {
1944         auto emitter = emitterFactory();
1945         std::vector<uint8_t> bytecode;
1946         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1947 
1948         auto f = CreateFrame(16U, nullptr, nullptr);
1949         InitializeFrame(f.get());
1950         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1951         auto methodData = CreateMethod(cls, f.get(), bytecode);
1952         auto method = std::move(methodData.first);
1953         f->SetMethod(method.get());
1954 
1955         bool failed = false;
1956         auto classLinker = AddProgramToClassLinker(source, failed);
1957         ASSERT_FALSE(failed);
1958         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
1959         ASSERT_FALSE(failed);
1960 
1961         auto *obj = AllocObject(objectClass);
1962         f->GetAccAsVReg().SetReference(obj);
1963 
1964         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
1965         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
1966         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
1967         RuntimeInterface::SetupResolvedClass(dstClass);
1968 
1969         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1970         RuntimeInterface::SetupResolvedClass(nullptr);
1971         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
1972     }
1973 
1974     {
1975         auto emitter = emitterFactory();
1976         std::vector<uint8_t> bytecode;
1977         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1978 
1979         auto f = CreateFrame(16U, nullptr, nullptr);
1980         InitializeFrame(f.get());
1981         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1982         auto methodData = CreateMethod(cls, f.get(), bytecode);
1983         auto method = std::move(methodData.first);
1984         f->SetMethod(method.get());
1985 
1986         bool failed = false;
1987         auto classLinker = AddProgramToClassLinker(source, failed);
1988         ASSERT_FALSE(failed);
1989         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
1990         ASSERT_FALSE(failed);
1991 
1992         f->GetAccAsVReg().SetReference(nullptr);
1993 
1994         RuntimeInterface::SetupResolvedClass(objectClass);
1995         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1996         RuntimeInterface::SetupResolvedClass(nullptr);
1997         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
1998     }
1999 
2000     {
2001         auto emitter = emitterFactory();
2002         std::vector<uint8_t> bytecode;
2003         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2004 
2005         auto f = CreateFrame(16U, nullptr, nullptr);
2006         InitializeFrame(f.get());
2007         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2008         auto methodData = CreateMethod(cls, f.get(), bytecode);
2009         auto method = std::move(methodData.first);
2010         f->SetMethod(method.get());
2011 
2012         bool failed = false;
2013         auto classLinker = AddProgramToClassLinker(source, failed);
2014         ASSERT_FALSE(failed);
2015         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
2016         ASSERT_FALSE(failed);
2017 
2018         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2019         f->GetAccAsVReg().SetReference(obj);
2020 
2021         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2022         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2023         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
2024 
2025         RuntimeInterface::SetupResolvedClass(dstClass);
2026         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2027         RuntimeInterface::SetupResolvedClass(nullptr);
2028         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2029     }
2030 }
2031 
CreateException(ManagedThread * thread)2032 static ObjectHeader *CreateException(ManagedThread *thread)
2033 {
2034     auto classLinker = CreateClassLinker(thread);
2035     auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2036     auto *cls = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2037     auto *exception = ObjectHeader::Create(cls);
2038     return exception;
2039 }
2040 
TEST_F(InterpreterTest,TestCheckCast)2041 TEST_F(InterpreterTest, TestCheckCast)
2042 {
2043     auto emitterFactory = []() {
2044         auto emitter = std::make_unique<BytecodeEmitter>();
2045         emitter->Checkcast(RuntimeInterface::TYPE_ID.AsIndex());
2046         emitter->ReturnVoid();
2047         return emitter;
2048     };
2049 
2050     {
2051         auto emitter = emitterFactory();
2052         auto source = R"(.record R {})";
2053         std::vector<uint8_t> bytecode;
2054         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2055 
2056         auto f = CreateFrame(16U, nullptr, nullptr);
2057         InitializeFrame(f.get());
2058         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2059         auto methodData = CreateMethod(cls, f.get(), bytecode);
2060         auto method = std::move(methodData.first);
2061         f->SetMethod(method.get());
2062 
2063         bool failed = false;
2064         auto classLinker = AddProgramToClassLinker(source, failed);
2065         ASSERT_FALSE(failed);
2066         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
2067         ASSERT_FALSE(failed);
2068 
2069         f->GetAccAsVReg().SetReference(nullptr);
2070 
2071         RuntimeInterface::SetupResolvedClass(objectClass);
2072         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2073         RuntimeInterface::SetupResolvedClass(nullptr);
2074     }
2075     {
2076         auto emitter = emitterFactory();
2077         auto source = R"(.record R {})";
2078         std::vector<uint8_t> bytecode;
2079         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2080 
2081         auto f = CreateFrame(16U, nullptr, nullptr);
2082         InitializeFrame(f.get());
2083         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2084         auto methodData = CreateMethod(cls, f.get(), bytecode);
2085         auto method = std::move(methodData.first);
2086         f->SetMethod(method.get());
2087 
2088         bool failed = false;
2089         auto classLinker = AddProgramToClassLinker(source, failed);
2090         ASSERT_FALSE(failed);
2091         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
2092         ASSERT_FALSE(failed);
2093 
2094         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2095         f->GetAccAsVReg().SetReference(obj);
2096 
2097         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2098         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2099         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
2100 
2101         RuntimeInterface::SetupResolvedClass(dstClass);
2102         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2103         RuntimeInterface::SetupResolvedClass(nullptr);
2104     }
2105     {
2106         auto emitter = emitterFactory();
2107         auto source = R"(
2108             .record A {}
2109             .record B <extends=A> {}
2110             .record C <extends=B> {}
2111         )";
2112         std::vector<uint8_t> bytecode;
2113         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2114 
2115         auto f = CreateFrame(16U, nullptr, nullptr);
2116         InitializeFrame(f.get());
2117         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2118         auto methodData = CreateMethod(cls, f.get(), bytecode);
2119         auto method = std::move(methodData.first);
2120         f->SetMethod(method.get());
2121 
2122         bool failed = false;
2123         auto classLinker = AddProgramToClassLinker(source, failed);
2124         ASSERT_FALSE(failed);
2125         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("C"), failed);
2126         ASSERT_FALSE(failed);
2127 
2128         auto *obj = AllocObject(objectClass);
2129         f->GetAccAsVReg().SetReference(obj);
2130 
2131         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2132         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("A")));
2133         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2134         RuntimeInterface::SetupResolvedClass(nullptr);
2135     }
2136     {
2137         auto emitter = emitterFactory();
2138         auto source = R"(
2139             .record A {}
2140             .record B <extends=A> {}
2141             .record C <extends=B> {}
2142         )";
2143         std::vector<uint8_t> bytecode;
2144         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2145 
2146         auto f = CreateFrame(16U, nullptr, nullptr);
2147         InitializeFrame(f.get());
2148         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2149         auto methodData = CreateMethod(cls, f.get(), bytecode);
2150         auto method = std::move(methodData.first);
2151         f->SetMethod(method.get());
2152 
2153         bool failed = false;
2154         auto classLinker = AddProgramToClassLinker(source, failed);
2155         ASSERT_FALSE(failed);
2156         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("C", 2_I), failed);
2157         ASSERT_FALSE(failed);
2158 
2159         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2160         f->GetAccAsVReg().SetReference(obj);
2161 
2162         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2163         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("A", 2_I)));
2164         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2165         RuntimeInterface::SetupResolvedClass(nullptr);
2166     }
2167     {
2168         BytecodeEmitter emitter;
2169         emitter.Checkcast(RuntimeInterface::TYPE_ID.AsIndex());
2170         emitter.ReturnVoid();
2171 
2172         std::vector<uint8_t> bytecode;
2173         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2174 
2175         RuntimeInterface::SetCatchBlockPcOffset(bytecode.size());
2176 
2177         emitter.ReturnObj();
2178 
2179         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2180 
2181         auto f = CreateFrame(16U, nullptr, nullptr);
2182         InitializeFrame(f.get());
2183         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2184         auto methodData = CreateMethod(cls, f.get(), bytecode);
2185         auto method = std::move(methodData.first);
2186         f->SetMethod(method.get());
2187 
2188         pandasm::Parser p;
2189         auto source = R"(
2190             .record A {}
2191             .record B <extends=A> {}
2192             .record C <extends=B> {}
2193         )";
2194 
2195         auto res = p.Parse(source);
2196         auto classPf = pandasm::AsmEmitter::Emit(res.Value());
2197 
2198         auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
2199         ASSERT_NE(classLinker, nullptr);
2200 
2201         classLinker->AddPandaFile(std::move(classPf));
2202 
2203         PandaString descriptor;
2204         auto *thread = ManagedThread::GetCurrent();
2205         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2206         auto *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("A"), &descriptor));
2207         ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
2208 
2209         auto *obj = AllocObject(objectClass);
2210 
2211         f->GetAccAsVReg().SetReference(obj);
2212 
2213         auto *dstClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("C"), &descriptor));
2214         ASSERT_TRUE(classLinker->InitializeClass(thread, dstClass));
2215         RuntimeInterface::SetupResolvedClass(dstClass);
2216 
2217         RuntimeInterface::SetClassCastExceptionData({true, dstClass, objectClass});
2218 
2219         auto *exception = CreateException(thread);
2220         thread->SetException(exception);
2221 
2222         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2223 
2224         RuntimeInterface::SetupResolvedClass(nullptr);
2225 
2226         RuntimeInterface::SetClassCastExceptionData({false, nullptr, nullptr});
2227 
2228         ASSERT_FALSE(thread->HasPendingException());
2229         ASSERT_EQ(f->GetAccAsVReg().GetReference(), exception);
2230     }
2231 }
2232 
TEST_F(InterpreterTest,TestIsInstanceInheritance)2233 TEST_F(InterpreterTest, TestIsInstanceInheritance)
2234 {
2235     auto emitterFactory = []() {
2236         auto emitter = std::make_unique<BytecodeEmitter>();
2237         emitter->Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
2238         emitter->Return();
2239         return emitter;
2240     };
2241 
2242     {
2243         auto emitter = emitterFactory();
2244         auto source = R"(
2245             .record A {}
2246             .record B <extends=A> {}
2247             .record C <extends=B> {}
2248         )";
2249         std::vector<uint8_t> bytecode;
2250         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2251 
2252         auto f = CreateFrame(16U, nullptr, nullptr);
2253         InitializeFrame(f.get());
2254         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2255         auto methodData = CreateMethod(cls, f.get(), bytecode);
2256         auto method = std::move(methodData.first);
2257         f->SetMethod(method.get());
2258 
2259         bool failed = false;
2260         auto classLinker = AddProgramToClassLinker(source, failed);
2261         ASSERT_FALSE(failed);
2262         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("C"), failed);
2263         ASSERT_FALSE(failed);
2264 
2265         auto *obj = AllocObject(objectClass);
2266         f->GetAccAsVReg().SetReference(obj);
2267 
2268         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2269         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("A")));
2270         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2271         RuntimeInterface::SetupResolvedClass(nullptr);
2272 
2273         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2274     }
2275 
2276     {
2277         auto emitter = emitterFactory();
2278         auto source = R"(
2279             .record A {}
2280             .record B <extends=A> {}
2281             .record C <extends=B> {}
2282         )";
2283         std::vector<uint8_t> bytecode;
2284         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2285 
2286         auto f = CreateFrame(16U, nullptr, nullptr);
2287         InitializeFrame(f.get());
2288         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2289         auto methodData = CreateMethod(cls, f.get(), bytecode);
2290         auto method = std::move(methodData.first);
2291         f->SetMethod(method.get());
2292 
2293         bool failed = false;
2294         auto classLinker = AddProgramToClassLinker(source, failed);
2295         ASSERT_FALSE(failed);
2296         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("C", 2_I), failed);
2297         ASSERT_FALSE(failed);
2298 
2299         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2300         f->GetAccAsVReg().SetReference(obj);
2301 
2302         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2303         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("A", 2_I)));
2304         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2305         RuntimeInterface::SetupResolvedClass(nullptr);
2306 
2307         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2308     }
2309 
2310     {
2311         auto emitter = emitterFactory();
2312         auto source = R"(
2313             .record A {}
2314             .record B <extends=A> {}
2315             .record C <extends=B> {}
2316         )";
2317         std::vector<uint8_t> bytecode;
2318         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2319 
2320         auto f = CreateFrame(16U, nullptr, nullptr);
2321         InitializeFrame(f.get());
2322         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2323         auto methodData = CreateMethod(cls, f.get(), bytecode);
2324         auto method = std::move(methodData.first);
2325         f->SetMethod(method.get());
2326 
2327         bool failed = false;
2328         auto classLinker = AddProgramToClassLinker(source, failed);
2329         ASSERT_FALSE(failed);
2330         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("A"), failed);
2331         ASSERT_FALSE(failed);
2332 
2333         auto *obj = AllocObject(objectClass);
2334         f->GetAccAsVReg().SetReference(obj);
2335 
2336         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2337         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("C")));
2338         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2339         RuntimeInterface::SetupResolvedClass(nullptr);
2340 
2341         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2342     }
2343 
2344     {
2345         auto emitter = emitterFactory();
2346         auto source = R"(
2347             .record A {}
2348             .record B <extends=A> {}
2349             .record C <extends=B> {}
2350         )";
2351         std::vector<uint8_t> bytecode;
2352         ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2353 
2354         auto f = CreateFrame(16U, nullptr, nullptr);
2355         InitializeFrame(f.get());
2356         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2357         auto methodData = CreateMethod(cls, f.get(), bytecode);
2358         auto method = std::move(methodData.first);
2359         f->SetMethod(method.get());
2360 
2361         bool failed = false;
2362         auto classLinker = AddProgramToClassLinker(source, failed);
2363         ASSERT_FALSE(failed);
2364         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("A", 2_I), failed);
2365         ASSERT_FALSE(failed);
2366 
2367         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2368         f->GetAccAsVReg().SetReference(obj);
2369 
2370         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2371         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("C", 2_I)));
2372         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2373         RuntimeInterface::SetupResolvedClass(nullptr);
2374 
2375         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2376     }
2377 }
2378 
TEST_F(InterpreterTest,TestVirtualCalls)2379 TEST_F(InterpreterTest, TestVirtualCalls)
2380 {
2381     {
2382         auto emitter = BytecodeEmitter {};
2383         emitter.CallVirtShort(0, 1, RuntimeInterface::METHOD_ID.AsIndex());
2384         emitter.Return();
2385         std::vector<uint8_t> bytecode;
2386         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2387 
2388         auto f = CreateFrame(16U, nullptr, nullptr);
2389         InitializeFrame(f.get());
2390         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2391         auto methodData = CreateMethod(cls, f.get(), bytecode);
2392         auto method = std::move(methodData.first);
2393         f->SetMethod(method.get());
2394 
2395         auto source = R"(
2396             .record A {}
2397             .record B <extends=A> {}
2398 
2399             .function i32 A.foo(A a0, i32 a1) {
2400                 lda a1
2401                 addi 1
2402                 return
2403             }
2404 
2405             .function i32 B.foo(B a0, i32 a1) {
2406                 lda a1
2407                 addi 2
2408                 return
2409             }
2410         )";
2411 
2412         bool failed = false;
2413         auto classLinker = AddProgramToClassLinker(source, failed);
2414         ASSERT_FALSE(failed);
2415 
2416         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2417         auto *classA = ext->GetClass(GetClassDescriptor("A"));
2418         auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2419         auto *callee = classA->GetMethods().data();
2420         auto *obj = AllocObject(objectClass);
2421 
2422         auto frameHandler = StaticFrameHandler(f.get());
2423         frameHandler.GetVReg(0).SetReference(obj);
2424         frameHandler.GetVReg(1).Set(1);
2425 
2426         RuntimeInterface::SetupResolvedMethod(callee);
2427         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2428         RuntimeInterface::SetupResolvedMethod(nullptr);
2429 
2430         ASSERT_EQ(f->GetAccAsVReg().Get(), 3L);
2431     }
2432 
2433     {
2434         auto emitter = BytecodeEmitter {};
2435         emitter.CallVirt(0U, 1U, 2U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2436         emitter.Return();
2437         std::vector<uint8_t> bytecode;
2438         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2439 
2440         auto f = CreateFrame(16U, nullptr, nullptr);
2441         InitializeFrame(f.get());
2442         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2443         auto methodData = CreateMethod(cls, f.get(), bytecode);
2444         auto method = std::move(methodData.first);
2445         f->SetMethod(method.get());
2446 
2447         auto source = R"(
2448             .record A {}
2449             .record B <extends=A> {}
2450 
2451             .function i32 A.foo(A a0, i32 a1, i32 a2, i32 a3) {
2452                 lda a1
2453                 addi 1
2454                 return
2455             }
2456 
2457             .function i32 B.foo(B a0, i32 a1, i32 a2, i32 a3) {
2458                 lda a1
2459                 addi 2
2460                 add2 a2
2461                 add2 a3
2462                 return
2463             }
2464         )";
2465 
2466         bool failed = false;
2467         auto classLinker = AddProgramToClassLinker(source, failed);
2468         ASSERT_FALSE(failed);
2469 
2470         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2471         auto *classA = ext->GetClass(GetClassDescriptor("A"));
2472         auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2473         auto *callee = classA->GetMethods().data();
2474         auto *obj = AllocObject(objectClass);
2475 
2476         auto frameHandler = StaticFrameHandler(f.get());
2477         frameHandler.GetVReg(0U).SetReference(obj);
2478         frameHandler.GetVReg(1U).Set(1U);
2479         frameHandler.GetVReg(2U).Set(2U);
2480         frameHandler.GetVReg(3U).Set(3U);
2481 
2482         RuntimeInterface::SetupResolvedMethod(callee);
2483         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2484         RuntimeInterface::SetupResolvedMethod(nullptr);
2485 
2486         ASSERT_EQ(f->GetAccAsVReg().Get(), 8L);
2487     }
2488 
2489     {
2490         auto emitter = BytecodeEmitter {};
2491         emitter.CallVirtRange(0, RuntimeInterface::METHOD_ID.AsIndex());
2492         emitter.Return();
2493         std::vector<uint8_t> bytecode;
2494         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2495 
2496         auto f = CreateFrame(16U, nullptr, nullptr);
2497         InitializeFrame(f.get());
2498         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2499         auto methodData = CreateMethod(cls, f.get(), bytecode);
2500         auto method = std::move(methodData.first);
2501         f->SetMethod(method.get());
2502 
2503         auto source = R"(
2504             .record A {}
2505             .record B <extends=A> {}
2506 
2507             .function i32 A.foo(A a0, i32 a1, i32 a2, i32 a3, i32 a4) {
2508                 lda a1
2509                 addi 1
2510                 return
2511             }
2512 
2513             .function i32 B.foo(B a0, i32 a1, i32 a2, i32 a3, i32 a4) {
2514                 lda a1
2515                 addi 2
2516                 add2 a2
2517                 add2 a3
2518                 add2 a4
2519                 return
2520             }
2521         )";
2522 
2523         bool failed = false;
2524         auto classLinker = AddProgramToClassLinker(source, failed);
2525         ASSERT_FALSE(failed);
2526 
2527         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2528         auto *classA = ext->GetClass(GetClassDescriptor("A"));
2529         auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2530         auto *callee = classA->GetMethods().data();
2531         auto *obj = AllocObject(objectClass);
2532 
2533         auto frameHandler = StaticFrameHandler(f.get());
2534         frameHandler.GetVReg(0U).SetReference(obj);
2535         frameHandler.GetVReg(1U).Set(1U);
2536         frameHandler.GetVReg(2U).Set(2U);
2537         frameHandler.GetVReg(3U).Set(3U);
2538         frameHandler.GetVReg(4U).Set(4U);
2539 
2540         RuntimeInterface::SetupResolvedMethod(callee);
2541         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2542         RuntimeInterface::SetupResolvedMethod(nullptr);
2543 
2544         ASSERT_EQ(f->GetAccAsVReg().Get(), 12L);
2545     }
2546 }
2547 
TEST_F(InterpreterTest,TestVirtualCallsExceptions)2548 TEST_F(InterpreterTest, TestVirtualCallsExceptions)
2549 {
2550     auto testNullReferenceException = [](BytecodeEmitter &emitter) {
2551         std::vector<uint8_t> bytecode;
2552         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2553 
2554         RuntimeInterface::SetCatchBlockPcOffset(bytecode.size());
2555         emitter.ReturnObj();
2556         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2557 
2558         auto f = CreateFrame(16U, nullptr, nullptr);
2559         InitializeFrame(f.get());
2560         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2561         auto methodData = CreateMethod(cls, f.get(), bytecode);
2562         auto method = std::move(methodData.first);
2563         f->SetMethod(method.get());
2564 
2565         auto source = R"(
2566             .record A {}
2567             .record B <extends=A> {}
2568 
2569             .function i32 A.foo(A a0) {
2570                 ldai 0
2571                 return
2572             }
2573 
2574             .function i32 B.foo(B a0) {
2575                 ldai 1
2576                 return
2577             }
2578         )";
2579 
2580         bool failed = false;
2581         auto classLinker = AddProgramToClassLinker(source, failed);
2582         ASSERT_FALSE(failed);
2583 
2584         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2585         auto *classA = ext->GetClass(GetClassDescriptor("A"));
2586         auto *callee = classA->GetMethods().data();
2587 
2588         auto frameHandler = StaticFrameHandler(f.get());
2589         frameHandler.GetVReg(0).SetReference(nullptr);
2590 
2591         RuntimeInterface::SetupResolvedMethod(callee);
2592         RuntimeInterface::SetNullPointerExceptionData({true});
2593 
2594         auto *thread = ManagedThread::GetCurrent();
2595         auto *exception = CreateException(thread);
2596         thread->SetException(exception);
2597 
2598         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2599 
2600         RuntimeInterface::SetNullPointerExceptionData({false});
2601         RuntimeInterface::SetupResolvedMethod(nullptr);
2602 
2603         ASSERT_FALSE(thread->HasPendingException());
2604         ASSERT_EQ(f->GetAccAsVReg().GetReference(), exception);
2605     };
2606 
2607     {
2608         auto emitter = BytecodeEmitter {};
2609         emitter.CallVirtShort(0, 0, RuntimeInterface::METHOD_ID.AsIndex());
2610         emitter.Return();
2611         testNullReferenceException(emitter);
2612     }
2613 
2614     {
2615         auto emitter = BytecodeEmitter {};
2616         emitter.CallVirt(0, 0, 0, 0, RuntimeInterface::METHOD_ID.AsIndex());
2617         emitter.Return();
2618         testNullReferenceException(emitter);
2619     }
2620 
2621     {
2622         auto emitter = BytecodeEmitter {};
2623         emitter.CallVirtRange(0, RuntimeInterface::METHOD_ID.AsIndex());
2624         emitter.Return();
2625         testNullReferenceException(emitter);
2626     }
2627 }
2628 
MakeShorty(size_t numArgs,std::vector<uint16_t> * buf)2629 static void MakeShorty(size_t numArgs, std::vector<uint16_t> *buf)
2630 {
2631     static constexpr auto I64 = static_cast<uint8_t>(panda_file::Type::TypeId::I64);
2632     static constexpr size_t ELEM_SIZE = 4;
2633     static constexpr size_t ELEM_COUNT = std::numeric_limits<uint16_t>::digits / ELEM_SIZE;
2634 
2635     uint16_t val = 0;
2636     uint32_t count = 1;
2637     ++numArgs;  // consider the return value
2638     while (numArgs > 0) {
2639         if (count == ELEM_COUNT) {
2640             buf->push_back(val);
2641             val = 0;
2642             count = 0;
2643         }
2644         // NOLINTNEXTLINE(hicpp-signed-bitwise)
2645         val |= (I64 << (ELEM_SIZE * count));
2646         ++count;
2647         --numArgs;
2648     }
2649     if (count == ELEM_COUNT) {
2650         buf->push_back(val);
2651         val = 0;
2652     }
2653     buf->push_back(val);
2654 }
2655 
2656 template <bool IS_DYNAMIC = false>
CreateResolvedMethod(Class * klass,size_t vregNum,const std::vector<int64_t> & args,std::vector<uint8_t> * bytecode,std::vector<uint16_t> * shortyBuf)2657 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateResolvedMethod(
2658     Class *klass, size_t vregNum, const std::vector<int64_t> &args, std::vector<uint8_t> *bytecode,
2659     std::vector<uint16_t> *shortyBuf)
2660 {
2661     BytecodeEmitter emitter;
2662     Label label = emitter.CreateLabel();
2663 
2664     size_t startIdx = 0;
2665     if constexpr (IS_DYNAMIC) {
2666         ++startIdx;  // skip function object
2667     }
2668     for (size_t i = startIdx; i < args.size(); i++) {
2669         emitter.LdaiWide(args[i]);
2670         emitter.Jne(vregNum + i, label);
2671     }
2672 
2673     emitter.LdaiWide(1);
2674     emitter.ReturnWide();
2675     emitter.Bind(label);
2676     emitter.LdaiWide(0);
2677     emitter.ReturnWide();
2678 
2679     [[maybe_unused]] auto res = emitter.Build(&*bytecode);
2680 
2681     ASSERT(res == BytecodeEmitter::ErrorCode::SUCCESS);
2682 
2683     MakeShorty(args.size(), shortyBuf);
2684 
2685     return CreateMethod(klass, 0, args.size(), vregNum, shortyBuf->data(), *bytecode);
2686 }
2687 
EntryPoint(CompilerInterface::ExecState * state)2688 CompilerInterface::ReturnReason EntryPoint(CompilerInterface::ExecState *state)
2689 {
2690     ASSERT(state->GetNumArgs() == 2U);
2691 
2692     ASSERT(state->GetFrame()->GetSize() == 16U);
2693 
2694     [[maybe_unused]] auto frameHandler = StaticFrameHandler(state->GetFrame());
2695     ASSERT(frameHandler.GetVReg(1U).GetLong() == 1L);
2696     ASSERT(frameHandler.GetVReg(3U).GetLong() == 2L);
2697 
2698     ASSERT(frameHandler.GetVReg(2U).GetLong() == 3L);
2699     ASSERT(frameHandler.GetVReg(4U).GetLong() == 4L);
2700 
2701     int64_t v = 100L + state->GetArg(0).GetLong() + state->GetArg(1).GetLong();
2702     interpreter::VRegister acc;
2703     acc.Set(0);
2704     acc.Set(v);
2705     state->SetAcc(acc);
2706     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2707     state->SetPc(state->GetPc() + 1);
2708 
2709     return CompilerInterface::ReturnReason::RET_OK;
2710 }
2711 
2712 // NOTE (Baladurin, Udovichenko) change for new interop
TEST_F(InterpreterTest,DISABLED_TestCallNative)2713 TEST_F(InterpreterTest, DISABLED_TestCallNative)
2714 {
2715     size_t vregNum = 10U;
2716 
2717     BytecodeEmitter emitter;
2718 
2719     // first call hotness_counter is 0
2720     emitter.CallShort(1U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2721     emitter.StaWide(5U);
2722     // second call hotness counter is 1 -> native call
2723     emitter.CallShort(5U, 6U, RuntimeInterface::METHOD_ID.AsIndex());
2724     // native call skips this return
2725     emitter.ReturnWide();
2726     emitter.Addi(1);
2727     emitter.ReturnWide();
2728 
2729     std::vector<uint8_t> bytecode;
2730     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2731 
2732     auto f = CreateFrame(16U, nullptr, nullptr);
2733     InitializeFrame(f.get());
2734 
2735     auto frameHandler = StaticFrameHandler(f.get());
2736     std::vector<int64_t> args1 = {1L, 2L};
2737     frameHandler.GetVReg(1U).SetPrimitive(args1[0]);
2738     frameHandler.GetVReg(3U).SetPrimitive(args1[1]);
2739 
2740     std::vector<int64_t> args2 = {3L, 4L};
2741     frameHandler.GetVReg(2U).SetPrimitive(args2[0]);
2742     frameHandler.GetVReg(4U).SetPrimitive(args2[1]);
2743 
2744     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2745     auto methodData = CreateMethod(cls, f.get(), bytecode);
2746     auto method = std::move(methodData.first);
2747     f->SetMethod(method.get());
2748 
2749     std::vector<uint16_t> shortyBuf;
2750     std::vector<uint8_t> methodBytecode;
2751     auto resolvedMethodData = CreateResolvedMethod(cls, vregNum, args1, &methodBytecode, &shortyBuf);
2752     auto resolvedMethod = std::move(resolvedMethodData.first);
2753 
2754     RuntimeInterface::SetCompilerHotnessThreshold(1);
2755 
2756     RuntimeInterface::SetupNativeEntryPoint(reinterpret_cast<const void *>(EntryPoint));
2757 
2758     RuntimeInterface::SetupResolvedMethod(resolvedMethod.get());
2759 
2760     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2761 
2762     RuntimeInterface::SetupResolvedMethod(nullptr);
2763 
2764     EXPECT_EQ(f->GetAccAsVReg().GetLong(), 102L);
2765 }
2766 
2767 class InterpreterWithSTWTest : public testing::Test {
2768 public:
InterpreterWithSTWTest()2769     InterpreterWithSTWTest()
2770     {
2771         RuntimeOptions options;
2772         options.SetShouldLoadBootPandaFiles(false);
2773         options.SetShouldInitializeIntrinsics(false);
2774         options.SetRunGcInPlace(true);
2775         options.SetGcTriggerType("debug-never");
2776         options.SetVerifyCallStack(false);
2777         options.SetGcType("stw");
2778         Runtime::Create(options);
2779         thread_ = panda::MTManagedThread::GetCurrent();
2780         thread_->ManagedCodeBegin();
2781     }
2782 
~InterpreterWithSTWTest()2783     ~InterpreterWithSTWTest() override
2784     {
2785         thread_->ManagedCodeEnd();
2786         Runtime::Destroy();
2787     }
2788 
2789     NO_COPY_SEMANTIC(InterpreterWithSTWTest);
2790     NO_MOVE_SEMANTIC(InterpreterWithSTWTest);
2791 
2792 private:
2793     panda::MTManagedThread *thread_;
2794 };
2795 
CreateFrameWithSize(uint32_t size,uint32_t nregs,Method * method,Frame * prev,ManagedThread * current)2796 Frame *CreateFrameWithSize(uint32_t size, uint32_t nregs, Method *method, Frame *prev, ManagedThread *current)
2797 {
2798     uint32_t extSz = CORE_EXT_FRAME_DATA_SIZE;
2799     size_t allocSz = Frame::GetAllocSize(size, extSz);
2800     size_t mirrorOffset = extSz + sizeof(Frame) + sizeof(interpreter::VRegister) * nregs;
2801     void *frame = current->GetStackFrameAllocator()->Alloc<false>(allocSz);
2802     auto mirrorPartBytes = reinterpret_cast<uint64_t *>(ToVoidPtr(ToUintPtr(frame) + mirrorOffset));
2803     for (size_t i = 0; i < nregs; i++) {
2804         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2805         mirrorPartBytes[i] = 0x00;
2806     }
2807     return new (Frame::FromExt(frame, extSz)) Frame(frame, method, prev, nregs);
2808 }
2809 
2810 #if defined(PANDA_TARGET_ARM32) && defined(NDEBUG)
DEATH_TEST_F(InterpreterWithSTWTest,DISABLED_TestCreateFrame)2811 DEATH_TEST_F(InterpreterWithSTWTest, DISABLED_TestCreateFrame)
2812 #else
2813 DEATH_TEST_F(InterpreterWithSTWTest, TestCreateFrame)
2814 #endif
2815 {
2816     testing::FLAGS_gtest_death_test_style = "threadsafe";
2817 
2818     size_t vregNum1 = 16U;
2819 
2820     BytecodeEmitter emitter1;
2821 
2822     emitter1.CallShort(1U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2823     emitter1.ReturnWide();
2824 
2825     std::vector<uint8_t> bytecode1;
2826     ASSERT_EQ(emitter1.Build(&bytecode1), BytecodeEmitter::ErrorCode::SUCCESS);
2827 
2828     auto f1 = CreateFrame(vregNum1, nullptr, nullptr);
2829 
2830     auto cls1 = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2831     auto methodData1 = CreateMethod(cls1, f1.get(), bytecode1);
2832     auto method1 = std::move(methodData1.first);
2833     f1->SetMethod(method1.get());
2834 
2835     auto frameHandler1 = StaticFrameHandler(f1.get());
2836     frameHandler1.GetVReg(1U).SetPrimitive(1_I);
2837     frameHandler1.GetVReg(3U).SetPrimitive(2_I);
2838 
2839     size_t vregNum2 = 65535;
2840 
2841     BytecodeEmitter emitter2;
2842 
2843     emitter2.LdaObj(1);
2844     emitter2.ReturnObj();
2845 
2846     std::vector<uint8_t> bytecode2;
2847     ASSERT_EQ(emitter2.Build(&bytecode2), BytecodeEmitter::ErrorCode::SUCCESS);
2848 
2849     auto f2 = CreateFrameWithSize(Frame::GetActualSize<false>(vregNum2), vregNum2, method1.get(), f1.get(),
2850                                   ManagedThread::GetCurrent());
2851 
2852     auto cls2 = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2853     auto methodData2 = CreateMethod(cls2, f2, bytecode2);
2854     auto method2 = std::move(methodData2.first);
2855     f2->SetMethod(method2.get());
2856     ManagedThread::GetCurrent()->SetCurrentFrame(f2);
2857 
2858     auto frameHandler2 = StaticFrameHandler(f2);
2859     for (size_t i = 0; i < vregNum2; i++) {
2860         frameHandler2.GetVReg(i).SetReference(panda::mem::AllocNonMovableObject());
2861     }
2862 
2863     size_t extSz = CORE_EXT_FRAME_DATA_SIZE;
2864     size_t allocSz = sizeof(interpreter::VRegister) * vregNum2;
2865     memset_s(ToVoidPtr(ToUintPtr(f2) + extSz + sizeof(Frame)), allocSz, 0xff, allocSz);
2866 
2867     panda::mem::GC *gc = Runtime::GetCurrent()->GetPandaVM()->GetGC();
2868 
2869     {
2870         ScopedNativeCodeThread sn(ManagedThread::GetCurrent());
2871         GCTask task(GCTaskCause::OOM_CAUSE);
2872         ASSERT_DEATH(task.Run(*gc), "");
2873     }
2874 
2875     panda::FreeFrameInterp(f2, ManagedThread::GetCurrent());
2876 
2877     f2 = CreateFrameWithSize(Frame::GetActualSize<false>(vregNum2), vregNum2, method1.get(), f1.get(),
2878                              ManagedThread::GetCurrent());
2879 
2880     {
2881         ScopedNativeCodeThread sn(ManagedThread::GetCurrent());
2882         GCTask task(GCTaskCause::OOM_CAUSE);
2883         task.Run(*gc);
2884     }
2885 
2886     panda::FreeFrameInterp(f2, ManagedThread::GetCurrent());
2887 }
2888 
2889 }  // namespace panda::interpreter::test
2890 
2891 // NOLINTEND(readability-magic-numbers)
2892