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