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