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