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