1
2 /*
3 * Copyright (c) 2021 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ecmascript/interpreter/frame_handler.h"
18
19 #include "ecmascript/jspandafile/program_object.h"
20 #include "ecmascript/compiler/llvm/llvm_stackmap_parser.h"
21 #include "ecmascript/mem/heap.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/js_thread.h"
24
25 #include "libpandafile/bytecode_instruction-inl.h"
26
27 namespace panda::ecmascript {
PrevFrame()28 void FrameHandler::PrevFrame()
29 {
30 ASSERT(HasFrame());
31 auto type = GetFrameType();
32 switch (type) {
33 case FrameType::OPTIMIZED_FRAME: {
34 auto framehandle =
35 reinterpret_cast<OptimizedFrameHandler *>(this);
36 framehandle->PrevFrame();
37 break;
38 }
39 case FrameType::OPTIMIZED_ENTRY_FRAME: {
40 auto framehandle =
41 reinterpret_cast<OptimizedEntryFrameHandler *>(this);
42 framehandle->PrevFrame();
43 break;
44 }
45 case FrameType::INTERPRETER_FRAME:
46 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
47 auto framehandle =
48 reinterpret_cast<InterpretedFrameHandler *>(this);
49 framehandle->PrevFrame();
50 break;
51 }
52 case FrameType::OPTIMIZED_LEAVE_FRAME: {
53 auto framehandle =
54 reinterpret_cast<OptimizedLeaveFrameHandler *>(this);
55 framehandle->PrevFrame();
56 break;
57 }
58 default:
59 UNREACHABLE();
60 }
61 }
62
InterpretedFrameHandler(JSThread * thread)63 InterpretedFrameHandler::InterpretedFrameHandler(JSThread *thread)
64 : FrameHandler(const_cast<JSTaggedType *>(thread->GetCurrentSPFrame()))
65 {
66 }
67
PrevFrame()68 void InterpretedFrameHandler::PrevFrame()
69 {
70 ASSERT(HasFrame());
71 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
72 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
73 sp_ = frame->base.prev;
74 }
75
PrevInterpretedFrame()76 void InterpretedFrameHandler::PrevInterpretedFrame()
77 {
78 FrameHandler::PrevFrame();
79 for (; HasFrame() && !IsInterpretedFrame(); FrameHandler::PrevFrame());
80 }
81
GetPrevFrame() const82 InterpretedFrameHandler InterpretedFrameHandler::GetPrevFrame() const
83 {
84 ASSERT(HasFrame());
85 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
86 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
87 return InterpretedFrameHandler(frame->base.prev);
88 }
89
GetVRegValue(size_t index) const90 JSTaggedValue InterpretedFrameHandler::GetVRegValue(size_t index) const
91 {
92 ASSERT(HasFrame());
93 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
94 return JSTaggedValue(sp_[index]);
95 }
96
SetVRegValue(size_t index,JSTaggedValue value)97 void InterpretedFrameHandler::SetVRegValue(size_t index, JSTaggedValue value)
98 {
99 ASSERT(HasFrame());
100 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101 sp_[index] = value.GetRawData();
102 }
103
GetAcc() const104 JSTaggedValue InterpretedFrameHandler::GetAcc() const
105 {
106 ASSERT(HasFrame());
107 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
108 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
109 return frame->acc;
110 }
111
GetSize() const112 uint32_t InterpretedFrameHandler::GetSize() const
113 {
114 ASSERT(HasFrame());
115 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
116 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
117 JSTaggedType *prevSp = frame->base.prev;
118 ASSERT(prevSp != nullptr);
119 auto size = (prevSp - sp_) - FRAME_STATE_SIZE;
120 return static_cast<uint32_t>(size);
121 }
122
GetBytecodeOffset() const123 uint32_t InterpretedFrameHandler::GetBytecodeOffset() const
124 {
125 ASSERT(HasFrame());
126 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
127 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
128 JSMethod *method = ECMAObject::Cast(frame->function.GetTaggedObject())->GetCallTarget();
129 auto offset = frame->pc - method->GetBytecodeArray();
130 return static_cast<uint32_t>(offset);
131 }
132
GetMethod() const133 JSMethod *InterpretedFrameHandler::GetMethod() const
134 {
135 ASSERT(HasFrame());
136 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
137 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
138 return ECMAObject::Cast(frame->function.GetTaggedObject())->GetCallTarget();
139 }
140
GetFunction() const141 JSTaggedValue InterpretedFrameHandler::GetFunction() const
142 {
143 ASSERT(HasFrame());
144 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
145 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
146 return frame->function;
147 }
148
GetPc() const149 const uint8_t *InterpretedFrameHandler::GetPc() const
150 {
151 ASSERT(HasFrame());
152 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
153 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
154 return frame->pc;
155 }
156
GetSp() const157 JSTaggedType *InterpretedFrameHandler::GetSp() const
158 {
159 ASSERT(HasFrame());
160 return sp_;
161 }
162
GetConstpool() const163 ConstantPool *InterpretedFrameHandler::GetConstpool() const
164 {
165 ASSERT(HasFrame());
166 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
167 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
168 return ConstantPool::Cast(frame->constpool.GetTaggedObject());
169 }
170
GetEnv() const171 JSTaggedValue InterpretedFrameHandler::GetEnv() const
172 {
173 ASSERT(HasFrame());
174 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
175 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp_);
176 return frame->env;
177 }
178
Iterate(const RootVisitor & v0,const RootRangeVisitor & v1)179 void InterpretedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1)
180 {
181 JSTaggedType *current = sp_;
182 if (current != nullptr) {
183 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
184 InterpretedFrame *frame = reinterpret_cast<InterpretedFrame *>(current) - 1;
185
186 if (frame->sp != nullptr) {
187 uintptr_t start = ToUintPtr(current);
188 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
189 InterpretedFrame *prev_frame = reinterpret_cast<InterpretedFrame *>(frame->base.prev) - 1;
190 uintptr_t end = ToUintPtr(prev_frame);
191 v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end));
192 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->function)));
193 if (frame->pc != nullptr) {
194 // interpreter frame
195 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->acc)));
196 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->constpool)));
197 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->env)));
198 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->profileTypeInfo)));
199 }
200 }
201 }
202 }
203
DumpStack(std::ostream & os) const204 void InterpretedFrameHandler::DumpStack(std::ostream &os) const
205 {
206 size_t i = 0;
207 InterpretedFrameHandler frameHandler(sp_);
208 for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) {
209 os << "[" << i++
210 << "]:" << frameHandler.GetMethod()->ParseFunctionName()
211 << "\n";
212 }
213 }
214
DumpPC(std::ostream & os,const uint8_t * pc) const215 void InterpretedFrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
216 {
217 InterpretedFrameHandler frameHandler(sp_);
218 ASSERT(frameHandler.HasFrame());
219
220 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
221 int offset = pc - JSMethod::Cast(frameHandler.GetMethod())->GetBytecodeArray();
222 os << "offset: " << offset << "\n";
223 }
224
PrevFrame()225 void OptimizedFrameHandler::PrevFrame()
226 {
227 OptimizedFrame *frame = OptimizedFrame::GetFrameFromSp(sp_);
228 sp_ = reinterpret_cast<JSTaggedType *>(frame->base.prevFp);
229 }
230
Iterate(const RootVisitor & v0,const RootRangeVisitor & v1,ChunkMap<DerivedDataKey,uintptr_t> * derivedPointers,bool isVerifying) const231 void OptimizedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1,
232 ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const
233 {
234 if (sp_ != nullptr) {
235 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
236 std::set<uintptr_t> slotAddrs;
237 auto returnAddr = reinterpret_cast<uintptr_t>(*(reinterpret_cast<uintptr_t*>(sp_) + 1));
238 bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
239 returnAddr, reinterpret_cast<uintptr_t>(sp_), slotAddrs, derivedPointers, isVerifying);
240 if (ret == false) {
241 #ifndef NDEBUG
242 LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
243 #endif
244 return;
245 }
246 for (auto slot : slotAddrs) {
247 v0(Root::ROOT_FRAME, ObjectSlot(slot));
248 }
249 }
250 }
251
Iterate(const RootVisitor & v0,const RootRangeVisitor & v1,ChunkMap<DerivedDataKey,uintptr_t> * derivedPointers,bool isVerifying) const252 void OptimizedEntryFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1,
253 ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const
254 {
255 if (sp_ != nullptr) {
256 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
257 std::set<uintptr_t> slotAddrs;
258 auto returnAddr = reinterpret_cast<uintptr_t>(*(reinterpret_cast<uintptr_t*>(sp_) + 1));
259 bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
260 returnAddr, reinterpret_cast<uintptr_t>(sp_), slotAddrs, derivedPointers, isVerifying);
261 if (ret == false) {
262 #ifndef NDEBUG
263 LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
264 #endif
265 return;
266 }
267 for (auto slot : slotAddrs) {
268 v0(Root::ROOT_FRAME, ObjectSlot(slot));
269 }
270 }
271 }
272
PrevFrame()273 void OptimizedEntryFrameHandler::PrevFrame()
274 {
275 OptimizedEntryFrame *frame = OptimizedEntryFrame::GetFrameFromSp(sp_);
276 sp_ = reinterpret_cast<JSTaggedType *>(frame->preLeaveFrameFp);
277 }
278
PrevFrame()279 void OptimizedLeaveFrameHandler::PrevFrame()
280 {
281 OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(sp_);
282 sp_ = reinterpret_cast<JSTaggedType *>(frame->callsiteFp);
283 }
284
Iterate(const RootVisitor & v0,const RootRangeVisitor & v1,ChunkMap<DerivedDataKey,uintptr_t> * derivedPointers,bool isVerifying) const285 void OptimizedLeaveFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1,
286 ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const
287 {
288 OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(sp_);
289 if (frame->argc > 0) {
290 uintptr_t start = ToUintPtr(&frame->argc + 1); // argv
291 uintptr_t end = ToUintPtr(&frame->argc + 1 + frame->argc);
292 v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end));
293 }
294 std::set<uintptr_t> slotAddrs;
295 bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
296 frame, slotAddrs, derivedPointers, isVerifying);
297 if (ret == false) {
298 #ifndef NDEBUG
299 LOG_ECMA(DEBUG) << " stackmap don't found patchPointId " << frame->argPatchId;
300 #endif
301 return;
302 }
303 for (auto slot : slotAddrs) {
304 v0(Root::ROOT_FRAME, ObjectSlot(slot));
305 }
306 }
307
Iterate(const RootVisitor & v0,const RootRangeVisitor & v1) const308 void FrameIterator::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const
309 {
310 ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers = thread_->GetEcmaVM()->GetHeap()->GetDerivedPointers();
311 bool isVerifying = false;
312
313 #if ECMASCRIPT_ENABLE_HEAP_VERIFY
314 isVerifying = thread_->GetEcmaVM()->GetHeap()->GetIsVerifying();
315 #endif
316
317 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
318 while (current) {
319 FrameType type = FrameHandler(current).GetFrameType();
320 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
321 InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(current);
322 InterpretedFrameHandler(current).Iterate(v0, v1);
323 current = frame->GetPrevFrameFp();
324 } else if (type == FrameType::OPTIMIZED_FRAME) {
325 OptimizedFrame *frame = OptimizedFrame::GetFrameFromSp(current);
326 OptimizedFrameHandler(reinterpret_cast<uintptr_t *>(current)).Iterate(v0, v1, derivedPointers, isVerifying);
327 current = frame->GetPrevFrameFp();
328 } else if (type == FrameType::OPTIMIZED_ENTRY_FRAME) {
329 OptimizedEntryFrame *frame = OptimizedEntryFrame::GetFrameFromSp(current);
330 current = frame->GetPrevFrameFp();
331 ASSERT(FrameHandler(current).IsInterpretedFrame());
332 } else {
333 ASSERT(type == FrameType::OPTIMIZED_LEAVE_FRAME);
334 OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(current);
335 OptimizedLeaveFrameHandler(reinterpret_cast<uintptr_t *>(current)).Iterate(v0,
336 v1, derivedPointers, isVerifying);
337 // arm32 only support stub, optimized entry frame don't exist, when interpret call stub
338 // don't customed prologue handle. when stub call runtime, generate optimized Leave Frame.
339 // arm64 and x86_64 support stub and aot, when aot/stub call runtime, generate Optimized
340 // Leave Frame.
341 #ifdef PANDA_TARGET_ARM32
342 current = reinterpret_cast<JSTaggedType *>(frame->callsiteFp);
343 ASSERT(FrameHandler(current).IsInterpretedFrame());
344 #else
345 current = reinterpret_cast<JSTaggedType *>(frame->callsiteFp);
346 ASSERT(FrameHandler(current).GetFrameType() == FrameType::OPTIMIZED_ENTRY_FRAME ||
347 FrameHandler(current).GetFrameType() == FrameType::OPTIMIZED_FRAME);
348 #endif
349 }
350 }
351 }
352 } // namespace panda::ecmascript
353