• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "runtime/osr.h"
17 
18 #include "libpandabase/events/events.h"
19 #include "libpandafile/shorty_iterator.h"
20 #include "runtime/include/managed_thread.h"
21 #include "runtime/include/method.h"
22 #include "runtime/include/stack_walker.h"
23 #include "code_info/code_info.h"
24 #include "runtime/include/panda_vm.h"
25 #include "compiler/optimizer/ir/runtime_interface.h"
26 
27 namespace panda {
28 
29 using compiler::CodeInfo;
30 using compiler::VRegInfo;
31 
UnpoisonAsanStack(void * ptr)32 static void UnpoisonAsanStack([[maybe_unused]] void *ptr)
33 {
34 #ifdef PANDA_ASAN_ON
35     uint8_t sp;
36     ASAN_UNPOISON_MEMORY_REGION(&sp, reinterpret_cast<uint8_t *>(ptr) - &sp);
37 #endif  // PANDA_ASAN_ON
38 }
39 
40 #if EVENT_OSR_ENTRY_ENABLED
WriteOsrEventError(Frame * frame,FrameKind kind,uintptr_t loopHeadBc)41 void WriteOsrEventError(Frame *frame, FrameKind kind, uintptr_t loopHeadBc)
42 {
43     events::OsrEntryKind osrKind;
44     switch (kind) {
45         case FrameKind::INTERPRETER:
46             osrKind = events::OsrEntryKind::AFTER_IFRAME;
47             break;
48         case FrameKind::COMPILER:
49             osrKind = events::OsrEntryKind::AFTER_CFRAME;
50             break;
51         case FrameKind::NONE:
52             osrKind = events::OsrEntryKind::TOP_FRAME;
53             break;
54         default:
55             UNREACHABLE();
56     }
57     EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loopHeadBc, osrKind, events::OsrEntryResult::ERROR);
58 }
59 #endif  // EVENT_OSR_ENTRY_ENABLED
60 
61 static size_t GetStackParamsSize(const Frame *frame);
62 
OsrEntry(uintptr_t loopHeadBc,const void * osrCode)63 bool OsrEntry(uintptr_t loopHeadBc, const void *osrCode)
64 {
65     auto stack = StackWalker::Create(ManagedThread::GetCurrent());
66     Frame *frame = stack.GetIFrame();
67     LOG(DEBUG, INTEROP) << "OSR entry in method '" << stack.GetMethod()->GetFullName() << "': " << osrCode;
68     CodeInfo codeInfo(CodeInfo::GetCodeOriginFromEntryPoint(osrCode));
69     auto stackmap = codeInfo.FindOsrStackMap(loopHeadBc);
70     if (!stackmap.IsValid()) {
71 #if EVENT_OSR_ENTRY_ENABLED
72         WriteOsrEventError(frame, stack.GetPreviousFrameKind(), loopHeadBc);
73 #endif  // EVENT_OSR_ENTRY_ENABLED
74         return false;
75     }
76 
77     switch (stack.GetPreviousFrameKind()) {
78         case FrameKind::INTERPRETER:
79             LOG(DEBUG, INTEROP) << "OSR: after interpreter frame";
80             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loopHeadBc,
81                             events::OsrEntryKind::AFTER_IFRAME, events::OsrEntryResult::SUCCESS);
82             OsrEntryAfterIFrame(frame, loopHeadBc, osrCode, codeInfo.GetFrameSize(), GetStackParamsSize(frame));
83             break;
84         case FrameKind::COMPILER:
85             if (frame->IsDynamic() && frame->GetNumActualArgs() < frame->GetMethod()->GetNumArgs()) {
86                 frame->DisableOsr();
87                 // We need to adjust slot arguments space from previous compiled frame.
88 #if EVENT_OSR_ENTRY_ENABLED
89                 WriteOsrEventError(frame, stack.GetPreviousFrameKind(), loopHeadBc);
90 #endif  // EVENT_OSR_ENTRY_ENABLED
91                 LOG(DEBUG, INTEROP) << "OSR: after compiled frame, fail: num_actual_args < num_args";
92                 return false;
93             }
94             UnpoisonAsanStack(frame->GetPrevFrame());
95             LOG(DEBUG, INTEROP) << "OSR: after compiled frame";
96             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loopHeadBc,
97                             events::OsrEntryKind::AFTER_CFRAME, events::OsrEntryResult::SUCCESS);
98             OsrEntryAfterCFrame(frame, loopHeadBc, osrCode, codeInfo.GetFrameSize());
99             UNREACHABLE();
100             break;
101         case FrameKind::NONE:
102             LOG(DEBUG, INTEROP) << "OSR: after no frame";
103             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loopHeadBc, events::OsrEntryKind::TOP_FRAME,
104                             events::OsrEntryResult::SUCCESS);
105             OsrEntryTopFrame(frame, loopHeadBc, osrCode, codeInfo.GetFrameSize(), GetStackParamsSize(frame));
106             break;
107         default:
108             break;
109     }
110     return true;
111 }
112 
PrepareOsrEntry(const Frame * iframe,uintptr_t bcOffset,const void * osrCode,void * cframePtr,uintptr_t * regBuffer,uintptr_t * fpRegBuffer)113 extern "C" void *PrepareOsrEntry(const Frame *iframe, uintptr_t bcOffset, const void *osrCode, void *cframePtr,
114                                  uintptr_t *regBuffer, uintptr_t *fpRegBuffer)
115 {
116     CodeInfo codeInfo(CodeInfo::GetCodeOriginFromEntryPoint(osrCode));
117     CFrame cframe(cframePtr);
118     auto stackmap = codeInfo.FindOsrStackMap(bcOffset);
119 
120     ASSERT(stackmap.IsValid() && osrCode != nullptr);
121 
122     cframe.SetMethod(iframe->GetMethod());
123     cframe.SetFrameKind(CFrameLayout::FrameKind::OSR);
124     cframe.SetHasFloatRegs(codeInfo.HasFloatRegs());
125 
126     auto *thread {ManagedThread::GetCurrent()};
127     ASSERT(thread != nullptr);
128 
129     auto *vm {thread->GetVM()};
130 
131     auto numSlots {[](size_t bytes) -> size_t {
132         ASSERT(IsAligned(bytes, ArchTraits<RUNTIME_ARCH>::POINTER_SIZE));
133         return bytes / ArchTraits<RUNTIME_ARCH>::POINTER_SIZE;
134     }};
135 
136     Span paramSlots(reinterpret_cast<uintptr_t *>(cframe.GetStackArgsStart()), numSlots(GetStackParamsSize(iframe)));
137 
138     auto ctx {vm->GetLanguageContext()};
139     ctx.InitializeOsrCframeSlots(paramSlots);
140 
141     for (auto vreg : codeInfo.GetVRegList(stackmap, mem::InternalAllocator<>::GetInternalAllocatorFromRuntime())) {
142         if (!vreg.IsLive()) {
143             continue;
144         }
145         int64_t value = 0;
146         if (vreg.IsAccumulator()) {
147             value = iframe->GetAcc().GetValue();
148         } else if (!vreg.IsSpecialVReg()) {
149             ASSERT(vreg.GetVRegType() == VRegInfo::VRegType::VREG);
150             value = iframe->GetVReg(vreg.GetIndex()).GetValue();
151         } else {
152             value = ctx.GetOsrEnv(iframe, vreg);
153         }
154 #ifdef PANDA_USE_32_BIT_POINTER
155         if (vreg.IsObject()) {
156             value = static_cast<int32_t>(value);
157         }
158 #endif
159         switch (vreg.GetLocation()) {
160             case VRegInfo::Location::SLOT:
161                 cframe.SetVRegValue(vreg, value, nullptr);
162                 break;
163             case VRegInfo::Location::REGISTER:
164                 regBuffer[vreg.GetValue()] = value;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
165                 break;
166             case VRegInfo::Location::FP_REGISTER:
167                 fpRegBuffer[vreg.GetValue()] = value;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
168                 break;
169             // NOLINTNEXTLINE(bugprone-branch-clone)
170             case VRegInfo::Location::CONSTANT:
171                 break;
172             default:
173                 break;
174         }
175     }
176 
177     thread->SetCurrentFrame(reinterpret_cast<Frame *>(cframePtr));
178     thread->SetCurrentFrameIsCompiled(true);
179 
180     return bit_cast<void *>(bit_cast<uintptr_t>(osrCode) + stackmap.GetNativePcUnpacked());
181 }
182 
SetOsrResult(Frame * frame,uint64_t uval,double fval)183 extern "C" void SetOsrResult(Frame *frame, uint64_t uval, double fval)
184 {
185     ASSERT(frame != nullptr);
186     panda_file::ShortyIterator it(frame->GetMethod()->GetShorty());
187     using panda_file::Type;
188     auto &acc = frame->GetAcc();
189 
190     switch ((*it).GetId()) {
191         case Type::TypeId::U1:
192         case Type::TypeId::I8:
193         case Type::TypeId::U8:
194         case Type::TypeId::I16:
195         case Type::TypeId::U16:
196         case Type::TypeId::I32:
197         case Type::TypeId::U32:
198         case Type::TypeId::I64:
199         case Type::TypeId::U64:
200             acc.SetValue(uval);
201             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
202             break;
203         case Type::TypeId::REFERENCE:
204             acc.SetValue(uval);
205             acc.SetTag(interpreter::StaticVRegisterRef::GC_OBJECT_TYPE);
206             break;
207         case Type::TypeId::F32:
208         case Type::TypeId::F64:
209             acc.SetValue(bit_cast<int64_t>(fval));
210             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
211             break;
212         case Type::TypeId::VOID:
213             // Interpreter always restores accumulator from the callee method, even if callee method is void. Thus, we
214             // need to reset it here, otherwise it can hold old object, that probably isn't live already.
215             acc.SetValue(0);
216             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
217             break;
218         case Type::TypeId::TAGGED:
219             acc.SetValue(uval);
220             break;
221         case Type::TypeId::INVALID:
222             UNREACHABLE();
223         default:
224             UNREACHABLE();
225     }
226 }
227 
GetStackParamsSize(const Frame * frame)228 static size_t GetStackParamsSize(const Frame *frame)
229 {
230     constexpr auto SLOT_SIZE {ArchTraits<RUNTIME_ARCH>::POINTER_SIZE};
231     auto *method {frame->GetMethod()};
232     if (frame->IsDynamic()) {
233         auto numArgs {std::max(method->GetNumArgs(), frame->GetNumActualArgs())};
234         auto argSize {std::max(sizeof(coretypes::TaggedType), SLOT_SIZE)};
235         return RoundUp(numArgs * argSize, 2U * SLOT_SIZE);
236     }
237 
238     arch::ArgCounter<RUNTIME_ARCH> counter;
239     counter.Count<Method *>();
240     if (!method->IsStatic()) {
241         counter.Count<ObjectHeader *>();
242     }
243     panda_file::ShortyIterator it(method->GetShorty());
244     ++it;  // skip return type
245     while (it != panda_file::ShortyIterator()) {
246         switch ((*it).GetId()) {
247             case panda_file::Type::TypeId::U1:
248             case panda_file::Type::TypeId::U8:
249             case panda_file::Type::TypeId::I8:
250             case panda_file::Type::TypeId::I16:
251             case panda_file::Type::TypeId::U16:
252             case panda_file::Type::TypeId::I32:
253             case panda_file::Type::TypeId::U32:
254                 counter.Count<int32_t>();
255                 break;
256             case panda_file::Type::TypeId::F32:
257                 counter.Count<float>();
258                 break;
259             case panda_file::Type::TypeId::F64:
260                 counter.Count<double>();
261                 break;
262             case panda_file::Type::TypeId::I64:
263             case panda_file::Type::TypeId::U64:
264                 counter.Count<int64_t>();
265                 break;
266             case panda_file::Type::TypeId::REFERENCE:
267                 counter.Count<ObjectHeader *>();
268                 break;
269             case panda_file::Type::TypeId::TAGGED:
270                 counter.Count<coretypes::TaggedType>();
271                 break;
272             default:
273                 UNREACHABLE();
274         }
275         ++it;
276     }
277     return RoundUp(counter.GetOnlyStackSize(), 2U * SLOT_SIZE);
278 }
279 
280 }  // namespace panda
281