• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <gmock/gmock.h>
17 #include <gtest/gtest.h>
18 
19 #include "assembly-parser.h"
20 #include "libpandabase/mem/pool_manager.h"
21 #include "libpandabase/utils/utf.h"
22 #include "libpandafile/bytecode_emitter.h"
23 #include "libpandafile/file.h"
24 #include "libpandafile/file_items.h"
25 #include "libpandafile/value.h"
26 #include "runtime/bridge/bridge.h"
27 #include "runtime/include/class_linker.h"
28 #include "runtime/include/compiler_interface.h"
29 #include "runtime/include/mem/allocator.h"
30 #include "runtime/include/method.h"
31 #include "runtime/include/runtime.h"
32 #include "runtime/include/runtime_options.h"
33 #include "runtime/interpreter/frame.h"
34 #include "runtime/mem/gc/gc.h"
35 #include "runtime/mem/internal_allocator.h"
36 #include "runtime/core/core_class_linker_extension.h"
37 #include "runtime/tests/class_linker_test_extension.h"
38 #include "runtime/tests/interpreter/test_interpreter.h"
39 #include "runtime/tests/interpreter/test_runtime_interface.h"
40 #include "runtime/include/coretypes/dyn_objects.h"
41 #include "runtime/include/hclass.h"
42 #include "runtime/handle_base-inl.h"
43 #include "runtime/handle_scope-inl.h"
44 #include "runtime/include/coretypes/native_pointer.h"
45 #include "runtime/tests/test_utils.h"
46 
47 namespace panda::interpreter {
48 
49 namespace test {
50 
51 using DynClass = panda::coretypes::DynClass;
52 using DynObject = panda::coretypes::DynObject;
53 
54 class InterpreterTest : public testing::Test {
55 public:
InterpreterTest()56     InterpreterTest()
57     {
58         RuntimeOptions options;
59         options.SetShouldLoadBootPandaFiles(false);
60         options.SetShouldInitializeIntrinsics(false);
61         options.SetRunGcInPlace(true);
62         options.SetVerifyCallStack(false);
63         options.SetGcType("epsilon");
64         Runtime::Create(options);
65         thread_ = panda::MTManagedThread::GetCurrent();
66         thread_->ManagedCodeBegin();
67     }
68 
~InterpreterTest()69     ~InterpreterTest()
70     {
71         thread_->ManagedCodeEnd();
72         Runtime::Destroy();
73     }
74 
75 protected:
76     panda::MTManagedThread *thread_;
77 };
78 
CreateFrame(uint32_t nregs,Method * method,Frame * prev)79 auto CreateFrame(uint32_t nregs, Method *method, Frame *prev)
80 {
81     auto frame_deleter = [](Frame *frame) { RuntimeInterface::FreeFrame(ManagedThread::GetCurrent(), frame); };
82     std::unique_ptr<Frame, decltype(frame_deleter)> frame(
83         RuntimeInterface::template CreateFrame<false>(nregs, method, prev), frame_deleter);
84     return frame;
85 }
86 
InitializeFrame(Frame * f)87 static void InitializeFrame(Frame *f)
88 {
89     ManagedThread::GetCurrent()->SetCurrentFrame(f);
90     auto frame_handler = StaticFrameHandler(f);
91     for (size_t i = 0; i < f->GetSize(); i++) {
92         frame_handler.GetVReg(i).Set(static_cast<int64_t>(0));
93     }
94 }
95 
CreateClass(panda_file::SourceLang lang)96 static Class *CreateClass(panda_file::SourceLang lang)
97 {
98     const std::string class_name("Foo");
99     auto runtime = Runtime::GetCurrent();
100     auto etx = runtime->GetClassLinker()->GetExtension(runtime->GetLanguageContext(lang));
101     auto klass = etx->CreateClass(reinterpret_cast<const uint8_t *>(class_name.data()), 0, 0,
102                                   AlignUp(sizeof(Class), OBJECT_POINTER_SIZE));
103     return klass;
104 }
105 
CreateMethod(Class * klass,uint32_t access_flags,uint32_t nargs,uint32_t nregs,uint16_t * shorty,const std::vector<uint8_t> & bytecode)106 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateMethod(
107     Class *klass, uint32_t access_flags, uint32_t nargs, uint32_t nregs, uint16_t *shorty,
108     const std::vector<uint8_t> &bytecode)
109 {
110     // Create panda_file
111 
112     panda_file::ItemContainer container;
113     panda_file::ClassItem *class_item = container.GetOrCreateGlobalClassItem();
114     class_item->SetAccessFlags(ACC_PUBLIC);
115 
116     panda_file::StringItem *method_name = container.GetOrCreateStringItem("test");
117     panda_file::PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(panda_file::Type::TypeId::VOID);
118     std::vector<panda_file::MethodParamItem> params;
119     panda_file::ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
120     panda_file::MethodItem *method_item =
121         class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
122 
123     panda_file::CodeItem *code_item = container.CreateItem<panda_file::CodeItem>(nregs, nargs, bytecode);
124     method_item->SetCode(code_item);
125 
126     panda_file::MemoryWriter mem_writer;
127     container.Write(&mem_writer);
128 
129     auto data = mem_writer.GetData();
130 
131     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
132     auto buf = allocator->AllocArray<uint8_t>(data.size());
133     memcpy_s(buf, data.size(), data.data(), data.size());
134 
135     os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(buf), data.size(), [](std::byte *buffer, size_t) noexcept {
136         auto a = Runtime::GetCurrent()->GetInternalAllocator();
137         a->Free(buffer);
138     });
139     auto pf = panda_file::File::OpenFromMemory(std::move(ptr));
140 
141     // Create method
142 
143     auto method = MakePandaUnique<Method>(klass, pf.get(), method_item->GetFileId(), code_item->GetFileId(),
144                                           access_flags | ACC_PUBLIC | ACC_STATIC, nargs, shorty);
145     method->SetInterpreterEntryPoint();
146     return {std::move(method), std::move(pf)};
147 }
148 
CreateMethod(Class * klass,Frame * f,const std::vector<uint8_t> & bytecode)149 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateMethod(
150     Class *klass, Frame *f, const std::vector<uint8_t> &bytecode)
151 {
152     return CreateMethod(klass, 0, 0, f->GetSize(), nullptr, bytecode);
153 }
154 
CreateClassLinker(ManagedThread * thread)155 static std::unique_ptr<ClassLinker> CreateClassLinker([[maybe_unused]] ManagedThread *thread)
156 {
157     std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
158     extensions.push_back(std::make_unique<CoreClassLinkerExtension>());
159 
160     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
161     auto class_linker = std::make_unique<ClassLinker>(allocator, std::move(extensions));
162     if (!class_linker->Initialize()) {
163         return nullptr;
164     }
165 
166     return class_linker;
167 }
168 
TEST_F(InterpreterTest,TestMov)169 TEST_F(InterpreterTest, TestMov)
170 {
171     BytecodeEmitter emitter;
172 
173     constexpr int64_t IMM4_MAX = 7;
174     constexpr int64_t IMM8_MAX = std::numeric_limits<int8_t>::max();
175     constexpr int64_t IMM16_MAX = std::numeric_limits<int16_t>::max();
176     constexpr int64_t IMM32_MAX = std::numeric_limits<int32_t>::max();
177     constexpr int64_t IMM64_MAX = std::numeric_limits<int64_t>::max();
178 
179     constexpr uint16_t V4_MAX = 15;
180     constexpr uint16_t V8_MAX = std::numeric_limits<uint8_t>::max();
181     constexpr uint16_t V16_MAX = std::numeric_limits<uint16_t>::max();
182 
183     ObjectHeader *obj1 = panda::mem::AllocateNullifiedPayloadString(1);
184     ObjectHeader *obj2 = panda::mem::AllocateNullifiedPayloadString(100);
185     ObjectHeader *obj3 = panda::mem::AllocateNullifiedPayloadString(200);
186 
187     emitter.Movi(0, IMM4_MAX);
188     emitter.Movi(1, IMM8_MAX);
189     emitter.Movi(2, IMM16_MAX);
190     emitter.Movi(3, IMM32_MAX);
191     emitter.MoviWide(4, IMM64_MAX);
192 
193     emitter.Mov(V4_MAX, V4_MAX - 1);
194     emitter.Mov(V8_MAX, V8_MAX - 1);
195     emitter.Mov(V16_MAX, V16_MAX - 1);
196 
197     emitter.MovWide(V4_MAX - 2, V4_MAX - 3);
198     emitter.MovWide(V16_MAX - 2, V16_MAX - 3);
199 
200     emitter.MovObj(V4_MAX - 4, V4_MAX - 5);
201     emitter.MovObj(V8_MAX - 4, V8_MAX - 5);
202     emitter.MovObj(V16_MAX - 4, V16_MAX - 5);
203 
204     emitter.ReturnVoid();
205 
206     std::vector<uint8_t> bytecode;
207     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
208 
209     auto f = CreateFrame(std::numeric_limits<uint16_t>::max() + 1, nullptr, nullptr);
210     InitializeFrame(f.get());
211     auto frame_handler = StaticFrameHandler(f.get());
212 
213     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
214     auto method_data = CreateMethod(cls, f.get(), bytecode);
215     auto method = std::move(method_data.first);
216     f->SetMethod(method.get());
217 
218     frame_handler.GetVReg(V4_MAX - 1).SetPrimitive(IMM64_MAX - 1);
219     frame_handler.GetVReg(V8_MAX - 1).SetPrimitive(IMM64_MAX - 2);
220     frame_handler.GetVReg(V16_MAX - 1).SetPrimitive(IMM64_MAX - 3);
221 
222     frame_handler.GetVReg(V4_MAX - 3).SetPrimitive(IMM64_MAX - 4);
223     frame_handler.GetVReg(V16_MAX - 3).SetPrimitive(IMM64_MAX - 5);
224 
225     frame_handler.GetVReg(V4_MAX - 5).SetReference(obj1);
226     frame_handler.GetVReg(V8_MAX - 5).SetReference(obj2);
227     frame_handler.GetVReg(V16_MAX - 5).SetReference(obj3);
228 
229     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
230 
231     // Check movi
232 
233     EXPECT_EQ(frame_handler.GetVReg(0).GetLong(), IMM4_MAX);
234     EXPECT_FALSE(frame_handler.GetVReg(0).HasObject());
235 
236     EXPECT_EQ(frame_handler.GetVReg(1).GetLong(), IMM8_MAX);
237     EXPECT_FALSE(frame_handler.GetVReg(1).HasObject());
238 
239     EXPECT_EQ(frame_handler.GetVReg(2).GetLong(), IMM16_MAX);
240     EXPECT_FALSE(frame_handler.GetVReg(2).HasObject());
241 
242     EXPECT_EQ(frame_handler.GetVReg(3).GetLong(), IMM32_MAX);
243     EXPECT_FALSE(frame_handler.GetVReg(3).HasObject());
244 
245     EXPECT_EQ(frame_handler.GetVReg(4).GetLong(), IMM64_MAX);
246     EXPECT_FALSE(frame_handler.GetVReg(4).HasObject());
247 
248     // Check mov
249 
250     EXPECT_EQ(frame_handler.GetVReg(V4_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 1));
251     EXPECT_FALSE(frame_handler.GetVReg(V4_MAX).HasObject());
252 
253     EXPECT_EQ(frame_handler.GetVReg(V8_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 2));
254     EXPECT_FALSE(frame_handler.GetVReg(V8_MAX).HasObject());
255 
256     EXPECT_EQ(frame_handler.GetVReg(V16_MAX).Get(), static_cast<int32_t>(IMM64_MAX - 3));
257     EXPECT_FALSE(frame_handler.GetVReg(V16_MAX).HasObject());
258 
259     // Check mov.64
260 
261     EXPECT_EQ(frame_handler.GetVReg(V4_MAX - 2).GetLong(), IMM64_MAX - 4);
262     EXPECT_FALSE(frame_handler.GetVReg(V4_MAX - 2).HasObject());
263 
264     EXPECT_EQ(frame_handler.GetVReg(V16_MAX - 2).GetLong(), IMM64_MAX - 5);
265     EXPECT_FALSE(frame_handler.GetVReg(V16_MAX - 2).HasObject());
266 
267     // Check mov.obj
268 
269     EXPECT_EQ(frame_handler.GetVReg(V4_MAX - 4).GetReference(), obj1);
270     EXPECT_TRUE(frame_handler.GetVReg(V4_MAX - 4).HasObject());
271 
272     EXPECT_EQ(frame_handler.GetVReg(V8_MAX - 4).GetReference(), obj2);
273     EXPECT_TRUE(frame_handler.GetVReg(V8_MAX - 4).HasObject());
274 
275     EXPECT_EQ(frame_handler.GetVReg(V16_MAX - 4).GetReference(), obj3);
276     EXPECT_TRUE(frame_handler.GetVReg(V16_MAX - 4).HasObject());
277 }
278 
TEST_F(InterpreterTest,TestLoadStoreAccumulator)279 TEST_F(InterpreterTest, TestLoadStoreAccumulator)
280 {
281     BytecodeEmitter emitter;
282 
283     constexpr int64_t IMM8_MAX = std::numeric_limits<int8_t>::max();
284     constexpr int64_t IMM16_MAX = std::numeric_limits<int16_t>::max();
285     constexpr int64_t IMM32_MAX = std::numeric_limits<int32_t>::max();
286     constexpr int64_t IMM64_MAX = std::numeric_limits<int64_t>::max();
287 
288     ObjectHeader *obj = panda::mem::AllocateNullifiedPayloadString(10);
289 
290     emitter.Ldai(IMM8_MAX);
291     emitter.Sta(0);
292 
293     emitter.Ldai(IMM16_MAX);
294     emitter.Sta(1);
295 
296     emitter.Ldai(IMM32_MAX);
297     emitter.Sta(2);
298 
299     emitter.LdaiWide(IMM64_MAX);
300     emitter.StaWide(3);
301 
302     emitter.Lda(4);
303     emitter.Sta(5);
304 
305     emitter.LdaWide(6);
306     emitter.StaWide(7);
307 
308     emitter.LdaObj(8);
309     emitter.StaObj(9);
310 
311     emitter.ReturnVoid();
312 
313     std::vector<uint8_t> bytecode;
314     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
315 
316     auto f = CreateFrame(16, nullptr, nullptr);
317     InitializeFrame(f.get());
318     auto frame_handler = StaticFrameHandler(f.get());
319 
320     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
321     auto method_data = CreateMethod(cls, f.get(), bytecode);
322     auto method = std::move(method_data.first);
323     f->SetMethod(method.get());
324 
325     frame_handler.GetVReg(4).SetPrimitive(IMM64_MAX - 1);
326     frame_handler.GetVReg(6).SetPrimitive(IMM64_MAX - 2);
327     frame_handler.GetVReg(8).SetReference(obj);
328 
329     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
330 
331     EXPECT_EQ(frame_handler.GetVReg(0).Get(), static_cast<int32_t>(IMM8_MAX));
332     EXPECT_FALSE(frame_handler.GetVReg(0).HasObject());
333 
334     EXPECT_EQ(frame_handler.GetVReg(1).Get(), static_cast<int32_t>(IMM16_MAX));
335     EXPECT_FALSE(frame_handler.GetVReg(1).HasObject());
336 
337     EXPECT_EQ(frame_handler.GetVReg(2).Get(), static_cast<int32_t>(IMM32_MAX));
338     EXPECT_FALSE(frame_handler.GetVReg(2).HasObject());
339 
340     EXPECT_EQ(frame_handler.GetVReg(3).GetLong(), IMM64_MAX);
341     EXPECT_FALSE(frame_handler.GetVReg(3).HasObject());
342 
343     EXPECT_EQ(frame_handler.GetVReg(5).Get(), static_cast<int32_t>(IMM64_MAX - 1));
344     EXPECT_FALSE(frame_handler.GetVReg(5).HasObject());
345 
346     EXPECT_EQ(frame_handler.GetVReg(7).GetLong(), IMM64_MAX - 2);
347     EXPECT_FALSE(frame_handler.GetVReg(7).HasObject());
348 
349     EXPECT_EQ(frame_handler.GetVReg(9).GetReference(), obj);
350     EXPECT_TRUE(frame_handler.GetVReg(9).HasObject());
351 }
352 
TEST_F(InterpreterTest,TestLoadString)353 TEST_F(InterpreterTest, TestLoadString)
354 {
355     pandasm::Parser p;
356     std::string source = R"(
357     .record panda.String <external>
358     .function panda.String foo(){
359         lda.str "TestLoadString"
360         return.obj
361     }
362     )";
363 
364     auto res = p.Parse(source);
365     auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
366 
367     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
368     ASSERT_NE(class_linker, nullptr);
369 
370     class_linker->AddPandaFile(std::move(class_pf));
371 
372     PandaString descriptor;
373     auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
374 
375     Class *cls = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
376     Method *method = cls->GetClassMethod(utf::CStringAsMutf8("foo"));
377     const uint8_t *method_data = method->GetInstructions();
378 
379     auto f = CreateFrame(16, nullptr, nullptr);
380     InitializeFrame(f.get());
381     f->SetMethod(method);
382 
383     Execute(ManagedThread::GetCurrent(), method_data, f.get());
384     EXPECT_TRUE(f->GetAccAsVReg().HasObject());
385 
386     PandaString str_sample = "TestLoadString";
387     panda::coretypes::String *str_core = panda::coretypes::String::Cast(f->GetAccAsVReg().GetReference());
388 
389     const char *str = reinterpret_cast<const char *>(str_core->GetDataMUtf8());
390     size_t str_len = str_core->GetMUtf8Length() - 1;  // Reserved zero.
391     PandaString str_tst(str, str_len);
392 
393     EXPECT_EQ(str_sample, str_tst);
394 }
395 
TestUnimpelemented(std::function<void (BytecodeEmitter *)> emit)396 void TestUnimpelemented(std::function<void(BytecodeEmitter *)> emit)
397 {
398     BytecodeEmitter emitter;
399 
400     emit(&emitter);
401 
402     std::vector<uint8_t> bytecode;
403     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
404 
405     auto f = CreateFrame(16, nullptr, nullptr);
406     InitializeFrame(f.get());
407 
408     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
409     auto method_data = CreateMethod(cls, f.get(), bytecode);
410     auto method = std::move(method_data.first);
411     f->SetMethod(method.get());
412 
413     EXPECT_DEATH_IF_SUPPORTED(Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get()), "");
414 }
415 
TEST_F(InterpreterTest,LoadType)416 TEST_F(InterpreterTest, LoadType)
417 {
418     BytecodeEmitter emitter;
419 
420     pandasm::Parser p;
421     auto source = R"(
422         .record R {}
423     )";
424 
425     auto res = p.Parse(source);
426     auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
427 
428     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
429     ASSERT_NE(class_linker, nullptr);
430 
431     class_linker->AddPandaFile(std::move(class_pf));
432 
433     PandaString descriptor;
434     auto *thread = ManagedThread::GetCurrent();
435     auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
436     Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
437     ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
438 
439     emitter.LdaType(RuntimeInterface::TYPE_ID.AsIndex());
440     emitter.ReturnObj();
441 
442     std::vector<uint8_t> bytecode;
443     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
444 
445     auto f = CreateFrame(16, nullptr, nullptr);
446     InitializeFrame(f.get());
447 
448     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
449     auto method_data = CreateMethod(cls, f.get(), bytecode);
450     auto method = std::move(method_data.first);
451     f->SetMethod(method.get());
452 
453     RuntimeInterface::SetupResolvedClass(object_class);
454 
455     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
456 
457     RuntimeInterface::SetupResolvedClass(nullptr);
458 
459     EXPECT_EQ(coretypes::Class::FromRuntimeClass(object_class), f->GetAccAsVReg().GetReference());
460 }
461 
TestFcmp(double v1,double v2,int64_t value,bool is_cmpg=false)462 void TestFcmp(double v1, double v2, int64_t value, bool is_cmpg = false)
463 {
464     std::ostringstream ss;
465     if (is_cmpg) {
466         ss << "Test fcmpg.64";
467     } else {
468         ss << "Test fcmpl.64";
469     }
470     ss << ", v1 = " << v1 << ", v2 = " << v2;
471 
472     BytecodeEmitter emitter;
473 
474     if (is_cmpg) {
475         emitter.FcmpgWide(0);
476     } else {
477         emitter.FcmplWide(0);
478     }
479     emitter.ReturnWide();
480 
481     std::vector<uint8_t> bytecode;
482     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
483 
484     auto f = CreateFrame(16, nullptr, nullptr);
485     InitializeFrame(f.get());
486 
487     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
488     auto method_data = CreateMethod(cls, f.get(), bytecode);
489     auto method = std::move(method_data.first);
490     f->SetMethod(method.get());
491 
492     f->GetAccAsVReg().SetPrimitive(v1);
493     auto frame_handler = StaticFrameHandler(f.get());
494     frame_handler.GetVReg(0).SetPrimitive(v2);
495 
496     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
497 
498     EXPECT_EQ(f->GetAccAsVReg().GetLong(), value) << ss.str();
499     EXPECT_FALSE(f->GetAccAsVReg().HasObject()) << ss.str();
500 }
501 
TEST_F(InterpreterTest,TestFcmp)502 TEST_F(InterpreterTest, TestFcmp)
503 {
504     TestFcmp(nan(""), 1.0, 1, true);
505     TestFcmp(1.0, nan(""), 1, true);
506     TestFcmp(nan(""), nan(""), 1, true);
507     TestFcmp(1.0, 2.0, -1, true);
508     TestFcmp(1.0, 1.0, 0, true);
509     TestFcmp(3.0, 2.0, 1, true);
510 
511     TestFcmp(nan(""), 1.0, -1);
512     TestFcmp(1.0, nan(""), -1);
513     TestFcmp(nan(""), nan(""), -1);
514     TestFcmp(1.0, 2.0, -1);
515     TestFcmp(1.0, 1.0, 0);
516     TestFcmp(3.0, 2.0, 1);
517 }
518 
TestConditionalJmp(const std::string & mnemonic,int64_t v1,int64_t v2,int64_t r,std::function<void (BytecodeEmitter *,uint8_t,const Label &)> emit)519 void TestConditionalJmp(const std::string &mnemonic, int64_t v1, int64_t v2, int64_t r,
520                         std::function<void(BytecodeEmitter *, uint8_t, const Label &)> emit)
521 {
522     std::ostringstream ss;
523     ss << "Test " << mnemonic << " with v1 = " << v1 << ", v2 = " << v2;
524 
525     {
526         BytecodeEmitter emitter;
527         Label label = emitter.CreateLabel();
528 
529         emit(&emitter, 0, label);
530         emitter.MoviWide(1, -1);
531         emitter.ReturnVoid();
532         emitter.Bind(label);
533         emitter.MoviWide(1, 1);
534         emitter.ReturnVoid();
535 
536         std::vector<uint8_t> bytecode;
537         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
538 
539         auto f = CreateFrame(16, nullptr, nullptr);
540         InitializeFrame(f.get());
541 
542         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
543         auto method_data = CreateMethod(cls, f.get(), bytecode);
544         auto method = std::move(method_data.first);
545         f->SetMethod(method.get());
546 
547         f->GetAccAsVReg().SetPrimitive(v1);
548         auto frame_handler = StaticFrameHandler(f.get());
549         frame_handler.GetVReg(0).SetPrimitive(v2);
550 
551         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
552 
553         EXPECT_EQ(frame_handler.GetVReg(1).GetLong(), r) << ss.str();
554     }
555 
556     {
557         BytecodeEmitter emitter;
558         Label label1 = emitter.CreateLabel();
559         Label label2 = emitter.CreateLabel();
560 
561         emitter.Jmp(label1);
562         emitter.Bind(label2);
563         emitter.MoviWide(1, 1);
564         emitter.ReturnVoid();
565         emitter.Bind(label1);
566         emit(&emitter, 0, label2);
567         emitter.MoviWide(1, -1);
568         emitter.ReturnVoid();
569 
570         std::vector<uint8_t> bytecode;
571         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
572 
573         auto f = CreateFrame(16, nullptr, nullptr);
574         InitializeFrame(f.get());
575 
576         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
577         auto method_data = CreateMethod(cls, f.get(), bytecode);
578         auto method = std::move(method_data.first);
579         f->SetMethod(method.get());
580 
581         f->GetAccAsVReg().SetPrimitive(v1);
582         auto frame_handler = StaticFrameHandler(f.get());
583         frame_handler.GetVReg(0).SetPrimitive(v2);
584 
585         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
586 
587         EXPECT_EQ(frame_handler.GetVReg(1).GetLong(), r) << ss.str();
588         EXPECT_EQ(method->GetHotnessCounter(), r == 1 ? 1U : 0U) << ss.str();
589     }
590 }
591 
TestConditionalJmpz(const std::string & mnemonic,int64_t v,int64_t r,std::function<void (BytecodeEmitter *,const Label &)> emit)592 void TestConditionalJmpz(const std::string &mnemonic, int64_t v, int64_t r,
593                          std::function<void(BytecodeEmitter *, const Label &)> emit)
594 {
595     std::ostringstream ss;
596     ss << "Test " << mnemonic << " with v = " << v;
597 
598     {
599         BytecodeEmitter emitter;
600         Label label = emitter.CreateLabel();
601 
602         emit(&emitter, label);
603         emitter.MoviWide(0, -1);
604         emitter.ReturnVoid();
605         emitter.Bind(label);
606         emitter.MoviWide(0, 1);
607         emitter.ReturnVoid();
608 
609         std::vector<uint8_t> bytecode;
610         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
611 
612         auto f = CreateFrame(16, nullptr, nullptr);
613         InitializeFrame(f.get());
614 
615         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
616         auto method_data = CreateMethod(cls, f.get(), bytecode);
617         auto method = std::move(method_data.first);
618         f->SetMethod(method.get());
619 
620         f->GetAccAsVReg().SetPrimitive(v);
621 
622         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
623 
624         auto frame_handler = StaticFrameHandler(f.get());
625         EXPECT_EQ(frame_handler.GetVReg(0).GetLong(), r) << ss.str();
626     }
627 
628     {
629         BytecodeEmitter emitter;
630         Label label1 = emitter.CreateLabel();
631         Label label2 = emitter.CreateLabel();
632 
633         emitter.Jmp(label1);
634         emitter.Bind(label2);
635         emitter.MoviWide(0, 1);
636         emitter.ReturnVoid();
637         emitter.Bind(label1);
638         emit(&emitter, label2);
639         emitter.MoviWide(0, -1);
640         emitter.ReturnVoid();
641 
642         std::vector<uint8_t> bytecode;
643         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
644 
645         auto f = CreateFrame(16, nullptr, nullptr);
646         InitializeFrame(f.get());
647 
648         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
649         auto method_data = CreateMethod(cls, f.get(), bytecode);
650         auto method = std::move(method_data.first);
651         f->SetMethod(method.get());
652 
653         f->GetAccAsVReg().SetPrimitive(v);
654 
655         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
656 
657         auto frame_handler = StaticFrameHandler(f.get());
658         EXPECT_EQ(frame_handler.GetVReg(0).GetLong(), r) << ss.str();
659         EXPECT_EQ(method->GetHotnessCounter(), r == 1 ? 1U : 0U) << ss.str();
660     }
661 }
662 
TEST_F(InterpreterTest,TestConditionalJumps)663 TEST_F(InterpreterTest, TestConditionalJumps)
664 {
665     // Test jmpz
666 
667     TestConditionalJmpz("jeqz", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
668     TestConditionalJmpz("jeqz", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
669     TestConditionalJmpz("jeqz", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jeqz(label); });
670 
671     TestConditionalJmpz("jnez", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
672     TestConditionalJmpz("jnez", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
673     TestConditionalJmpz("jnez", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jnez(label); });
674 
675     TestConditionalJmpz("jltz", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
676     TestConditionalJmpz("jltz", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
677     TestConditionalJmpz("jltz", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jltz(label); });
678 
679     TestConditionalJmpz("jgtz", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
680     TestConditionalJmpz("jgtz", 0, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
681     TestConditionalJmpz("jgtz", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgtz(label); });
682 
683     TestConditionalJmpz("jlez", -1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
684     TestConditionalJmpz("jlez", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
685     TestConditionalJmpz("jlez", 1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jlez(label); });
686 
687     TestConditionalJmpz("jgez", 1, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
688     TestConditionalJmpz("jgez", 0, 1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
689     TestConditionalJmpz("jgez", -1, -1, [](BytecodeEmitter *emitter, const Label &label) { emitter->Jgez(label); });
690 
691     // Test jmp
692 
693     TestConditionalJmp("jeq", 2, 2, 1,
694                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
695     TestConditionalJmp("jeq", 1, 2, -1,
696                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
697     TestConditionalJmp("jeq", 2, 1, -1,
698                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jeq(reg, label); });
699 
700     TestConditionalJmp("jne", 2, 2, -1,
701                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
702     TestConditionalJmp("jne", 1, 2, 1,
703                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
704     TestConditionalJmp("jne", 2, 1, 1,
705                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jne(reg, label); });
706 
707     TestConditionalJmp("jlt", 2, 2, -1,
708                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
709     TestConditionalJmp("jlt", 1, 2, 1,
710                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
711     TestConditionalJmp("jlt", 2, 1, -1,
712                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jlt(reg, label); });
713 
714     TestConditionalJmp("jgt", 2, 2, -1,
715                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
716     TestConditionalJmp("jgt", 1, 2, -1,
717                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
718     TestConditionalJmp("jgt", 2, 1, 1,
719                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jgt(reg, label); });
720 
721     TestConditionalJmp("jle", 2, 2, 1,
722                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
723     TestConditionalJmp("jle", 1, 2, 1,
724                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
725     TestConditionalJmp("jle", 2, 1, -1,
726                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jle(reg, label); });
727 
728     TestConditionalJmp("jge", 2, 2, 1,
729                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
730     TestConditionalJmp("jge", 1, 2, -1,
731                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
732     TestConditionalJmp("jge", 2, 1, 1,
733                        [](BytecodeEmitter *emitter, uint8_t reg, const Label &label) { emitter->Jge(reg, label); });
734 }
735 
736 template <class T, class R>
TestUnaryOp(const std::string & mnemonic,T v,R r,std::function<void (BytecodeEmitter *)> emit)737 void TestUnaryOp(const std::string &mnemonic, T v, R r, std::function<void(BytecodeEmitter *)> emit)
738 {
739     std::ostringstream ss;
740     ss << "Test " << mnemonic << " with v = " << v;
741 
742     BytecodeEmitter emitter;
743 
744     emit(&emitter);
745     emitter.ReturnWide();
746 
747     std::vector<uint8_t> bytecode;
748     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
749 
750     auto f = CreateFrame(16, nullptr, nullptr);
751     InitializeFrame(f.get());
752 
753     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
754     auto method_data = CreateMethod(cls, f.get(), bytecode);
755     auto method = std::move(method_data.first);
756     f->SetMethod(method.get());
757 
758     f->GetAccAsVReg().SetPrimitive(v);
759 
760     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
761 
762     EXPECT_EQ(f->GetAccAsVReg().GetAs<R>(), r) << ss.str();
763 }
764 
TEST_F(InterpreterTest,TestUnaryOp)765 TEST_F(InterpreterTest, TestUnaryOp)
766 {
767     constexpr int64_t I32_MIN = std::numeric_limits<int32_t>::min();
768     constexpr int64_t I64_MIN = std::numeric_limits<int64_t>::min();
769 
770     TestUnaryOp<int64_t, int64_t>("neg", I64_MIN + 1, -(I64_MIN + 1),
771                                   [](BytecodeEmitter *emitter) { emitter->NegWide(); });
772 
773     TestUnaryOp<int32_t, int64_t>("neg", I32_MIN + 1, -(I32_MIN + 1), [](BytecodeEmitter *emitter) { emitter->Neg(); });
774 
775     TestUnaryOp<double, double>("fneg", 1.0, -1.0, [](BytecodeEmitter *emitter) { emitter->FnegWide(); });
776 
777     TestUnaryOp<int64_t, int64_t>("not", 0, 0xffffffffffffffff, [](BytecodeEmitter *emitter) { emitter->NotWide(); });
778 
779     TestUnaryOp<int32_t, int32_t>("not", 0, 0xffffffff, [](BytecodeEmitter *emitter) { emitter->Not(); });
780 }
781 
TEST_F(InterpreterTest,TestInci)782 TEST_F(InterpreterTest, TestInci)
783 {
784     BytecodeEmitter emitter;
785     emitter.Inci(0, 2);
786     emitter.Inci(1, -3);
787     emitter.ReturnWide();
788 
789     std::vector<uint8_t> bytecode;
790     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
791 
792     auto f = CreateFrame(16, nullptr, nullptr);
793     InitializeFrame(f.get());
794 
795     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
796     auto method_data = CreateMethod(cls, f.get(), bytecode);
797     auto method = std::move(method_data.first);
798     f->SetMethod(method.get());
799 
800     auto frame_handler = StaticFrameHandler(f.get());
801     frame_handler.GetVReg(0).SetPrimitive(-2);
802     frame_handler.GetVReg(1).SetPrimitive(3);
803 
804     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
805 
806     EXPECT_EQ(frame_handler.GetVReg(0).GetAs<int32_t>(), 0);
807     EXPECT_EQ(frame_handler.GetVReg(1).GetAs<int32_t>(), 0);
808 }
809 
TEST_F(InterpreterTest,TestCast)810 TEST_F(InterpreterTest, TestCast)
811 {
812     constexpr int64_t I64_MAX = std::numeric_limits<int64_t>::max();
813     constexpr int32_t I32_MAX = std::numeric_limits<int32_t>::max();
814     constexpr int64_t I64_MIN = std::numeric_limits<int64_t>::min();
815     constexpr int32_t I32_MIN = std::numeric_limits<int32_t>::min();
816 
817     constexpr double F64_MAX = std::numeric_limits<double>::max();
818     constexpr double F64_PINF = std::numeric_limits<double>::infinity();
819     constexpr double F64_NINF = -F64_PINF;
820 
821     double f64 = 64.0;
822 
823     TestUnaryOp("i32toi64", I32_MAX, static_cast<int64_t>(I32_MAX),
824                 [](BytecodeEmitter *emitter) { emitter->I32toi64(); });
825 
826     TestUnaryOp("i32tof64", I32_MAX, static_cast<double>(I32_MAX),
827                 [](BytecodeEmitter *emitter) { emitter->I32tof64(); });
828 
829     TestUnaryOp("i64toi32", I64_MAX, static_cast<int32_t>(I64_MAX),
830                 [](BytecodeEmitter *emitter) { emitter->I64toi32(); });
831 
832     TestUnaryOp("i64tof64", I64_MAX, static_cast<double>(I64_MAX),
833                 [](BytecodeEmitter *emitter) { emitter->I64tof64(); });
834 
835     TestUnaryOp("F64toi32", F64_MAX, I32_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
836     TestUnaryOp("F64toi32", F64_PINF, I32_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
837     TestUnaryOp("F64toi32", -F64_MAX, I32_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
838     TestUnaryOp("F64toi32", F64_NINF, I32_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
839     TestUnaryOp("F64toi32", nan(""), 0, [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
840     TestUnaryOp("F64toi32", f64, static_cast<int32_t>(f64), [](BytecodeEmitter *emitter) { emitter->F64toi32(); });
841 
842     TestUnaryOp("F64toi64", F64_MAX, I64_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
843     TestUnaryOp("F64toi64", F64_PINF, I64_MAX, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
844     TestUnaryOp("F64toi64", -F64_MAX, I64_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
845     TestUnaryOp("F64toi64", F64_NINF, I64_MIN, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
846     TestUnaryOp("F64toi64", nan(""), 0, [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
847     TestUnaryOp("F64toi64", f64, static_cast<int64_t>(f64), [](BytecodeEmitter *emitter) { emitter->F64toi64(); });
848 }
849 
850 // clang-format off
851 
852 template <panda_file::Type::TypeId type_id>
853 struct ArrayComponentTypeHelper {
854     using type = std::conditional_t<type_id == panda_file::Type::TypeId::U1, uint8_t,
855                  std::conditional_t<type_id == panda_file::Type::TypeId::I8, int8_t,
856                  std::conditional_t<type_id == panda_file::Type::TypeId::U8, uint8_t,
857                  std::conditional_t<type_id == panda_file::Type::TypeId::I16, int16_t,
858                  std::conditional_t<type_id == panda_file::Type::TypeId::U16, uint16_t,
859                  std::conditional_t<type_id == panda_file::Type::TypeId::I32, int32_t,
860                  std::conditional_t<type_id == panda_file::Type::TypeId::U32, uint32_t,
861                  std::conditional_t<type_id == panda_file::Type::TypeId::I64, int64_t,
862                  std::conditional_t<type_id == panda_file::Type::TypeId::U64, uint64_t,
863                  std::conditional_t<type_id == panda_file::Type::TypeId::F32, float,
864                  std::conditional_t<type_id == panda_file::Type::TypeId::F64, double,
865                  std::conditional_t<type_id == panda_file::Type::TypeId::REFERENCE, ObjectHeader*, void>>>>>>>>>>>>;
866 };
867 
868 // clang-format on
869 
870 template <panda_file::Type::TypeId type_id>
871 using ArrayComponentTypeHelperT = typename ArrayComponentTypeHelper<type_id>::type;
872 
873 template <panda_file::Type::TypeId type_id>
874 struct ArrayStoredTypeHelperT {
875     using type = typename ArrayComponentTypeHelper<type_id>::type;
876 };
877 
878 template <>
879 struct ArrayStoredTypeHelperT<panda_file::Type::TypeId::REFERENCE> {
880     using type = object_pointer_type;
881 };
882 
883 template <panda_file::Type::TypeId type_id>
CastIfRef(ArrayComponentTypeHelperT<type_id> value)884 typename ArrayStoredTypeHelperT<type_id>::type CastIfRef(ArrayComponentTypeHelperT<type_id> value)
885 {
886     if constexpr (type_id == panda_file::Type::TypeId::REFERENCE) {
887         return static_cast<object_pointer_type>(reinterpret_cast<uintptr_t>(value));
888     } else {
889         return value;
890     }
891 }
892 
AllocArray(Class * cls,size_t elem_size,size_t length)893 coretypes::Array *AllocArray(Class *cls, [[maybe_unused]] size_t elem_size, size_t length)
894 {
895     return coretypes::Array::Create(cls, length);
896 }
897 
AllocObject(Class * cls)898 ObjectHeader *AllocObject(Class *cls)
899 {
900     return ObjectHeader::Create(cls);
901 }
902 
903 template <class T>
GetStoreValue(Class * cls)904 static T GetStoreValue([[maybe_unused]] Class *cls)
905 {
906     if constexpr (std::is_same_v<T, ObjectHeader *>) {
907         return AllocObject(cls);
908     }
909 
910     return std::numeric_limits<T>::max();
911 }
912 
913 template <class T>
GetLoadValue(Class * cls)914 static T GetLoadValue([[maybe_unused]] Class *cls)
915 {
916     if constexpr (std::is_same_v<T, ObjectHeader *>) {
917         return AllocObject(cls);
918     }
919 
920     return std::numeric_limits<T>::min() + 1;
921 }
922 
GetArrayClassName(panda_file::Type::TypeId component_type_id)923 PandaString GetArrayClassName(panda_file::Type::TypeId component_type_id)
924 {
925     PandaString descriptor;
926 
927     if (component_type_id == panda_file::Type::TypeId::REFERENCE) {
928         ClassHelper::GetArrayDescriptor(utf::CStringAsMutf8("panda.Object"), 1, &descriptor);
929         return descriptor;
930     }
931 
932     ClassHelper::GetPrimitiveArrayDescriptor(panda_file::Type(component_type_id), 1, &descriptor);
933     return descriptor;
934 }
935 
936 template <panda_file::Type::TypeId component_type_id>
TestArray()937 static void TestArray()
938 {
939     std::ostringstream ss;
940     ss << "Test with component type id " << static_cast<uint32_t>(component_type_id);
941 
942     using component_type = ArrayComponentTypeHelperT<component_type_id>;
943     using stored_type = typename ArrayStoredTypeHelperT<component_type_id>::type;
944 
945     BytecodeEmitter emitter;
946 
947     constexpr int64_t ARRAY_LENGTH = 10;
948     constexpr size_t STORE_IDX = ARRAY_LENGTH - 1;
949     constexpr size_t LOAD_IDX = 0;
950 
951     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
952     ASSERT_NE(class_linker, nullptr) << ss.str();
953 
954     auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
955     PandaString array_class_name = GetArrayClassName(component_type_id);
956     Class *array_class = class_linker->GetExtension(ctx)->GetClass(utf::CStringAsMutf8(array_class_name.c_str()));
957     Class *elem_class = array_class->GetComponentType();
958 
959     const component_type STORE_VALUE = GetStoreValue<component_type>(elem_class);
960     const component_type LOAD_VALUE = GetLoadValue<component_type>(elem_class);
961 
962     emitter.Movi(0, ARRAY_LENGTH);
963     emitter.Newarr(1, 0, RuntimeInterface::TYPE_ID.AsIndex());
964 
965     if constexpr (component_type_id == panda_file::Type::TypeId::REFERENCE) {
966         emitter.LdaObj(4);
967     } else if constexpr (component_type_id == panda_file::Type::TypeId::F32) {
968         emitter.Fldai(bit_cast<int32_t>(STORE_VALUE));
969     } else if constexpr (component_type_id == panda_file::Type::TypeId::F64) {
970         emitter.FldaiWide(bit_cast<int64_t>(STORE_VALUE));
971     } else {
972         emitter.LdaiWide(static_cast<int64_t>(STORE_VALUE));
973     }
974 
975     emitter.Movi(2, STORE_IDX);
976 
977     if constexpr (component_type_id != panda_file::Type::TypeId::REFERENCE) {
978         switch (component_type_id) {
979             case panda_file::Type::TypeId::U1:
980             case panda_file::Type::TypeId::U8: {
981                 emitter.Starr8(1, 2);
982                 emitter.Ldai(LOAD_IDX);
983                 emitter.Ldarru8(1);
984                 break;
985             }
986             case panda_file::Type::TypeId::I8: {
987                 emitter.Starr8(1, 2);
988                 emitter.Ldai(LOAD_IDX);
989                 emitter.Ldarr8(1);
990                 break;
991             }
992             case panda_file::Type::TypeId::U16: {
993                 emitter.Starr16(1, 2);
994                 emitter.Ldai(LOAD_IDX);
995                 emitter.Ldarru16(1);
996                 break;
997             }
998             case panda_file::Type::TypeId::I16: {
999                 emitter.Starr16(1, 2);
1000                 emitter.Ldai(LOAD_IDX);
1001                 emitter.Ldarr16(1);
1002                 break;
1003             }
1004             case panda_file::Type::TypeId::U32:
1005             case panda_file::Type::TypeId::I32: {
1006                 emitter.Starr(1, 2);
1007                 emitter.Ldai(LOAD_IDX);
1008                 emitter.Ldarr(1);
1009                 break;
1010             }
1011             case panda_file::Type::TypeId::U64:
1012             case panda_file::Type::TypeId::I64: {
1013                 emitter.StarrWide(1, 2);
1014                 emitter.Ldai(LOAD_IDX);
1015                 emitter.LdarrWide(1);
1016                 break;
1017             }
1018             case panda_file::Type::TypeId::F32: {
1019                 emitter.Fstarr32(1, 2);
1020                 emitter.Ldai(LOAD_IDX);
1021                 emitter.Fldarr32(1);
1022                 break;
1023             }
1024             case panda_file::Type::TypeId::F64: {
1025                 emitter.FstarrWide(1, 2);
1026                 emitter.Ldai(LOAD_IDX);
1027                 emitter.FldarrWide(1);
1028                 break;
1029             }
1030             default:
1031                 UNREACHABLE();
1032         }
1033     } else {
1034         emitter.StarrObj(1, 2);
1035         emitter.Ldai(LOAD_IDX);
1036         emitter.LdarrObj(1);
1037     }
1038 
1039     if constexpr (component_type_id != panda_file::Type::TypeId::REFERENCE) {
1040         emitter.StaWide(3);
1041     } else {
1042         emitter.StaObj(3);
1043     }
1044 
1045     emitter.Lenarr(1);
1046     emitter.Return();
1047 
1048     std::vector<uint8_t> bytecode;
1049     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
1050 
1051     auto f = CreateFrame(16, nullptr, nullptr);
1052     InitializeFrame(f.get());
1053 
1054     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1055     auto method_data = CreateMethod(cls, f.get(), bytecode);
1056     auto method = std::move(method_data.first);
1057     f->SetMethod(method.get());
1058 
1059     auto frame_handler = StaticFrameHandler(f.get());
1060     if constexpr (component_type_id == panda_file::Type::TypeId::REFERENCE) {
1061         frame_handler.GetVReg(4).SetReference(STORE_VALUE);
1062     }
1063 
1064     coretypes::Array *array = AllocArray(array_class, sizeof(stored_type), ARRAY_LENGTH);
1065     array->Set<component_type>(LOAD_IDX, LOAD_VALUE);
1066 
1067     RuntimeInterface::SetupResolvedClass(array_class);
1068     RuntimeInterface::SetupArrayClass(array_class);
1069     RuntimeInterface::SetupArrayLength(ARRAY_LENGTH);
1070     RuntimeInterface::SetupArrayObject(array);
1071 
1072     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1073 
1074     RuntimeInterface::SetupResolvedClass(nullptr);
1075     RuntimeInterface::SetupArrayClass(nullptr);
1076     RuntimeInterface::SetupArrayObject(nullptr);
1077 
1078     ASSERT_EQ(f->GetAccAsVReg().Get(), ARRAY_LENGTH) << ss.str();
1079 
1080     auto *result = static_cast<coretypes::Array *>(frame_handler.GetVReg(1).GetReference());
1081     EXPECT_EQ(result, array) << ss.str();
1082 
1083     EXPECT_EQ(frame_handler.GetVReg(3).GetAs<component_type>(), LOAD_VALUE) << ss.str();
1084 
1085     std::vector<stored_type> data(ARRAY_LENGTH);
1086     data[LOAD_IDX] = CastIfRef<component_type_id>(LOAD_VALUE);
1087     data[STORE_IDX] = CastIfRef<component_type_id>(STORE_VALUE);
1088 
1089     EXPECT_THAT(data, ::testing::ElementsAreArray(reinterpret_cast<stored_type *>(array->GetData()), ARRAY_LENGTH))
1090         << ss.str();
1091 }
1092 
TEST_F(InterpreterTest,TestArray)1093 TEST_F(InterpreterTest, TestArray)
1094 {
1095     TestArray<panda_file::Type::TypeId::U1>();
1096     TestArray<panda_file::Type::TypeId::I8>();
1097     TestArray<panda_file::Type::TypeId::U8>();
1098     TestArray<panda_file::Type::TypeId::I16>();
1099     TestArray<panda_file::Type::TypeId::U16>();
1100     TestArray<panda_file::Type::TypeId::I32>();
1101     TestArray<panda_file::Type::TypeId::U32>();
1102     TestArray<panda_file::Type::TypeId::I64>();
1103     TestArray<panda_file::Type::TypeId::U64>();
1104     TestArray<panda_file::Type::TypeId::F32>();
1105     TestArray<panda_file::Type::TypeId::F64>();
1106     TestArray<panda_file::Type::TypeId::REFERENCE>();
1107 }
1108 
AllocObject(BaseClass * cls)1109 ObjectHeader *AllocObject(BaseClass *cls)
1110 {
1111     return ObjectHeader::Create(cls);
1112 }
1113 
TEST_F(InterpreterTest,TestNewobj)1114 TEST_F(InterpreterTest, TestNewobj)
1115 {
1116     BytecodeEmitter emitter;
1117 
1118     emitter.Newobj(0, RuntimeInterface::TYPE_ID.AsIndex());
1119     emitter.LdaObj(0);
1120     emitter.ReturnObj();
1121 
1122     std::vector<uint8_t> bytecode;
1123     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1124 
1125     auto f = CreateFrame(16, nullptr, nullptr);
1126     InitializeFrame(f.get());
1127 
1128     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1129     auto method_data = CreateMethod(cls, f.get(), bytecode);
1130     auto method = std::move(method_data.first);
1131     f->SetMethod(method.get());
1132 
1133     pandasm::Parser p;
1134     auto source = R"(
1135         .record R {}
1136     )";
1137 
1138     auto res = p.Parse(source);
1139     auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1140 
1141     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1142     ASSERT_NE(class_linker, nullptr);
1143 
1144     class_linker->AddPandaFile(std::move(class_pf));
1145 
1146     PandaString descriptor;
1147     auto *thread = ManagedThread::GetCurrent();
1148     auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1149     Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1150     ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1151 
1152     ObjectHeader *obj = AllocObject(object_class);
1153 
1154     RuntimeInterface::SetupResolvedClass(object_class);
1155     RuntimeInterface::SetupObjectClass(object_class);
1156     RuntimeInterface::SetupObject(obj);
1157 
1158     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1159 
1160     RuntimeInterface::SetupResolvedClass(nullptr);
1161     RuntimeInterface::SetupObjectClass(nullptr);
1162     RuntimeInterface::SetupObject(nullptr);
1163 
1164     EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1165 }
1166 
TEST_F(InterpreterTest,TestInitobj)1167 TEST_F(InterpreterTest, TestInitobj)
1168 {
1169     {
1170         BytecodeEmitter emitter;
1171 
1172         emitter.InitobjShort(0, 2, RuntimeInterface::METHOD_ID.AsIndex());
1173         emitter.ReturnObj();
1174 
1175         std::vector<uint8_t> bytecode;
1176         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1177 
1178         auto f = CreateFrame(16, nullptr, nullptr);
1179         InitializeFrame(f.get());
1180 
1181         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1182         auto method_data = CreateMethod(cls, f.get(), bytecode);
1183         auto method = std::move(method_data.first);
1184         f->SetMethod(method.get());
1185 
1186         pandasm::Parser p;
1187         auto source = R"(
1188             .record R {}
1189 
1190             .function void R.ctor(R a0, i32 a1, i32 a2) <static> {
1191                 return.void
1192             }
1193         )";
1194 
1195         auto res = p.Parse(source);
1196         auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1197 
1198         auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1199         ASSERT_NE(class_linker, nullptr);
1200 
1201         class_linker->AddPandaFile(std::move(class_pf));
1202 
1203         PandaString descriptor;
1204 
1205         auto *thread = ManagedThread::GetCurrent();
1206         auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1207         Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1208         ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1209 
1210         Method *ctor = object_class->GetMethods().data();
1211         ObjectHeader *obj = AllocObject(object_class);
1212 
1213         auto frame_handler = StaticFrameHandler(f.get());
1214         frame_handler.GetVReg(0).Set(10);
1215         frame_handler.GetVReg(2).Set(20);
1216 
1217         bool has_errors = false;
1218 
1219         RuntimeInterface::SetupInvokeMethodHandler(
1220             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1221                 if (m != ctor) {
1222                     has_errors = true;
1223                     return Value(nullptr);
1224                 }
1225 
1226                 Span<Value> sp(args, m->GetNumArgs());
1227                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1228                     has_errors = true;
1229                     return Value(nullptr);
1230                 }
1231 
1232                 if (sp[1].GetAs<int32_t>() != frame_handler.GetVReg(0).Get()) {
1233                     has_errors = true;
1234                     return Value(nullptr);
1235                 }
1236 
1237                 if (sp[2].GetAs<int32_t>() != frame_handler.GetVReg(2).Get()) {
1238                     has_errors = true;
1239                     return Value(nullptr);
1240                 }
1241 
1242                 return Value(nullptr);
1243             });
1244 
1245         RuntimeInterface::SetupResolvedMethod(ctor);
1246         RuntimeInterface::SetupResolvedClass(object_class);
1247         RuntimeInterface::SetupObjectClass(object_class);
1248         RuntimeInterface::SetupObject(obj);
1249 
1250         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1251 
1252         ASSERT_FALSE(has_errors);
1253 
1254         RuntimeInterface::SetupInvokeMethodHandler({});
1255         RuntimeInterface::SetupResolvedMethod(nullptr);
1256         RuntimeInterface::SetupResolvedClass(nullptr);
1257         RuntimeInterface::SetupObjectClass(nullptr);
1258         RuntimeInterface::SetupObject(nullptr);
1259 
1260         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1261     }
1262 
1263     {
1264         BytecodeEmitter emitter;
1265 
1266         emitter.Initobj(0, 2, 3, 5, RuntimeInterface::METHOD_ID.AsIndex());
1267         emitter.ReturnObj();
1268 
1269         std::vector<uint8_t> bytecode;
1270         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1271 
1272         auto f = CreateFrame(16, nullptr, nullptr);
1273         InitializeFrame(f.get());
1274 
1275         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1276         auto method_data = CreateMethod(cls, f.get(), bytecode);
1277         auto method = std::move(method_data.first);
1278         f->SetMethod(method.get());
1279 
1280         pandasm::Parser p;
1281         auto source = R"(
1282             .record R {}
1283 
1284             .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4) <static> {
1285                 return.void
1286             }
1287         )";
1288 
1289         auto res = p.Parse(source);
1290         auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1291 
1292         auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1293         ASSERT_NE(class_linker, nullptr);
1294 
1295         class_linker->AddPandaFile(std::move(class_pf));
1296 
1297         PandaString descriptor;
1298 
1299         auto *thread = ManagedThread::GetCurrent();
1300         auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1301         Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1302         ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1303 
1304         Method *ctor = object_class->GetMethods().data();
1305         ObjectHeader *obj = AllocObject(object_class);
1306 
1307         auto frame_handler = StaticFrameHandler(f.get());
1308         frame_handler.GetVReg(0).Set(10);
1309         frame_handler.GetVReg(2).Set(20);
1310         frame_handler.GetVReg(3).Set(30);
1311         frame_handler.GetVReg(5).Set(40);
1312 
1313         bool has_errors = false;
1314 
1315         RuntimeInterface::SetupInvokeMethodHandler(
1316             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1317                 if (m != ctor) {
1318                     has_errors = true;
1319                     return Value(nullptr);
1320                 }
1321 
1322                 Span<Value> sp(args, m->GetNumArgs());
1323                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1324                     has_errors = true;
1325                     return Value(nullptr);
1326                 }
1327 
1328                 if (sp[1].GetAs<int32_t>() != frame_handler.GetVReg(0).Get()) {
1329                     has_errors = true;
1330                     return Value(nullptr);
1331                 }
1332 
1333                 if (sp[2].GetAs<int32_t>() != frame_handler.GetVReg(2).Get()) {
1334                     has_errors = true;
1335                     return Value(nullptr);
1336                 }
1337 
1338                 if (sp[3].GetAs<int32_t>() != frame_handler.GetVReg(3).Get()) {
1339                     has_errors = true;
1340                     return Value(nullptr);
1341                 }
1342 
1343                 if (sp[4].GetAs<int32_t>() != frame_handler.GetVReg(5).Get()) {
1344                     has_errors = true;
1345                     return Value(nullptr);
1346                 }
1347 
1348                 return Value(nullptr);
1349             });
1350 
1351         RuntimeInterface::SetupResolvedMethod(ctor);
1352         RuntimeInterface::SetupResolvedClass(object_class);
1353         RuntimeInterface::SetupObjectClass(object_class);
1354         RuntimeInterface::SetupObject(obj);
1355 
1356         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1357 
1358         ASSERT_FALSE(has_errors);
1359 
1360         RuntimeInterface::SetupInvokeMethodHandler({});
1361         RuntimeInterface::SetupResolvedMethod(nullptr);
1362         RuntimeInterface::SetupResolvedClass(nullptr);
1363         RuntimeInterface::SetupObjectClass(nullptr);
1364         RuntimeInterface::SetupObject(nullptr);
1365 
1366         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1367     }
1368 
1369     {
1370         BytecodeEmitter emitter;
1371 
1372         emitter.InitobjRange(2, RuntimeInterface::METHOD_ID.AsIndex());
1373         emitter.ReturnObj();
1374 
1375         std::vector<uint8_t> bytecode;
1376         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1377 
1378         auto f = CreateFrame(16, nullptr, nullptr);
1379         InitializeFrame(f.get());
1380 
1381         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1382         auto method_data = CreateMethod(cls, f.get(), bytecode);
1383         auto method = std::move(method_data.first);
1384         f->SetMethod(method.get());
1385 
1386         pandasm::Parser p;
1387         auto source = R"(
1388             .record R {}
1389 
1390             .function void R.ctor(R a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5) <static> {
1391                 return.void
1392             }
1393         )";
1394 
1395         auto res = p.Parse(source);
1396         auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1397 
1398         auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1399         ASSERT_NE(class_linker, nullptr);
1400 
1401         class_linker->AddPandaFile(std::move(class_pf));
1402 
1403         PandaString descriptor;
1404 
1405         auto *thread = ManagedThread::GetCurrent();
1406         auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1407         Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1408         ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1409 
1410         Method *ctor = object_class->GetMethods().data();
1411         ObjectHeader *obj = AllocObject(object_class);
1412 
1413         auto frame_handler = StaticFrameHandler(f.get());
1414         frame_handler.GetVReg(2).Set(10);
1415         frame_handler.GetVReg(3).Set(20);
1416         frame_handler.GetVReg(4).Set(30);
1417         frame_handler.GetVReg(5).Set(40);
1418         frame_handler.GetVReg(6).Set(50);
1419 
1420         bool has_errors = false;
1421 
1422         RuntimeInterface::SetupInvokeMethodHandler(
1423             [&]([[maybe_unused]] ManagedThread *t, Method *m, Value *args) -> Value {
1424                 if (m != ctor) {
1425                     has_errors = true;
1426                     return Value(nullptr);
1427                 }
1428 
1429                 Span<Value> sp(args, m->GetNumArgs());
1430                 if (sp[0].GetAs<ObjectHeader *>() != obj) {
1431                     has_errors = true;
1432                     return Value(nullptr);
1433                 }
1434 
1435                 if (sp[1].GetAs<int32_t>() != frame_handler.GetVReg(2).Get()) {
1436                     has_errors = true;
1437                     return Value(nullptr);
1438                 }
1439 
1440                 if (sp[2].GetAs<int32_t>() != frame_handler.GetVReg(3).Get()) {
1441                     has_errors = true;
1442                     return Value(nullptr);
1443                 }
1444 
1445                 if (sp[3].GetAs<int32_t>() != frame_handler.GetVReg(4).Get()) {
1446                     has_errors = true;
1447                     return Value(nullptr);
1448                 }
1449 
1450                 if (sp[4].GetAs<int32_t>() != frame_handler.GetVReg(5).Get()) {
1451                     has_errors = true;
1452                     return Value(nullptr);
1453                 }
1454 
1455                 if (sp[5].GetAs<int32_t>() != frame_handler.GetVReg(6).Get()) {
1456                     has_errors = true;
1457                     return Value(nullptr);
1458                 }
1459 
1460                 return Value(nullptr);
1461             });
1462 
1463         RuntimeInterface::SetupResolvedMethod(ctor);
1464         RuntimeInterface::SetupResolvedClass(object_class);
1465         RuntimeInterface::SetupObjectClass(object_class);
1466         RuntimeInterface::SetupObject(obj);
1467 
1468         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1469 
1470         ASSERT_FALSE(has_errors);
1471 
1472         RuntimeInterface::SetupInvokeMethodHandler({});
1473         RuntimeInterface::SetupResolvedMethod(nullptr);
1474         RuntimeInterface::SetupResolvedClass(nullptr);
1475         RuntimeInterface::SetupObjectClass(nullptr);
1476         RuntimeInterface::SetupObject(nullptr);
1477 
1478         EXPECT_EQ(obj, f->GetAccAsVReg().GetReference());
1479     }
1480 }
1481 
TestLoadStoreField(bool is_static)1482 void TestLoadStoreField(bool is_static)
1483 {
1484     BytecodeEmitter emitter;
1485 
1486     if (is_static) {
1487         emitter.Ldstatic(RuntimeInterface::FIELD_ID.AsIndex());
1488         emitter.StaWide(1);
1489         emitter.LdaWide(2);
1490         emitter.Ststatic(RuntimeInterface::FIELD_ID.AsIndex());
1491         emitter.Ldstatic(RuntimeInterface::FIELD_ID.AsIndex());
1492     } else {
1493         emitter.Ldobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1494         emitter.StaWide(1);
1495         emitter.LdaWide(2);
1496         emitter.Stobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1497         emitter.Ldobj(0, RuntimeInterface::FIELD_ID.AsIndex());
1498     }
1499     emitter.ReturnWide();
1500 
1501     std::vector<uint8_t> bytecode;
1502     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1503 
1504     auto f = CreateFrame(16, nullptr, nullptr);
1505     InitializeFrame(f.get());
1506 
1507     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1508     auto method_data = CreateMethod(cls, f.get(), bytecode);
1509     auto method = std::move(method_data.first);
1510     f->SetMethod(method.get());
1511 
1512     pandasm::Parser p;
1513     std::string source;
1514 
1515     if (is_static) {
1516         source = R"(
1517             .record R {
1518                 u1  sf_u1  <static>
1519                 i8  sf_i8  <static>
1520                 u8  sf_u8  <static>
1521                 i16 sf_i16 <static>
1522                 u16 sf_u16 <static>
1523                 i32 sf_i32 <static>
1524                 u32 sf_u32 <static>
1525                 i64 sf_i64 <static>
1526                 u64 sf_u64 <static>
1527                 f32 sf_f32 <static>
1528                 f64 sf_f64 <static>
1529             }
1530         )";
1531     } else {
1532         source = R"(
1533             .record R {
1534                 u1  if_u1
1535                 i8  if_i8
1536                 u8  if_u8
1537                 i16 if_i16
1538                 u16 if_u16
1539                 i32 if_i32
1540                 u32 if_u32
1541                 i64 if_i64
1542                 u64 if_u64
1543                 f32 if_f32
1544                 f64 if_f64
1545             }
1546         )";
1547     }
1548 
1549     auto res = p.Parse(source);
1550     auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1551 
1552     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1553     ASSERT_NE(class_linker, nullptr);
1554 
1555     class_linker->AddPandaFile(std::move(class_pf));
1556 
1557     PandaString descriptor;
1558 
1559     auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1560     Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1561     ASSERT_TRUE(class_linker->InitializeClass(ManagedThread::GetCurrent(), object_class));
1562     ObjectHeader *obj = nullptr;
1563 
1564     auto frame_handler = StaticFrameHandler(f.get());
1565     if (!is_static) {
1566         obj = AllocObject(object_class);
1567         frame_handler.GetVReg(0).SetReference(obj);
1568     }
1569 
1570     std::vector<panda_file::Type::TypeId> types {
1571         panda_file::Type::TypeId::U1,  panda_file::Type::TypeId::I8,  panda_file::Type::TypeId::U8,
1572         panda_file::Type::TypeId::I16, panda_file::Type::TypeId::U16, panda_file::Type::TypeId::I32,
1573         panda_file::Type::TypeId::U32, panda_file::Type::TypeId::I64, panda_file::Type::TypeId::U64,
1574         panda_file::Type::TypeId::F32, panda_file::Type::TypeId::F64};
1575 
1576     Span<Field> fields = is_static ? object_class->GetStaticFields() : object_class->GetInstanceFields();
1577     for (size_t i = 0; i < fields.size(); i++) {
1578         Field *field = &fields[i];
1579 
1580         std::ostringstream ss;
1581         ss << "Test field " << reinterpret_cast<const char *>(field->GetName().data);
1582 
1583         constexpr float FLOAT_VALUE = 1.0;
1584         constexpr double DOUBLE_VALUE = 2.0;
1585         int64_t value = 0;
1586 
1587         switch (field->GetTypeId()) {
1588             case panda_file::Type::TypeId::U1: {
1589                 value = std::numeric_limits<uint8_t>::max();
1590                 frame_handler.GetVReg(2).SetPrimitive(value);
1591                 break;
1592             }
1593             case panda_file::Type::TypeId::I8: {
1594                 value = std::numeric_limits<int8_t>::min();
1595                 frame_handler.GetVReg(2).SetPrimitive(value);
1596                 break;
1597             }
1598             case panda_file::Type::TypeId::U8: {
1599                 value = std::numeric_limits<uint8_t>::max();
1600                 frame_handler.GetVReg(2).SetPrimitive(value);
1601                 break;
1602             }
1603             case panda_file::Type::TypeId::I16: {
1604                 value = std::numeric_limits<int16_t>::min();
1605                 frame_handler.GetVReg(2).SetPrimitive(value);
1606                 break;
1607             }
1608             case panda_file::Type::TypeId::U16: {
1609                 value = std::numeric_limits<uint16_t>::max();
1610                 frame_handler.GetVReg(2).SetPrimitive(value);
1611                 break;
1612             }
1613             case panda_file::Type::TypeId::I32: {
1614                 value = std::numeric_limits<int32_t>::min();
1615                 frame_handler.GetVReg(2).SetPrimitive(value);
1616                 break;
1617             }
1618             case panda_file::Type::TypeId::U32: {
1619                 value = std::numeric_limits<uint32_t>::max();
1620                 frame_handler.GetVReg(2).SetPrimitive(value);
1621                 break;
1622             }
1623             case panda_file::Type::TypeId::I64: {
1624                 value = std::numeric_limits<int64_t>::min();
1625                 frame_handler.GetVReg(2).SetPrimitive(value);
1626                 break;
1627             }
1628             case panda_file::Type::TypeId::U64: {
1629                 value = std::numeric_limits<uint64_t>::max();
1630                 frame_handler.GetVReg(2).SetPrimitive(value);
1631                 break;
1632             }
1633             case panda_file::Type::TypeId::F32: {
1634                 frame_handler.GetVReg(2).SetPrimitive(FLOAT_VALUE);
1635                 break;
1636             }
1637             case panda_file::Type::TypeId::F64: {
1638                 frame_handler.GetVReg(2).SetPrimitive(DOUBLE_VALUE);
1639                 break;
1640             }
1641             default: {
1642                 UNREACHABLE();
1643                 break;
1644             }
1645         }
1646 
1647         RuntimeInterface::SetupResolvedField(field);
1648 
1649         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1650 
1651         RuntimeInterface::SetupResolvedField(nullptr);
1652 
1653         switch (field->GetTypeId()) {
1654             case panda_file::Type::TypeId::F32: {
1655                 EXPECT_EQ(f->GetAccAsVReg().GetFloat(), FLOAT_VALUE) << ss.str();
1656                 break;
1657             }
1658             case panda_file::Type::TypeId::F64: {
1659                 EXPECT_EQ(f->GetAccAsVReg().GetDouble(), DOUBLE_VALUE) << ss.str();
1660                 break;
1661             }
1662             default: {
1663                 EXPECT_EQ(f->GetAccAsVReg().GetLong(), value) << ss.str();
1664                 break;
1665             }
1666         }
1667 
1668         EXPECT_EQ(frame_handler.GetVReg(1).GetLong(), 0) << ss.str();
1669     }
1670 }
1671 
TestLoadStoreObjectField(bool is_static)1672 void TestLoadStoreObjectField(bool is_static)
1673 {
1674     BytecodeEmitter emitter;
1675 
1676     std::ostringstream ss;
1677     ss << "Test load/store ";
1678     if (is_static) {
1679         ss << "static ";
1680     }
1681     ss << "object field";
1682 
1683     if (is_static) {
1684         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1685         emitter.StaObj(1);
1686         emitter.LdaObj(2);
1687         emitter.StstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1688         emitter.LdstaticObj(RuntimeInterface::FIELD_ID.AsIndex());
1689     } else {
1690         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1691         emitter.StaObj(1);
1692         emitter.LdaObj(2);
1693         emitter.StobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1694         emitter.LdobjObj(0, RuntimeInterface::FIELD_ID.AsIndex());
1695     }
1696     emitter.ReturnObj();
1697 
1698     std::vector<uint8_t> bytecode;
1699     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS) << ss.str();
1700 
1701     auto f = CreateFrame(16, nullptr, nullptr);
1702     InitializeFrame(f.get());
1703 
1704     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1705     auto method_data = CreateMethod(cls, f.get(), bytecode);
1706     auto method = std::move(method_data.first);
1707     f->SetMethod(method.get());
1708 
1709     pandasm::Parser p;
1710     std::string source;
1711 
1712     if (is_static) {
1713         source = R"(
1714             .record R {
1715                 R sf_ref <static>
1716             }
1717         )";
1718     } else {
1719         source = R"(
1720             .record R {
1721                 R sf_ref
1722             }
1723         )";
1724     }
1725 
1726     auto res = p.Parse(source);
1727     auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1728 
1729     auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1730     ASSERT_NE(class_linker, nullptr) << ss.str();
1731 
1732     class_linker->AddPandaFile(std::move(class_pf));
1733 
1734     PandaString descriptor;
1735 
1736     auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1737     Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1738     ASSERT_TRUE(class_linker->InitializeClass(ManagedThread::GetCurrent(), object_class)) << ss.str();
1739 
1740     ObjectHeader *obj = nullptr;
1741 
1742     auto frame_handler = StaticFrameHandler(f.get());
1743     if (!is_static) {
1744         obj = AllocObject(object_class);
1745         frame_handler.GetVReg(0).SetReference(obj);
1746     }
1747 
1748     Span<Field> fields = is_static ? object_class->GetStaticFields() : object_class->GetInstanceFields();
1749     Field *field = &fields[0];
1750     ObjectHeader *ref_value = panda::mem::AllocateNullifiedPayloadString(1);
1751 
1752     frame_handler.GetVReg(2).SetReference(ref_value);
1753 
1754     RuntimeInterface::SetupResolvedField(field);
1755 
1756     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1757 
1758     RuntimeInterface::SetupResolvedField(nullptr);
1759 
1760     EXPECT_EQ(f->GetAccAsVReg().GetReference(), ref_value) << ss.str();
1761     EXPECT_EQ(frame_handler.GetVReg(1).GetReference(), nullptr) << ss.str();
1762 }
1763 
TEST_F(InterpreterTest,TestLoadStoreField)1764 TEST_F(InterpreterTest, TestLoadStoreField)
1765 {
1766     TestLoadStoreField(false);
1767     TestLoadStoreObjectField(false);
1768 }
1769 
TEST_F(InterpreterTest,TestLoadStoreStaticField)1770 TEST_F(InterpreterTest, TestLoadStoreStaticField)
1771 {
1772     TestLoadStoreField(true);
1773     TestLoadStoreObjectField(true);
1774 }
1775 
TEST_F(InterpreterTest,TestReturns)1776 TEST_F(InterpreterTest, TestReturns)
1777 {
1778     int64_t value = 0xaabbccdd11223344;
1779 
1780     {
1781         BytecodeEmitter emitter;
1782 
1783         emitter.Return();
1784 
1785         std::vector<uint8_t> bytecode;
1786         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1787 
1788         auto f = CreateFrame(16, nullptr, nullptr);
1789         InitializeFrame(f.get());
1790 
1791         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1792         auto method_data = CreateMethod(cls, f.get(), bytecode);
1793         auto method = std::move(method_data.first);
1794         f->SetMethod(method.get());
1795 
1796         f->GetAccAsVReg().SetPrimitive(value);
1797 
1798         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1799 
1800         EXPECT_EQ(f->GetAccAsVReg().Get(), static_cast<int32_t>(value));
1801         EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1802     }
1803 
1804     {
1805         BytecodeEmitter emitter;
1806 
1807         emitter.ReturnWide();
1808 
1809         std::vector<uint8_t> bytecode;
1810         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1811 
1812         auto f = CreateFrame(16, nullptr, nullptr);
1813         InitializeFrame(f.get());
1814 
1815         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1816         auto method_data = CreateMethod(cls, f.get(), bytecode);
1817         auto method = std::move(method_data.first);
1818         f->SetMethod(method.get());
1819 
1820         f->GetAccAsVReg().SetPrimitive(value);
1821 
1822         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1823 
1824         EXPECT_EQ(f->GetAccAsVReg().GetLong(), value);
1825         EXPECT_FALSE(f->GetAccAsVReg().HasObject());
1826     }
1827 
1828     {
1829         BytecodeEmitter emitter;
1830 
1831         emitter.ReturnObj();
1832 
1833         std::vector<uint8_t> bytecode;
1834         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1835 
1836         auto f = CreateFrame(16, nullptr, nullptr);
1837         InitializeFrame(f.get());
1838 
1839         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1840         auto method_data = CreateMethod(cls, f.get(), bytecode);
1841         auto method = std::move(method_data.first);
1842         f->SetMethod(method.get());
1843 
1844         ObjectHeader *obj = panda::mem::AllocateNullifiedPayloadString(1);
1845         f->GetAccAsVReg().SetReference(obj);
1846 
1847         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1848 
1849         EXPECT_EQ(f->GetAccAsVReg().GetReference(), obj);
1850         EXPECT_TRUE(f->GetAccAsVReg().HasObject());
1851     }
1852 }
1853 
TEST_F(InterpreterTest,TestIsInstance)1854 TEST_F(InterpreterTest, TestIsInstance)
1855 {
1856     {
1857         BytecodeEmitter emitter;
1858         emitter.Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
1859         emitter.Return();
1860 
1861         std::vector<uint8_t> bytecode;
1862         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1863 
1864         auto f = CreateFrame(16, nullptr, nullptr);
1865         InitializeFrame(f.get());
1866         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1867         auto method_data = CreateMethod(cls, f.get(), bytecode);
1868         auto method = std::move(method_data.first);
1869         f->SetMethod(method.get());
1870 
1871         pandasm::Parser p;
1872         auto source = R"(
1873             .record R {}
1874         )";
1875 
1876         auto res = p.Parse(source);
1877         auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1878 
1879         auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1880         ASSERT_NE(class_linker, nullptr);
1881 
1882         class_linker->AddPandaFile(std::move(class_pf));
1883 
1884         PandaString descriptor;
1885         auto *thread = ManagedThread::GetCurrent();
1886         auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1887         Class *object_class = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("R"), &descriptor));
1888         ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1889 
1890         f->GetAccAsVReg().SetReference(nullptr);
1891 
1892         RuntimeInterface::SetupResolvedClass(object_class);
1893 
1894         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1895 
1896         RuntimeInterface::SetupResolvedClass(nullptr);
1897 
1898         ASSERT_EQ(f->GetAccAsVReg().Get(), 0);
1899     }
1900 
1901     {
1902         BytecodeEmitter emitter;
1903         emitter.Isinstance(RuntimeInterface::TYPE_ID.AsIndex());
1904         emitter.Return();
1905 
1906         std::vector<uint8_t> bytecode;
1907         ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
1908 
1909         auto f = CreateFrame(16, nullptr, nullptr);
1910         InitializeFrame(f.get());
1911         auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
1912         auto method_data = CreateMethod(cls, f.get(), bytecode);
1913         auto method = std::move(method_data.first);
1914         f->SetMethod(method.get());
1915 
1916         pandasm::Parser p;
1917         auto source = R"(
1918             .record R {}
1919         )";
1920 
1921         auto res = p.Parse(source);
1922         auto class_pf = pandasm::AsmEmitter::Emit(res.Value());
1923 
1924         auto class_linker = CreateClassLinker(ManagedThread::GetCurrent());
1925         ASSERT_NE(class_linker, nullptr);
1926 
1927         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
1928 
1929         class_linker->AddPandaFile(std::move(class_pf));
1930 
1931         PandaString descriptor;
1932         auto *thread = ManagedThread::GetCurrent();
1933         auto *ext = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
1934         auto *object_class = ext->GetClass(ClassHelper::GetArrayDescriptor(utf::CStringAsMutf8("R"), 2, &descriptor));
1935         ASSERT_TRUE(class_linker->InitializeClass(thread, object_class));
1936 
1937         auto *obj = AllocArray(object_class, sizeof(uint8_t), 0);
1938 
1939         f->GetAccAsVReg().SetReference(obj);
1940 
1941         auto *dst_class = class_linker->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
1942         ASSERT_TRUE(class_linker->InitializeClass(thread, dst_class));
1943         RuntimeInterface::SetupResolvedClass(dst_class);
1944 
1945         Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
1946 
1947         RuntimeInterface::SetupResolvedClass(nullptr);
1948 
1949         ASSERT_EQ(f->GetAccAsVReg().Get(), 1);
1950     }
1951 }
1952 
MakeShorty(size_t num_args,std::vector<uint16_t> * buf)1953 static void MakeShorty(size_t num_args, std::vector<uint16_t> *buf)
1954 {
1955     static constexpr uint8_t I64 = static_cast<uint8_t>(panda_file::Type::TypeId::I64);
1956     static constexpr size_t ELEM_SIZE = 4;
1957     static constexpr size_t ELEM_COUNT = std::numeric_limits<uint16_t>::digits / ELEM_SIZE;
1958 
1959     uint16_t val = 0;
1960     uint32_t count = 1;
1961     ++num_args;  // consider the return value
1962     while (num_args > 0) {
1963         if (count == ELEM_COUNT) {
1964             buf->push_back(val);
1965             val = 0;
1966             count = 0;
1967         }
1968         val |= I64 << ELEM_SIZE * count;
1969         ++count;
1970         --num_args;
1971     }
1972     if (count == ELEM_COUNT) {
1973         buf->push_back(val);
1974         val = 0;
1975     }
1976     buf->push_back(val);
1977 }
1978 
1979 template <bool is_dynamic = false>
CreateResolvedMethod(Class * klass,size_t vreg_num,const std::vector<int64_t> args,std::vector<uint8_t> * bytecode,std::vector<uint16_t> * shorty_buf)1980 static std::pair<PandaUniquePtr<Method>, std::unique_ptr<const panda_file::File>> CreateResolvedMethod(
1981     Class *klass, size_t vreg_num, const std::vector<int64_t> args, std::vector<uint8_t> *bytecode,
1982     std::vector<uint16_t> *shorty_buf)
1983 {
1984     BytecodeEmitter emitter;
1985     Label label = emitter.CreateLabel();
1986 
1987     size_t start_idx = 0;
1988     if constexpr (is_dynamic) {
1989         ++start_idx;  // skip function object
1990     }
1991     for (size_t i = start_idx; i < args.size(); i++) {
1992         emitter.LdaiWide(args[i]);
1993         emitter.Jne(vreg_num + i, label);
1994     }
1995 
1996     emitter.LdaiWide(1);
1997     emitter.ReturnWide();
1998     emitter.Bind(label);
1999     emitter.LdaiWide(0);
2000     emitter.ReturnWide();
2001 
2002     [[maybe_unused]] auto res = emitter.Build(&*bytecode);
2003 
2004     ASSERT(res == BytecodeEmitter::ErrorCode::SUCCESS);
2005 
2006     MakeShorty(args.size(), shorty_buf);
2007 
2008     return CreateMethod(klass, 0, args.size(), vreg_num, shorty_buf->data(), *bytecode);
2009 }
2010 
EntryPoint(CompilerInterface::ExecState * state)2011 CompilerInterface::ReturnReason EntryPoint(CompilerInterface::ExecState *state)
2012 {
2013     ASSERT(state->GetNumArgs() == 2);
2014 
2015     ASSERT(state->GetFrame()->GetSize() == 16);
2016 
2017     [[maybe_unused]] auto frame_handler = StaticFrameHandler(state->GetFrame());
2018     ASSERT(frame_handler.GetVReg(1).GetLong() == 1);
2019     ASSERT(frame_handler.GetVReg(3).GetLong() == 2);
2020 
2021     ASSERT(frame_handler.GetVReg(2).GetLong() == 3);
2022     ASSERT(frame_handler.GetVReg(4).GetLong() == 4);
2023 
2024     int64_t v = 100 + state->GetArg(0).GetLong() + state->GetArg(1).GetLong();
2025     interpreter::VRegister acc;
2026     acc.Set(0);
2027     acc.Set(v);
2028     state->SetAcc(acc);
2029     state->SetPc(state->GetPc() + 1);
2030 
2031     return CompilerInterface::ReturnReason::RET_OK;
2032 }
2033 
2034 // TODO (Baladurin, Udovichenko) change for new interop
TEST_F(InterpreterTest,DISABLED_TestCallNative)2035 TEST_F(InterpreterTest, DISABLED_TestCallNative)
2036 {
2037     size_t vreg_num = 10;
2038 
2039     BytecodeEmitter emitter;
2040 
2041     // first call hotness_counter is 0
2042     emitter.CallShort(1, 3, RuntimeInterface::METHOD_ID.AsIndex());
2043     emitter.StaWide(5);
2044     // second call hotness counter is 1 -> native call
2045     emitter.CallShort(5, 6, RuntimeInterface::METHOD_ID.AsIndex());
2046     // native call skips this return
2047     emitter.ReturnWide();
2048     emitter.Addi(1);
2049     emitter.ReturnWide();
2050 
2051     std::vector<uint8_t> bytecode;
2052     ASSERT_EQ(emitter.Build(&bytecode), BytecodeEmitter::ErrorCode::SUCCESS);
2053 
2054     auto f = CreateFrame(16, nullptr, nullptr);
2055     InitializeFrame(f.get());
2056 
2057     auto frame_handler = StaticFrameHandler(f.get());
2058     std::vector<int64_t> args1 = {1, 2};
2059     frame_handler.GetVReg(1).SetPrimitive(args1[0]);
2060     frame_handler.GetVReg(3).SetPrimitive(args1[1]);
2061 
2062     std::vector<int64_t> args2 = {3, 4};
2063     frame_handler.GetVReg(2).SetPrimitive(args2[0]);
2064     frame_handler.GetVReg(4).SetPrimitive(args2[1]);
2065 
2066     auto cls = CreateClass(panda_file::SourceLang::PANDA_ASSEMBLY);
2067     auto method_data = CreateMethod(cls, f.get(), bytecode);
2068     auto method = std::move(method_data.first);
2069     f->SetMethod(method.get());
2070 
2071     std::vector<uint16_t> shorty_buf;
2072     std::vector<uint8_t> method_bytecode;
2073     auto resolved_method_data = CreateResolvedMethod(cls, vreg_num, args1, &method_bytecode, &shorty_buf);
2074     auto resolved_method = std::move(resolved_method_data.first);
2075 
2076     RuntimeInterface::SetCompilerHotnessThreshold(1);
2077 
2078     RuntimeInterface::SetupNativeEntryPoint(reinterpret_cast<const void *>(EntryPoint));
2079 
2080     RuntimeInterface::SetupResolvedMethod(resolved_method.get());
2081 
2082     Execute(ManagedThread::GetCurrent(), bytecode.data(), f.get());
2083 
2084     RuntimeInterface::SetupResolvedMethod(nullptr);
2085 
2086     EXPECT_EQ(f->GetAccAsVReg().GetLong(), 102);
2087 }
2088 
2089 }  // namespace test
2090 }  // namespace panda::interpreter
2091