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