• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "assembler/assembly-parser.h"
20 #include "bytecode_instruction.h"
21 #include "include/thread_scopes.h"
22 #include "libpandafile/bytecode_instruction-inl.h"
23 #include "runtime/include/managed_thread.h"
24 #include "runtime/include/runtime.h"
25 #include "runtime/include/runtime_notification.h"
26 #include "runtime/interpreter/runtime_interface.h"
27 
28 namespace ark::interpreter::test {
29 
30 class InterpreterTestSwitch : public testing::Test {
31 public:
InterpreterTestSwitch()32     InterpreterTestSwitch()
33     {
34         RuntimeOptions options;
35         options.SetShouldLoadBootPandaFiles(false);
36         options.SetShouldInitializeIntrinsics(false);
37         options.SetRunGcInPlace(true);
38         options.SetVerifyCallStack(false);
39         options.SetInterpreterType("cpp");
40         Runtime::Create(options);
41     }
42 
~InterpreterTestSwitch()43     ~InterpreterTestSwitch() override
44     {
45         Runtime::Destroy();
46     }
47 
48     NO_COPY_SEMANTIC(InterpreterTestSwitch);
49     NO_MOVE_SEMANTIC(InterpreterTestSwitch);
50 };
51 
52 constexpr int32_t RET = 10;
53 
EntryPoint(Method *)54 static int32_t EntryPoint(Method * /* unused */)
55 {
56     auto *thread = ManagedThread::GetCurrent();
57     thread->SetCurrentDispatchTable<false>(thread->GetDebugDispatchTable());
58     return RET;
59 }
60 
61 class SwitchToDebugListener : public RuntimeListener {
62 public:
63     struct Event {
64         ManagedThread *thread;
65         Method *method;
66         uint32_t bcOffset;
67     };
68 
BytecodePcChanged(ManagedThread * thread,Method * method,uint32_t bcOffset)69     void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override
70     {
71         events_.push_back({thread, method, bcOffset});
72     }
73 
GetEvents() const74     auto &GetEvents() const
75     {
76         return events_;
77     }
78 
79 private:
80     std::vector<Event> events_ {};
81 };
82 
83 static auto g_switchToDebugSource = R"(
84     .function i32 f() {
85         ldai 10
86         return
87     }
88 
89     .function i32 g() {
90         call f
91         return
92     }
93 
94     .function i32 main() {
95         call g
96         return
97     }
98 )";
99 
TEST_F(InterpreterTestSwitch,SwitchToDebug)100 TEST_F(InterpreterTestSwitch, SwitchToDebug)
101 {
102     pandasm::Parser p;
103 
104     auto source = g_switchToDebugSource;
105 
106     auto res = p.Parse(source);
107     auto pf = pandasm::AsmEmitter::Emit(res.Value());
108     ASSERT_NE(pf, nullptr);
109 
110     ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
111     classLinker->AddPandaFile(std::move(pf));
112     auto *extension = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
113 
114     SwitchToDebugListener listener {};
115 
116     auto *notificationManager = Runtime::GetCurrent()->GetNotificationManager();
117     notificationManager->AddListener(&listener, RuntimeNotificationManager::BYTECODE_PC_CHANGED);
118 
119     std::vector<Value> args;
120     Value v;
121     Method *mainMethod;
122 
123     auto *thread = ManagedThread::GetCurrent();
124 
125     {
126         ScopedManagedCodeThread smc(thread);
127         PandaString descriptor;
128 
129         Class *klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
130         ASSERT_NE(klass, nullptr);
131 
132         mainMethod = klass->GetDirectMethod(utf::CStringAsMutf8("main"));
133         ASSERT_NE(mainMethod, nullptr);
134 
135         Method *fMethod = klass->GetDirectMethod(utf::CStringAsMutf8("f"));
136         ASSERT_NE(fMethod, nullptr);
137 
138         fMethod->SetCompiledEntryPoint(reinterpret_cast<const void *>(EntryPoint));
139 
140         v = mainMethod->Invoke(thread, args.data());
141     }
142 
143     notificationManager->RemoveListener(&listener, RuntimeNotificationManager::BYTECODE_PC_CHANGED);
144 
145     ASSERT_EQ(v.GetAs<int32_t>(), RET);
146     ASSERT_EQ(listener.GetEvents().size(), 1U);
147 
148     auto &event = listener.GetEvents()[0];
149     EXPECT_EQ(event.thread, thread);
150     EXPECT_EQ(event.method, mainMethod);
151     EXPECT_EQ(event.bcOffset, BytecodeInstruction::Size(BytecodeInstruction::Format::V4_V4_ID16));
152 }
153 
154 }  // namespace ark::interpreter::test
155