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