• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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