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