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