• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /**
3  * Copyright (c) 2021-2024 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()->IsJitEnabled() ? 1499U : std::numeric_limits<int16_t>::max() - 1)
596                       : (Runtime::GetCurrent()->IsJitEnabled() ? 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()->IsJitEnabled() ? 1499U : std::numeric_limits<int16_t>::max() - 1)
676                       : (Runtime::GetCurrent()->IsJitEnabled() ? 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 
1700     auto classPf = pandasm::AsmEmitter::Emit(p.Parse(source).Value());
1701 
1702     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1703     ASSERT_NE(classLinker, nullptr);
1704 
1705     classLinker->AddPandaFile(std::move(classPf));
1706 
1707     PandaString descriptor;
1708 
1709     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1710     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1711     ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), objectClass));
1712     ObjectHeader *obj = nullptr;
1713 
1714     auto frameHandler = StaticFrameHandler(f.get());
1715     if (!isStatic) {
1716         obj = AllocObject(objectClass);
1717         frameHandler.GetVReg(0).SetReference(obj);
1718     }
1719 
1720     Span<Field> fields = isStatic ? objectClass->GetStaticFields() : objectClass->GetInstanceFields();
1721     for (Field &field : fields) {
1722         std::ostringstream ss;
1723         ss << "Test field " << reinterpret_cast<const char *>(field.GetName().data);
1724 
1725         int64_t value = 0;
1726         SetPrimitive(frameHandler, field, value);
1727 
1728         RuntimeInterface::SetupResolvedField(&field);
1729 
1730         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1731 
1732         RuntimeInterface::SetupResolvedField(nullptr);
1733 
1734         CheckValues(field, f.get(), value, ss);
1735 
1736         EXPECT_EQ(frameHandler.GetVReg(1).GetLong(), 0) << ss.str();
1737     }
1738 }
1739 
GetSourceForObjectFieldTest(bool isStatic)1740 static std::string GetSourceForObjectFieldTest(bool isStatic)
1741 {
1742     std::string source;
1743 
1744     if (isStatic) {
1745         source = R"(
1746             .record R {
1747                 R sf_ref <static>
1748             }
1749         )";
1750     } else {
1751         source = R"(
1752             .record R {
1753                 R sf_ref
1754             }
1755         )";
1756     }
1757 
1758     return source;
1759 }
1760 
PrepareEmitter(BytecodeEmitter & emitter,bool isStatic)1761 static void PrepareEmitter(BytecodeEmitter &emitter, bool isStatic)
1762 {
1763     if (isStatic) {
1764         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1765         emitter.StaObj(1U);
1766         emitter.LdaObj(2U);
1767         emitter.StstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1768         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1769     } else {
1770         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1771         emitter.StaObj(1U);
1772         emitter.LdaObj(2U);
1773         emitter.StobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1774         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1775     }
1776     emitter.ReturnObj();
1777 }
1778 
TestLoadStoreObjectField(bool isStatic)1779 void TestLoadStoreObjectField(bool isStatic)
1780 {
1781     BytecodeEmitter emitter;
1782 
1783     std::ostringstream ss;
1784     ss << "Test load/store ";
1785     if (isStatic) {
1786         ss << "static ";
1787     }
1788     ss << "object field";
1789 
1790     PrepareEmitter(emitter, isStatic);
1791 
1792     std::vector<uint8_t> bytecode;
1793     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
1794 
1795     auto f = CreateFrame(16U, nullptr, nullptr);
1796     InitializeFrame(f.get());
1797 
1798     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1799     auto methodData = CreateMethod(cls, f.get(), bytecode);
1800     auto method = std::move(methodData.first);
1801     f->SetMethod(method.get());
1802 
1803     pandasm::Parser p;
1804     std::string source = GetSourceForObjectFieldTest(isStatic);
1805 
1806     auto res = p.Parse(source);
1807     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1808 
1809     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1810     ASSERT_NE(classLinker, nullptr) << ss.str();
1811 
1812     classLinker->AddPandaFile(std::move(classPf));
1813 
1814     PandaString descriptor;
1815 
1816     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1817     Class *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1818     ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), objectClass)) << ss.str();
1819 
1820     ObjectHeader *obj = nullptr;
1821 
1822     auto frameHandler = StaticFrameHandler(f.get());
1823     if (!isStatic) {
1824         obj = AllocObject(objectClass);
1825         frameHandler.GetVReg(0).SetReference(obj);
1826     }
1827 
1828     Span<Field> fields = isStatic ? objectClass->GetStaticFields() : objectClass->GetInstanceFields();
1829     Field *field = &fields[0];
1830     ObjectHeader *refValue = ark::mem::AllocateNullifiedPayloadString(1);
1831 
1832     frameHandler.GetVReg(2U).SetReference(refValue);
1833 
1834     RuntimeInterface::SetupResolvedField(field);
1835 
1836     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1837 
1838     RuntimeInterface::SetupResolvedField(nullptr);
1839 
1840     EXPECT_EQ(f->GetAccAsVReg().GetReference(), refValue) << ss.str();
1841     EXPECT_EQ(frameHandler.GetVReg(1).GetReference(), nullptr) << ss.str();
1842 }
1843 
TEST_F(InterpreterTest,TestLoadStoreField)1844 TEST_F(InterpreterTest, TestLoadStoreField)
1845 {
1846     TestLoadStoreField(false);
1847     TestLoadStoreObjectField(false);
1848 }
1849 
TEST_F(InterpreterTest,TestLoadStoreStaticField)1850 TEST_F(InterpreterTest, TestLoadStoreStaticField)
1851 {
1852     TestLoadStoreField(true);
1853     TestLoadStoreObjectField(true);
1854 }
1855 
TEST_F(InterpreterTest,TestReturn)1856 TEST_F(InterpreterTest, TestReturn)
1857 {
1858     int64_t value = 0xaabbccdd11223344;
1859 
1860     BytecodeEmitter emitter;
1861 
1862     emitter.Return();
1863 
1864     std::vector<uint8_t> bytecode;
1865     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1866 
1867     auto f = CreateFrame(16U, nullptr, nullptr);
1868     InitializeFrame(f.get());
1869 
1870     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1871     auto methodData = CreateMethod(cls, f.get(), bytecode);
1872     auto method = std::move(methodData.first);
1873     f->SetMethod(method.get());
1874 
1875     f->GetAccAsVReg().SetPrimitive(value);
1876 
1877     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1878 
1879     EXPECT_EQ(f->GetAccAsVReg().Get(), static_cast<int32_t>(value));
1880     EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1881 }
1882 
TEST_F(InterpreterTest,TestReturnWide)1883 TEST_F(InterpreterTest, TestReturnWide)
1884 {
1885     int64_t value = 0xaabbccdd11223344;
1886 
1887     BytecodeEmitter emitter;
1888 
1889     emitter.ReturnWide();
1890 
1891     std::vector<uint8_t> bytecode;
1892     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1893 
1894     auto f = CreateFrame(16U, nullptr, nullptr);
1895     InitializeFrame(f.get());
1896 
1897     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1898     auto methodData = CreateMethod(cls, f.get(), bytecode);
1899     auto method = std::move(methodData.first);
1900     f->SetMethod(method.get());
1901 
1902     f->GetAccAsVReg().SetPrimitive(value);
1903 
1904     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1905 
1906     EXPECT_EQ(f->GetAccAsVReg().GetLong(), value);
1907     EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1908 }
1909 
TEST_F(InterpreterTest,TestReturnObj)1910 TEST_F(InterpreterTest, TestReturnObj)
1911 {
1912     BytecodeEmitter emitter;
1913 
1914     emitter.ReturnObj();
1915 
1916     std::vector<uint8_t> bytecode;
1917     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1918 
1919     auto f = CreateFrame(16U, nullptr, nullptr);
1920     InitializeFrame(f.get());
1921 
1922     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1923     auto methodData = CreateMethod(cls, f.get(), bytecode);
1924     auto method = std::move(methodData.first);
1925     f->SetMethod(method.get());
1926 
1927     ObjectHeader *obj = ark::mem::AllocateNullifiedPayloadString(1);
1928     f->GetAccAsVReg().SetReference(obj);
1929 
1930     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1931 
1932     EXPECT_EQ(f->GetAccAsVReg().GetReference(), obj);
1933     EXPECT_TRUE(f->GetAccAsVReg().HasObject());
1934 }
1935 
AddProgramToClassLinker(std::string_view source,bool & failed)1936 auto AddProgramToClassLinker(std::string_view source, bool &failed)
1937 {
1938     pandasm::Parser p;
1939     auto res = p.Parse(source.data());
1940     auto classPf = pandasm::AsmEmitter::Emit(res.Value());
1941 
1942     auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
1943     if (classLinker == nullptr) {
1944         failed = true;
1945         return classLinker;
1946     }
1947 
1948     classLinker->AddPandaFile(std::move(classPf));
1949     return classLinker;
1950 }
1951 
InitObjectClass(ClassLinker * classLinker,const uint8_t * descriptor,bool & failed)1952 auto InitObjectClass(ClassLinker *classLinker, const uint8_t *descriptor, bool &failed)
1953 {
1954     auto *thread = ManagedThread::GetCurrent();
1955     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1956     auto *objectClass = ext->GetClass(descriptor);
1957     failed = !classLinker->InitializeClass(thread, objectClass);
1958     return objectClass;
1959 }
1960 
GetClassDescriptor(const char * name)1961 auto GetClassDescriptor(const char *name)
1962 {
1963     static PandaString descriptor;
1964     descriptor.clear();
1965     return ClassHelper::GetDescriptor(utf::CStringAsMutf8(name), &descriptor);
1966 }
1967 
GetArrayDescriptor(const char * name,int rank)1968 auto GetArrayDescriptor(const char *name, int rank)
1969 {
1970     static PandaString descriptor;
1971     descriptor.clear();
1972     return ClassHelper::GetArrayDescriptor(utf::CStringAsMutf8(name), rank, &descriptor);
1973 }
1974 
1975 // CC-OFFNXT(G.FUN.01, huge_method) solid logic
TEST_F(InterpreterTest,TestIsInstance)1976 TEST_F(InterpreterTest, TestIsInstance)
1977 {
1978     auto emitterFactory = []() {
1979         auto emitter = std::make_unique<BytecodeEmitter>();
1980         emitter->Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
1981         emitter->Return();
1982         return emitter;
1983     };
1984     auto source = R"(
1985         .record R {}
1986     )";
1987 
1988     auto emitter = emitterFactory();
1989     std::vector<uint8_t> bytecode;
1990     ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1991     auto f = CreateFrame(16U, nullptr, nullptr);
1992     InitializeFrame(f.get());
1993     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1994     auto methodData = CreateMethod(cls, f.get(), bytecode);
1995     auto method = std::move(methodData.first);
1996     f->SetMethod(method.get());
1997     bool failed = false;
1998     auto classLinker = AddProgramToClassLinker(source, failed);
1999     ASSERT_FALSE(failed);
2000 
2001     {
2002         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
2003         ASSERT_FALSE(failed);
2004 
2005         f->GetAccAsVReg().SetReference(nullptr);
2006 
2007         RuntimeInterface::SetupResolvedClass(objectClass);
2008         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2009         RuntimeInterface::SetupResolvedClass(nullptr);
2010         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2011     }
2012 
2013     {
2014         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
2015         ASSERT_FALSE(failed);
2016 
2017         auto *obj = AllocObject(objectClass);
2018         f->GetAccAsVReg().SetReference(obj);
2019 
2020         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2021         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2022         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
2023         RuntimeInterface::SetupResolvedClass(dstClass);
2024 
2025         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2026         RuntimeInterface::SetupResolvedClass(nullptr);
2027         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2028     }
2029 
2030     {
2031         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
2032         ASSERT_FALSE(failed);
2033 
2034         f->GetAccAsVReg().SetReference(nullptr);
2035 
2036         RuntimeInterface::SetupResolvedClass(objectClass);
2037         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2038         RuntimeInterface::SetupResolvedClass(nullptr);
2039         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2040     }
2041 
2042     {
2043         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
2044         ASSERT_FALSE(failed);
2045 
2046         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2047         f->GetAccAsVReg().SetReference(obj);
2048 
2049         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2050         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2051         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
2052 
2053         RuntimeInterface::SetupResolvedClass(dstClass);
2054         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2055         RuntimeInterface::SetupResolvedClass(nullptr);
2056         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2057     }
2058 }
2059 
CreateException(ManagedThread * thread)2060 static ObjectHeader *CreateException(ManagedThread *thread)
2061 {
2062     auto classLinker = CreateClassLinker(thread);
2063     auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2064     auto *cls = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2065     auto *exception = ObjectHeader::Create(cls);
2066     return exception;
2067 }
2068 
2069 namespace {
EmitterFactoryCast()2070 std::unique_ptr<BytecodeEmitter> EmitterFactoryCast()
2071 {
2072     auto emitter = std::make_unique<BytecodeEmitter>();
2073     emitter->Checkcast(RuntimeInterface::TYPE_ID.AsIndex());
2074     emitter->ReturnVoid();
2075     return emitter;
2076 }
2077 
TEST_F(InterpreterTest,TestCheckCastEmpty)2078 TEST_F(InterpreterTest, TestCheckCastEmpty)
2079 {
2080     auto emitter = EmitterFactoryCast();
2081     auto source = R"(.record R {})";
2082     std::vector<uint8_t> bytecode;
2083     ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2084 
2085     auto f = CreateFrame(16U, nullptr, nullptr);
2086     InitializeFrame(f.get());
2087     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2088     auto methodData = CreateMethod(cls, f.get(), bytecode);
2089     auto method = std::move(methodData.first);
2090     f->SetMethod(method.get());
2091 
2092     bool failed = false;
2093     auto classLinker = AddProgramToClassLinker(source, failed);
2094     ASSERT_FALSE(failed);
2095 
2096     {
2097         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("R"), failed);
2098         ASSERT_FALSE(failed);
2099 
2100         f->GetAccAsVReg().SetReference(nullptr);
2101 
2102         RuntimeInterface::SetupResolvedClass(objectClass);
2103         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2104         RuntimeInterface::SetupResolvedClass(nullptr);
2105     }
2106     {
2107         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("R", 2_I), failed);
2108         ASSERT_FALSE(failed);
2109 
2110         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2111         f->GetAccAsVReg().SetReference(obj);
2112 
2113         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2114         auto *dstClass = classLinker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
2115         ASSERT_TRUE(classLinker->InitializeClass(ManagedThread::GetCurrent(), dstClass));
2116 
2117         RuntimeInterface::SetupResolvedClass(dstClass);
2118         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2119         RuntimeInterface::SetupResolvedClass(nullptr);
2120     }
2121 }
2122 
TEST_F(InterpreterTest,TestCheckCastInheritance)2123 TEST_F(InterpreterTest, TestCheckCastInheritance)
2124 {
2125     auto emitter = EmitterFactoryCast();
2126     auto source = R"(
2127         .record A {}
2128         .record B <extends=A> {}
2129         .record C <extends=B> {}
2130     )";
2131     std::vector<uint8_t> bytecode;
2132     ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2133 
2134     auto f = CreateFrame(16U, nullptr, nullptr);
2135     InitializeFrame(f.get());
2136     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2137     auto methodData = CreateMethod(cls, f.get(), bytecode);
2138     auto method = std::move(methodData.first);
2139     f->SetMethod(method.get());
2140 
2141     bool failed = false;
2142     auto classLinker = AddProgramToClassLinker(source, failed);
2143     ASSERT_FALSE(failed);
2144 
2145     {
2146         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("C"), failed);
2147         ASSERT_FALSE(failed);
2148 
2149         auto *obj = AllocObject(objectClass);
2150         f->GetAccAsVReg().SetReference(obj);
2151 
2152         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2153         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("A")));
2154         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2155         RuntimeInterface::SetupResolvedClass(nullptr);
2156     }
2157     {
2158         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("C", 2_I), failed);
2159         ASSERT_FALSE(failed);
2160 
2161         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2162         f->GetAccAsVReg().SetReference(obj);
2163 
2164         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2165         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("A", 2_I)));
2166         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2167         RuntimeInterface::SetupResolvedClass(nullptr);
2168     }
2169 }
2170 
TEST_F(InterpreterTest,TestCheckCast)2171 TEST_F(InterpreterTest, TestCheckCast)
2172 {
2173     {
2174         BytecodeEmitter emitter;
2175         emitter.Checkcast(RuntimeInterface::TYPE_ID.AsIndex());
2176         emitter.ReturnVoid();
2177 
2178         std::vector<uint8_t> bytecode;
2179         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2180 
2181         RuntimeInterface::SetCatchBlockPcOffset(bytecode.size());
2182 
2183         emitter.ReturnObj();
2184 
2185         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2186 
2187         auto f = CreateFrame(16U, nullptr, nullptr);
2188         InitializeFrame(f.get());
2189         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2190         auto methodData = CreateMethod(cls, f.get(), bytecode);
2191         auto method = std::move(methodData.first);
2192         f->SetMethod(method.get());
2193 
2194         pandasm::Parser p;
2195         auto source = R"(
2196             .record A {}
2197             .record B <extends=A> {}
2198             .record C <extends=B> {}
2199         )";
2200 
2201         auto res = p.Parse(source);
2202         auto classPf = pandasm::AsmEmitter::Emit(res.Value());
2203 
2204         auto classLinker = CreateClassLinker(ManagedThread::GetCurrent());
2205         ASSERT_NE(classLinker, nullptr);
2206 
2207         classLinker->AddPandaFile(std::move(classPf));
2208 
2209         PandaString descriptor;
2210         auto *thread = ManagedThread::GetCurrent();
2211         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2212         auto *objectClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("A"), &descriptor));
2213         ASSERT_TRUE(classLinker->InitializeClass(thread, objectClass));
2214 
2215         auto *obj = AllocObject(objectClass);
2216 
2217         f->GetAccAsVReg().SetReference(obj);
2218 
2219         auto *dstClass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("C"), &descriptor));
2220         ASSERT_TRUE(classLinker->InitializeClass(thread, dstClass));
2221         RuntimeInterface::SetupResolvedClass(dstClass);
2222 
2223         RuntimeInterface::SetClassCastExceptionData({true, dstClass, objectClass});
2224 
2225         auto *exception = CreateException(thread);
2226         thread->SetException(exception);
2227 
2228         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2229 
2230         RuntimeInterface::SetupResolvedClass(nullptr);
2231 
2232         RuntimeInterface::SetClassCastExceptionData({false, nullptr, nullptr});
2233 
2234         ASSERT_FALSE(thread->HasPendingException());
2235         ASSERT_EQ(f->GetAccAsVReg().GetReference(), exception);
2236     }
2237 }
2238 }  // namespace
2239 
2240 namespace {
2241 
EmitterFactoryIsInstance()2242 std::unique_ptr<BytecodeEmitter> EmitterFactoryIsInstance()
2243 {
2244     auto emitter = std::make_unique<BytecodeEmitter>();
2245     emitter->Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
2246     emitter->Return();
2247     return emitter;
2248 }
2249 
TEST_F(InterpreterTest,TestIsInstanceInheritanceClass)2250 TEST_F(InterpreterTest, TestIsInstanceInheritanceClass)
2251 {
2252     auto emitter = EmitterFactoryIsInstance();
2253     auto source = R"(
2254         .record A {}
2255         .record B <extends=A> {}
2256         .record C <extends=B> {}
2257     )";
2258     std::vector<uint8_t> bytecode;
2259     ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2260 
2261     auto f = CreateFrame(16U, nullptr, nullptr);
2262     InitializeFrame(f.get());
2263     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2264     auto methodData = CreateMethod(cls, f.get(), bytecode);
2265     auto method = std::move(methodData.first);
2266     f->SetMethod(method.get());
2267 
2268     bool failed = false;
2269     auto classLinker = AddProgramToClassLinker(source, failed);
2270     ASSERT_FALSE(failed);
2271 
2272     {
2273         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("C"), failed);
2274         ASSERT_FALSE(failed);
2275 
2276         auto *obj = AllocObject(objectClass);
2277         f->GetAccAsVReg().SetReference(obj);
2278 
2279         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2280         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("A")));
2281         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2282         RuntimeInterface::SetupResolvedClass(nullptr);
2283 
2284         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2285     }
2286     {
2287         auto objectClass = InitObjectClass(classLinker.get(), GetClassDescriptor("A"), failed);
2288         ASSERT_FALSE(failed);
2289 
2290         auto *obj = AllocObject(objectClass);
2291         f->GetAccAsVReg().SetReference(obj);
2292 
2293         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2294         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetClassDescriptor("C")));
2295         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2296         RuntimeInterface::SetupResolvedClass(nullptr);
2297 
2298         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2299     }
2300 }
2301 
TEST_F(InterpreterTest,TestIsInstanceInheritanceArray)2302 TEST_F(InterpreterTest, TestIsInstanceInheritanceArray)
2303 {
2304     auto emitter = EmitterFactoryIsInstance();
2305     auto source = R"(
2306         .record A {}
2307         .record B <extends=A> {}
2308         .record C <extends=B> {}
2309     )";
2310     std::vector<uint8_t> bytecode;
2311     ASSERT_EQ(emitter->Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2312 
2313     auto f = CreateFrame(16U, nullptr, nullptr);
2314     InitializeFrame(f.get());
2315     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2316     auto methodData = CreateMethod(cls, f.get(), bytecode);
2317     auto method = std::move(methodData.first);
2318     f->SetMethod(method.get());
2319 
2320     bool failed = false;
2321     auto classLinker = AddProgramToClassLinker(source, failed);
2322     ASSERT_FALSE(failed);
2323     {
2324         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("C", 2_I), failed);
2325         ASSERT_FALSE(failed);
2326 
2327         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2328         f->GetAccAsVReg().SetReference(obj);
2329 
2330         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2331         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("A", 2_I)));
2332         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2333         RuntimeInterface::SetupResolvedClass(nullptr);
2334 
2335         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
2336     }
2337     {
2338         auto objectClass = InitObjectClass(classLinker.get(), GetArrayDescriptor("A", 2_I), failed);
2339         ASSERT_FALSE(failed);
2340 
2341         auto *obj = AllocArray(objectClass, sizeof(uint8_t), 0);
2342         f->GetAccAsVReg().SetReference(obj);
2343 
2344         auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
2345         RuntimeInterface::SetupResolvedClass(classLinker->GetExtension(ctx)->GetClass(GetArrayDescriptor("C", 2_I)));
2346         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2347         RuntimeInterface::SetupResolvedClass(nullptr);
2348 
2349         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
2350     }
2351 }
2352 }  // namespace
2353 
TEST_F(InterpreterTest,TestVirtual1Call)2354 TEST_F(InterpreterTest, TestVirtual1Call)
2355 {
2356     auto emitter = BytecodeEmitter {};
2357     emitter.CallVirtShort(0, 1, RuntimeInterface::METHOD_ID.AsIndex());
2358     emitter.Return();
2359     std::vector<uint8_t> bytecode;
2360     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2361 
2362     auto f = CreateFrame(16U, nullptr, nullptr);
2363     InitializeFrame(f.get());
2364     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2365     auto methodData = CreateMethod(cls, f.get(), bytecode);
2366     auto method = std::move(methodData.first);
2367     f->SetMethod(method.get());
2368 
2369     auto source = R"(
2370         .record A {}
2371         .record B <extends=A> {}
2372 
2373         .function i32 A.foo(A a0, i32 a1) {
2374             lda a1
2375             addi 1
2376             return
2377         }
2378 
2379         .function i32 B.foo(B a0, i32 a1) {
2380             lda a1
2381             addi 2
2382             return
2383         }
2384     )";
2385 
2386     bool failed = false;
2387     auto classLinker = AddProgramToClassLinker(source, failed);
2388     ASSERT_FALSE(failed);
2389 
2390     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2391     auto *classA = ext->GetClass(GetClassDescriptor("A"));
2392     auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2393     auto *callee = classA->GetMethods().data();
2394     auto *obj = AllocObject(objectClass);
2395 
2396     auto frameHandler = StaticFrameHandler(f.get());
2397     frameHandler.GetVReg(0).SetReference(obj);
2398     frameHandler.GetVReg(1).Set(1);
2399 
2400     RuntimeInterface::SetupResolvedMethod(callee);
2401     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2402     RuntimeInterface::SetupResolvedMethod(nullptr);
2403 
2404     ASSERT_EQ(f->GetAccAsVReg().Get(), 3L);
2405 }
2406 
TEST_F(InterpreterTest,TestVirtual3Call)2407 TEST_F(InterpreterTest, TestVirtual3Call)
2408 {
2409     auto emitter = BytecodeEmitter {};
2410     emitter.CallVirt(0U, 1U, 2U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2411     emitter.Return();
2412     std::vector<uint8_t> bytecode;
2413     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2414 
2415     auto f = CreateFrame(16U, nullptr, nullptr);
2416     InitializeFrame(f.get());
2417     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2418     auto methodData = CreateMethod(cls, f.get(), bytecode);
2419     auto method = std::move(methodData.first);
2420     f->SetMethod(method.get());
2421 
2422     auto source = R"(
2423         .record A {}
2424         .record B <extends=A> {}
2425 
2426         .function i32 A.foo(A a0, i32 a1, i32 a2, i32 a3) {
2427             lda a1
2428             addi 1
2429             return
2430         }
2431 
2432         .function i32 B.foo(B a0, i32 a1, i32 a2, i32 a3) {
2433             lda a1
2434             addi 2
2435             add2 a2
2436             add2 a3
2437             return
2438         }
2439     )";
2440 
2441     bool failed = false;
2442     auto classLinker = AddProgramToClassLinker(source, failed);
2443     ASSERT_FALSE(failed);
2444 
2445     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2446     auto *classA = ext->GetClass(GetClassDescriptor("A"));
2447     auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2448     auto *callee = classA->GetMethods().data();
2449     auto *obj = AllocObject(objectClass);
2450 
2451     auto frameHandler = StaticFrameHandler(f.get());
2452     frameHandler.GetVReg(0U).SetReference(obj);
2453     frameHandler.GetVReg(1U).Set(1U);
2454     frameHandler.GetVReg(2U).Set(2U);
2455     frameHandler.GetVReg(3U).Set(3U);
2456 
2457     RuntimeInterface::SetupResolvedMethod(callee);
2458     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2459     RuntimeInterface::SetupResolvedMethod(nullptr);
2460 
2461     ASSERT_EQ(f->GetAccAsVReg().Get(), 8L);
2462 }
2463 
TEST_F(InterpreterTest,TestVirtual4Calls)2464 TEST_F(InterpreterTest, TestVirtual4Calls)
2465 {
2466     {
2467         auto emitter = BytecodeEmitter {};
2468         emitter.CallVirtRange(0, RuntimeInterface::METHOD_ID.AsIndex());
2469         emitter.Return();
2470         std::vector<uint8_t> bytecode;
2471         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2472 
2473         auto f = CreateFrame(16U, nullptr, nullptr);
2474         InitializeFrame(f.get());
2475         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2476         auto methodData = CreateMethod(cls, f.get(), bytecode);
2477         auto method = std::move(methodData.first);
2478         f->SetMethod(method.get());
2479 
2480         auto source = R"(
2481             .record A {}
2482             .record B <extends=A> {}
2483 
2484             .function i32 A.foo(A a0, i32 a1, i32 a2, i32 a3, i32 a4) {
2485                 lda a1
2486                 addi 1
2487                 return
2488             }
2489 
2490             .function i32 B.foo(B a0, i32 a1, i32 a2, i32 a3, i32 a4) {
2491                 lda a1
2492                 addi 2
2493                 add2 a2
2494                 add2 a3
2495                 add2 a4
2496                 return
2497             }
2498         )";
2499 
2500         bool failed = false;
2501         auto classLinker = AddProgramToClassLinker(source, failed);
2502         ASSERT_FALSE(failed);
2503 
2504         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2505         auto *classA = ext->GetClass(GetClassDescriptor("A"));
2506         auto *objectClass = ext->GetClass(GetClassDescriptor("B"));
2507         auto *callee = classA->GetMethods().data();
2508         auto *obj = AllocObject(objectClass);
2509 
2510         auto frameHandler = StaticFrameHandler(f.get());
2511         frameHandler.GetVReg(0U).SetReference(obj);
2512         frameHandler.GetVReg(1U).Set(1U);
2513         frameHandler.GetVReg(2U).Set(2U);
2514         frameHandler.GetVReg(3U).Set(3U);
2515         frameHandler.GetVReg(4U).Set(4U);
2516 
2517         RuntimeInterface::SetupResolvedMethod(callee);
2518         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2519         RuntimeInterface::SetupResolvedMethod(nullptr);
2520 
2521         ASSERT_EQ(f->GetAccAsVReg().Get(), 12L);
2522     }
2523 }
2524 
2525 namespace {
TestNullReferenceException(BytecodeEmitter & emitter)2526 void TestNullReferenceException(BytecodeEmitter &emitter)
2527 {
2528     std::vector<uint8_t> bytecode;
2529     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2530 
2531     RuntimeInterface::SetCatchBlockPcOffset(bytecode.size());
2532     emitter.ReturnObj();
2533     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2534 
2535     auto f = CreateFrame(16U, nullptr, nullptr);
2536     InitializeFrame(f.get());
2537     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2538     auto methodData = CreateMethod(cls, f.get(), bytecode);
2539     auto method = std::move(methodData.first);
2540     f->SetMethod(method.get());
2541 
2542     auto source = R"(
2543         .record A {}
2544         .record B <extends=A> {}
2545 
2546         .function i32 A.foo(A a0) {
2547             ldai 0
2548             return
2549         }
2550 
2551         .function i32 B.foo(B a0) {
2552             ldai 1
2553             return
2554         }
2555     )";
2556 
2557     bool failed = false;
2558     auto classLinker = AddProgramToClassLinker(source, failed);
2559     ASSERT_FALSE(failed);
2560 
2561     auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
2562     auto *classA = ext->GetClass(GetClassDescriptor("A"));
2563     auto *callee = classA->GetMethods().data();
2564 
2565     auto frameHandler = StaticFrameHandler(f.get());
2566     frameHandler.GetVReg(0).SetReference(nullptr);
2567 
2568     RuntimeInterface::SetupResolvedMethod(callee);
2569     RuntimeInterface::SetNullPointerExceptionData({true});
2570 
2571     auto *thread = ManagedThread::GetCurrent();
2572     auto *exception = CreateException(thread);
2573     thread->SetException(exception);
2574 
2575     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2576 
2577     RuntimeInterface::SetNullPointerExceptionData({false});
2578     RuntimeInterface::SetupResolvedMethod(nullptr);
2579 
2580     ASSERT_FALSE(thread->HasPendingException());
2581     ASSERT_EQ(f->GetAccAsVReg().GetReference(), exception);
2582 }
2583 
TEST_F(InterpreterTest,TestVirtualCallsExceptions)2584 TEST_F(InterpreterTest, TestVirtualCallsExceptions)
2585 {
2586     {
2587         auto emitter = BytecodeEmitter {};
2588         emitter.CallVirtShort(0, 0, RuntimeInterface::METHOD_ID.AsIndex());
2589         emitter.Return();
2590         TestNullReferenceException(emitter);
2591     }
2592 
2593     {
2594         auto emitter = BytecodeEmitter {};
2595         emitter.CallVirt(0, 0, 0, 0, RuntimeInterface::METHOD_ID.AsIndex());
2596         emitter.Return();
2597         TestNullReferenceException(emitter);
2598     }
2599 
2600     {
2601         auto emitter = BytecodeEmitter {};
2602         emitter.CallVirtRange(0, RuntimeInterface::METHOD_ID.AsIndex());
2603         emitter.Return();
2604         TestNullReferenceException(emitter);
2605     }
2606 }
2607 }  // namespace
2608 
MakeShorty(size_t numArgs,std::vector<uint16_t> * buf)2609 static void MakeShorty(size_t numArgs, std::vector<uint16_t> *buf)
2610 {
2611     static constexpr auto I64 = static_cast<uint8_t>(panda_file::Type::TypeId::I64);
2612     static constexpr size_t ELEM_SIZE = 4;
2613     static constexpr size_t ELEM_COUNT = std::numeric_limits<uint16_t>::digits / ELEM_SIZE;
2614 
2615     uint16_t val = 0;
2616     uint32_t count = 1;
2617     ++numArgs;  // consider the return value
2618     while (numArgs > 0) {
2619         if (count == ELEM_COUNT) {
2620             buf->push_back(val);
2621             val = 0;
2622             count = 0;
2623         }
2624         // NOLINTNEXTLINE(hicpp-signed-bitwise)
2625         val |= (I64 << (ELEM_SIZE * count));
2626         ++count;
2627         --numArgs;
2628     }
2629     if (count == ELEM_COUNT) {
2630         buf->push_back(val);
2631         val = 0;
2632     }
2633     buf->push_back(val);
2634 }
2635 
2636 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)2637 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateResolvedMethod(
2638     Class *klass, size_t vregNum, const std::vector<int64_t> &args, std::vector<uint8_t> *bytecode,
2639     std::vector<uint16_t> *shortyBuf)
2640 {
2641     BytecodeEmitter emitter;
2642     Label label = emitter.CreateLabel();
2643 
2644     size_t startIdx = 0;
2645     if constexpr (IS_DYNAMIC) {
2646         ++startIdx;  // skip function object
2647     }
2648     for (size_t i = startIdx; i < args.size(); i++) {
2649         emitter.LdaiWide(args[i]);
2650         emitter.Jne(vregNum + i, label);
2651     }
2652 
2653     emitter.LdaiWide(1);
2654     emitter.ReturnWide();
2655     emitter.Bind(label);
2656     emitter.LdaiWide(0);
2657     emitter.ReturnWide();
2658 
2659     [[maybe_unused]] auto res = emitter.Build(&*bytecode);
2660 
2661     ASSERT(res == BytecodeEmitter::ErrorCode::SUCCESS);
2662 
2663     MakeShorty(args.size(), shortyBuf);
2664 
2665     return CreateMethod(klass, 0, args.size(), vregNum, shortyBuf->data(), *bytecode);
2666 }
2667 
EntryPoint(CompilerInterface::ExecState * state)2668 CompilerInterface::ReturnReason EntryPoint(CompilerInterface::ExecState *state)
2669 {
2670     ASSERT(state->GetNumArgs() == 2U);
2671 
2672     ASSERT(state->GetFrame()->GetSize() == 16U);
2673 
2674     [[maybe_unused]] auto frameHandler = StaticFrameHandler(state->GetFrame());
2675     ASSERT(frameHandler.GetVReg(1U).GetLong() == 1L);
2676     ASSERT(frameHandler.GetVReg(3U).GetLong() == 2L);
2677 
2678     ASSERT(frameHandler.GetVReg(2U).GetLong() == 3L);
2679     ASSERT(frameHandler.GetVReg(4U).GetLong() == 4L);
2680 
2681     int64_t v = 100L + state->GetArg(0).GetLong() + state->GetArg(1).GetLong();
2682     interpreter::VRegister acc;
2683     acc.Set(0);
2684     acc.Set(v);
2685     state->SetAcc(acc);
2686     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2687     state->SetPc(state->GetPc() + 1);
2688 
2689     return CompilerInterface::ReturnReason::RET_OK;
2690 }
2691 
2692 // NOTE (Baladurin, Udovichenko) change for new interop
TEST_F(InterpreterTest,DISABLED_TestCallNative)2693 TEST_F(InterpreterTest, DISABLED_TestCallNative)
2694 {
2695     size_t vregNum = 10U;
2696 
2697     BytecodeEmitter emitter;
2698 
2699     // first call hotness_counter is 0
2700     emitter.CallShort(1U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2701     emitter.StaWide(5U);
2702     // second call hotness counter is 1 -> native call
2703     emitter.CallShort(5U, 6U, RuntimeInterface::METHOD_ID.AsIndex());
2704     // native call skips this return
2705     emitter.ReturnWide();
2706     emitter.Addi(1);
2707     emitter.ReturnWide();
2708 
2709     std::vector<uint8_t> bytecode;
2710     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2711 
2712     auto f = CreateFrame(16U, nullptr, nullptr);
2713     InitializeFrame(f.get());
2714 
2715     auto frameHandler = StaticFrameHandler(f.get());
2716     std::vector<int64_t> args1 = {1L, 2L};
2717     frameHandler.GetVReg(1U).SetPrimitive(args1[0]);
2718     frameHandler.GetVReg(3U).SetPrimitive(args1[1]);
2719 
2720     std::vector<int64_t> args2 = {3L, 4L};
2721     frameHandler.GetVReg(2U).SetPrimitive(args2[0]);
2722     frameHandler.GetVReg(4U).SetPrimitive(args2[1]);
2723 
2724     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2725     auto methodData = CreateMethod(cls, f.get(), bytecode);
2726     auto method = std::move(methodData.first);
2727     f->SetMethod(method.get());
2728 
2729     std::vector<uint16_t> shortyBuf;
2730     std::vector<uint8_t> methodBytecode;
2731     auto resolvedMethodData = CreateResolvedMethod(cls, vregNum, args1, &methodBytecode, &shortyBuf);
2732     auto resolvedMethod = std::move(resolvedMethodData.first);
2733 
2734     RuntimeInterface::SetCompilerHotnessThreshold(1);
2735 
2736     RuntimeInterface::SetupNativeEntryPoint(reinterpret_cast<const void *>(EntryPoint));
2737 
2738     RuntimeInterface::SetupResolvedMethod(resolvedMethod.get());
2739 
2740     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2741 
2742     RuntimeInterface::SetupResolvedMethod(nullptr);
2743 
2744     EXPECT_EQ(f->GetAccAsVReg().GetLong(), 102L);
2745 }
2746 
2747 class InterpreterWithSTWTest : public testing::Test {
2748 public:
InterpreterWithSTWTest()2749     InterpreterWithSTWTest()
2750     {
2751         RuntimeOptions options;
2752         options.SetShouldLoadBootPandaFiles(false);
2753         options.SetShouldInitializeIntrinsics(false);
2754         options.SetRunGcInPlace(true);
2755         options.SetGcTriggerType("debug-never");
2756         options.SetVerifyCallStack(false);
2757         options.SetGcType("stw");
2758         Runtime::Create(options);
2759         thread_ = ark::MTManagedThread::GetCurrent();
2760         thread_->ManagedCodeBegin();
2761     }
2762 
~InterpreterWithSTWTest()2763     ~InterpreterWithSTWTest() override
2764     {
2765         thread_->ManagedCodeEnd();
2766         Runtime::Destroy();
2767     }
2768 
2769     NO_COPY_SEMANTIC(InterpreterWithSTWTest);
2770     NO_MOVE_SEMANTIC(InterpreterWithSTWTest);
2771 
2772 private:
2773     ark::MTManagedThread *thread_;
2774 };
2775 
CreateFrameWithSize(uint32_t size,uint32_t nregs,Method * method,Frame * prev,ManagedThread * current)2776 Frame *CreateFrameWithSize(uint32_t size, uint32_t nregs, Method *method, Frame *prev, ManagedThread *current)
2777 {
2778     uint32_t extSz = CORE_EXT_FRAME_DATA_SIZE;
2779     size_t allocSz = Frame::GetAllocSize(size, extSz);
2780     size_t mirrorOffset = extSz + sizeof(Frame) + sizeof(interpreter::VRegister) * nregs;
2781     void *frame = current->GetStackFrameAllocator()->Alloc<false>(allocSz);
2782     auto mirrorPartBytes = reinterpret_cast<uint64_t *>(ToVoidPtr(ToUintPtr(frame) + mirrorOffset));
2783     for (size_t i = 0; i < nregs; i++) {
2784         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2785         mirrorPartBytes[i] = 0x00;
2786     }
2787     return new (Frame::FromExt(frame, extSz)) Frame(frame, method, prev, nregs);
2788 }
2789 
RunTask(ark::mem::GC * gc)2790 static inline void RunTask(ark::mem::GC *gc)
2791 {
2792     ScopedNativeCodeThread sn(ManagedThread::GetCurrent());
2793     GCTask task(GCTaskCause::OOM_CAUSE);
2794     task.Run(*gc);
2795 }
2796 
2797 #if defined(PANDA_TARGET_ARM32) && defined(NDEBUG)
DEATH_TEST_F(InterpreterWithSTWTest,DISABLED_TestCreateFrame)2798 DEATH_TEST_F(InterpreterWithSTWTest, DISABLED_TestCreateFrame)
2799 #else
2800 DEATH_TEST_F(InterpreterWithSTWTest, TestCreateFrame)
2801 #endif
2802 {
2803     testing::FLAGS_gtest_death_test_style = "threadsafe";
2804 
2805     size_t vregNum1 = 16U;
2806 
2807     BytecodeEmitter emitter1;
2808 
2809     emitter1.CallShort(1U, 3U, RuntimeInterface::METHOD_ID.AsIndex());
2810     emitter1.ReturnWide();
2811 
2812     std::vector<uint8_t> bytecode1;
2813     ASSERT_EQ(emitter1.Build(&bytecode1), BytecodeEmitter::ErrorCode::SUCCESS);
2814 
2815     auto f1 = CreateFrame(vregNum1, nullptr, nullptr);
2816 
2817     auto cls1 = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2818     auto methodData1 = CreateMethod(cls1, f1.get(), bytecode1);
2819     auto method1 = std::move(methodData1.first);
2820     f1->SetMethod(method1.get());
2821 
2822     auto frameHandler1 = StaticFrameHandler(f1.get());
2823     frameHandler1.GetVReg(1U).SetPrimitive(1_I);
2824     frameHandler1.GetVReg(3U).SetPrimitive(2_I);
2825 
2826     size_t vregNum2 = 65535;
2827 
2828     BytecodeEmitter emitter2;
2829 
2830     emitter2.LdaObj(1);
2831     emitter2.ReturnObj();
2832 
2833     std::vector<uint8_t> bytecode2;
2834     ASSERT_EQ(emitter2.Build(&bytecode2), BytecodeEmitter::ErrorCode::SUCCESS);
2835 
2836     auto f2 = CreateFrameWithSize(Frame::GetActualSize<false>(vregNum2), vregNum2, method1.get(), f1.get(),
2837                                   ManagedThread::GetCurrent());
2838 
2839     auto cls2 = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2840     auto methodData2 = CreateMethod(cls2, f2, bytecode2);
2841     auto method2 = std::move(methodData2.first);
2842     f2->SetMethod(method2.get());
2843     ManagedThread::GetCurrent()->SetCurrentFrame(f2);
2844 
2845     auto frameHandler2 = StaticFrameHandler(f2);
2846     for (size_t i = 0; i < vregNum2; i++) {
2847         frameHandler2.GetVReg(i).SetReference(ark::mem::AllocNonMovableObject());
2848     }
2849 
2850     size_t allocSz = sizeof(interpreter::VRegister) * vregNum2;
2851     memset_s(ToVoidPtr(ToUintPtr(f2) + CORE_EXT_FRAME_DATA_SIZE + sizeof(Frame)), allocSz, 0xff, allocSz);
2852 
2853     ark::mem::GC *gc = Runtime::GetCurrent()->GetPandaVM()->GetGC();
2854 
2855     {
2856         ScopedNativeCodeThread sn(ManagedThread::GetCurrent());
2857         GCTask task(GCTaskCause::OOM_CAUSE);
2858         ASSERT_DEATH(task.Run(*gc), "");
2859     }
2860 
2861     ark::FreeFrameInterp(f2, ManagedThread::GetCurrent());
2862 
2863     f2 = CreateFrameWithSize(Frame::GetActualSize<false>(vregNum2), vregNum2, method1.get(), f1.get(),
2864                              ManagedThread::GetCurrent());
2865 
2866     RunTask(gc);
2867 
2868     ark::FreeFrameInterp(f2, ManagedThread::GetCurrent());
2869 }
2870 
2871 }  // namespace ark::interpreter::test
2872 
2873 // NOLINTEND(readability-magic-numbers)
2874