• 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 
25 namespace panda {
26 
27 using compiler::CodeInfo;
28 using compiler::VRegInfo;
29 
UnpoisonAsanStack(void * ptr)30 static void UnpoisonAsanStack([[maybe_unused]] void *ptr)
31 {
32 #ifdef PANDA_ASAN_ON
33     uint8_t sp;
34     ASAN_UNPOISON_MEMORY_REGION(&sp, reinterpret_cast<uint8_t *>(ptr) - &sp);
35 #endif  // PANDA_ASAN_ON
36 }
37 
38 #if EVENT_OSR_ENTRY_ENABLED
WriteOsrEventError(Frame * frame,FrameKind kind,uintptr_t loop_head_bc)39 void WriteOsrEventError(Frame *frame, FrameKind kind, uintptr_t loop_head_bc)
40 {
41     events::OsrEntryKind osr_kind;
42     switch (kind) {
43         case FrameKind::INTERPRETER:
44             osr_kind = events::OsrEntryKind::AFTER_IFRAME;
45             break;
46         case FrameKind::COMPILER:
47             osr_kind = events::OsrEntryKind::AFTER_CFRAME;
48             break;
49         case FrameKind::NONE:
50             osr_kind = events::OsrEntryKind::TOP_FRAME;
51             break;
52         default:
53             UNREACHABLE();
54     }
55     EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loop_head_bc, osr_kind,
56                     events::OsrEntryResult::ERROR);
57 }
58 #endif  // EVENT_OSR_ENTRY_ENABLED
59 
OsrEntry(uintptr_t loop_head_bc,const void * osr_code)60 bool OsrEntry(uintptr_t loop_head_bc, const void *osr_code)
61 {
62     auto stack = StackWalker::Create(ManagedThread::GetCurrent());
63     Frame *frame = stack.GetIFrame();
64     LOG(DEBUG, INTEROP) << "OSR entry in method '" << stack.GetMethod()->GetFullName() << "': " << osr_code;
65     CodeInfo code_info(CodeInfo::GetCodeOriginFromEntryPoint(osr_code));
66     auto stackmap = code_info.FindOsrStackMap(loop_head_bc);
67     if (!stackmap.IsValid()) {
68 #if EVENT_OSR_ENTRY_ENABLED
69         WriteOsrEventError(frame, stack.GetPreviousFrameKind(), loop_head_bc);
70 #endif  // EVENT_OSR_ENTRY_ENABLED
71         return false;
72     }
73 
74     switch (stack.GetPreviousFrameKind()) {
75         case FrameKind::INTERPRETER:
76             LOG(DEBUG, INTEROP) << "OSR: after interpreter frame";
77             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loop_head_bc,
78                             events::OsrEntryKind::AFTER_IFRAME, events::OsrEntryResult::SUCCESS);
79             OsrEntryAfterIFrame(frame, loop_head_bc, osr_code, code_info.GetFrameSize());
80             break;
81         case FrameKind::COMPILER:
82             UnpoisonAsanStack(frame->GetPrevFrame());
83             LOG(DEBUG, INTEROP) << "OSR: after compiled frame";
84             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loop_head_bc,
85                             events::OsrEntryKind::AFTER_CFRAME, events::OsrEntryResult::SUCCESS);
86             OsrEntryAfterCFrame(frame, loop_head_bc, osr_code, code_info.GetFrameSize());
87             UNREACHABLE();
88             break;
89         case FrameKind::NONE:
90             LOG(DEBUG, INTEROP) << "OSR: after no frame";
91             EVENT_OSR_ENTRY(std::string(frame->GetMethod()->GetFullName()), loop_head_bc,
92                             events::OsrEntryKind::TOP_FRAME, events::OsrEntryResult::SUCCESS);
93             OsrEntryTopFrame(frame, loop_head_bc, osr_code, code_info.GetFrameSize());
94             break;
95         default:
96             break;
97     }
98     return true;
99 }
100 
PrepareOsrEntry(const Frame * iframe,uintptr_t bc_offset,const void * osr_code,void * cframe_ptr,uintptr_t * reg_buffer,uintptr_t * fp_reg_buffer)101 extern "C" void *PrepareOsrEntry(const Frame *iframe, uintptr_t bc_offset, const void *osr_code, void *cframe_ptr,
102                                  uintptr_t *reg_buffer, uintptr_t *fp_reg_buffer)
103 {
104     CodeInfo code_info(CodeInfo::GetCodeOriginFromEntryPoint(osr_code));
105     CFrame cframe(cframe_ptr);
106     auto stackmap = code_info.FindOsrStackMap(bc_offset);
107 
108     ASSERT(stackmap.IsValid() && osr_code != nullptr);
109 
110     cframe.SetMethod(iframe->GetMethod());
111     cframe.SetFrameKind(CFrameLayout::FrameKind::OSR);
112     cframe.SetHasFloatRegs(code_info.HasFloatRegs());
113 
114     for (auto vreg : code_info.GetVRegList(stackmap, mem::InternalAllocator<>::GetInternalAllocatorFromRuntime())) {
115         int64_t value =
116             vreg.IsAccumulator() ? iframe->GetAcc().GetValue() : iframe->GetVReg(vreg.GetIndex()).GetValue();
117         if (!vreg.IsLive()) {
118             continue;
119         }
120         switch (vreg.GetLocation()) {
121             case VRegInfo::Location::SLOT:
122                 cframe.SetVRegValue(vreg, value, nullptr);
123                 break;
124             case VRegInfo::Location::REGISTER:
125                 reg_buffer[vreg.GetValue()] = value;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
126                 break;
127             case VRegInfo::Location::FP_REGISTER:
128                 fp_reg_buffer[vreg.GetValue()] = value;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
129                 break;
130             // NOLINTNEXTLINE(bugprone-branch-clone)
131             case VRegInfo::Location::CONSTANT:
132                 break;
133             default:
134                 break;
135         }
136     }
137     auto *thread = ManagedThread::GetCurrent();
138     ASSERT(thread != nullptr);
139     thread->SetCurrentFrame(reinterpret_cast<Frame *>(cframe_ptr));
140     thread->SetCurrentFrameIsCompiled(true);
141 
142     return bit_cast<void *>(bit_cast<uintptr_t>(osr_code) + stackmap.GetNativePcUnpacked());
143 }
144 
SetOsrResult(Frame * frame,uint64_t uval,double fval)145 extern "C" void SetOsrResult(Frame *frame, uint64_t uval, double fval)
146 {
147     ASSERT(frame != nullptr);
148     panda_file::ShortyIterator it(frame->GetMethod()->GetShorty());
149     using panda_file::Type;
150     auto &acc = frame->GetAcc();
151 
152     switch ((*it).GetId()) {
153         case Type::TypeId::U1:
154         case Type::TypeId::I8:
155         case Type::TypeId::U8:
156         case Type::TypeId::I16:
157         case Type::TypeId::U16:
158         case Type::TypeId::I32:
159         case Type::TypeId::U32:
160         case Type::TypeId::I64:
161         case Type::TypeId::U64:
162             acc.SetValue(uval);
163             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
164             break;
165         case Type::TypeId::REFERENCE:
166             acc.SetValue(uval);
167             acc.SetTag(interpreter::StaticVRegisterRef::GC_OBJECT_TYPE);
168             break;
169         case Type::TypeId::F32:
170         case Type::TypeId::F64:
171             acc.SetValue(bit_cast<int64_t>(fval));
172             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
173             break;
174         case Type::TypeId::VOID:
175             // Interpreter always restores accumulator from the callee method, even if callee method is void. Thus, we
176             // need to reset it here, otherwise it can hold old object, that probably isn't live already.
177             acc.SetValue(0);
178             acc.SetTag(interpreter::StaticVRegisterRef::PRIMITIVE_TYPE);
179             break;
180         case Type::TypeId::TAGGED:
181         case Type::TypeId::INVALID:
182             UNREACHABLE();
183         default:
184             UNREACHABLE();
185     }
186 }
187 
188 }  // namespace panda
189