• 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 #ifndef PANDA_INTERPRETER_FRAME_H_
16 #define PANDA_INTERPRETER_FRAME_H_
17 
18 #include <cstddef>
19 #include <cstdint>
20 
21 #include "libpandabase/macros.h"
22 #include "libpandabase/utils/bit_helpers.h"
23 #include "libpandabase/utils/bit_utils.h"
24 #include "libpandabase/utils/logger.h"
25 #include "runtime/interpreter/acc_vregister.h"
26 #include "runtime/mem/frame_allocator-inl.h"
27 #include "libpandafile/bytecode_instruction-inl.h"
28 
29 namespace panda {
30 
31 // ========== Compatible Frame Layout ==========
32 // Now we have a variable vregisters list, it's compatible with static language(Java etc.) and dynamic language(JS etc.)
33 // Frame layout - Static Languages
34 // +---------------------------------+
35 // |          panda::Frame           |
36 // +---------------------------------+ <-------- payload
37 // |           vregs[0]: v_          |
38 // +---------------------------------+
39 // |              ...                |
40 // +---------------------------------+
41 // |         vregs[nregs-1] : v_     |
42 // +---------------------------------+ <-------- mirror
43 // |         vregs[0]: v_            |
44 // +---------------------------------+
45 // |               ...               |
46 // +---------------------------------+
47 // |         vregs[nregs-1] : v_     |
48 // +---------------------------------+
49 //
50 // Frame layout - Dynamic Languages
51 // +---------------------------------+
52 // |          panda::Frame           |
53 // +---------------------------------+ <-------- payload
54 // |           vregs[0]: v_          |
55 // +---------------------------------+
56 // |              ...                |
57 // +---------------------------------+
58 // |         vregs[nregs-1] : v_     |
59 // +---------------------------------+
60 //
61 // Vregister has no type info now, called tagless vregister. For dynamic Language, vregister's value is Tagged with type
62 // info, which does not need the mirror part to store extra tag. For static Language, we alloc a mirror part for every
63 // vregister to retain the tag info. And the mirror part offset will be `nregs_ * sizeof(Vregister)`.
64 // You can use the `FrameHandler` to access the vregisters list and GetVReg will return `VRegisterRef`
65 // AccVRegister is different from VRegister, it contains both value and tag like before.
66 
67 class Method;
68 class ObjectHeader;
69 template <class ExtData>
70 class ExtFrame;
71 
72 class Frame {
73 public:
74     // Instrumentation: indicate what the frame must be force poped
75     static constexpr size_t FORCE_POP = 1U;
76     // Instrumentation: indicate what the frame must retry last instruction
77     static constexpr size_t RETRY_INSTRUCTION = 2U;
78     // Instrumentation: indicate what the frame must notify when poped
79     static constexpr size_t NOTIFY_POP = 4U;
80     // Indicate that the frame was created after deoptimization.
81     // This flag is needed to avoid OSR for deoptimized frames. Because the OSR consumes stack that isn't released after
82     // deoptimization, stack overflow can be occurred. This constrain may be removed once asm interpreter is introduced.
83     static constexpr size_t IS_DEOPTIMIZED = 8U;
84     // Indicate whether this frame is stackless frame, only take effects under stackless interpreter mode.
85     static constexpr size_t IS_STACKLESS = 16U;
86     // Indicate whether this frame is initobj frame, only take effects under stackless interpreter mode.
87     static constexpr size_t IS_INITOBJ = 32U;
88 
89     // Indicate whether this frame is created in Method::Invoke
90     static constexpr size_t IS_INVOKE = 64U;
91 
92     // Indicate whether this frame is static or dynamic, which decides the frame layout
93     static constexpr size_t IS_DYNAMIC = 128U;
94 
Frame(void * ext,Method * method,Frame * prev,uint32_t nregs)95     ALWAYS_INLINE inline Frame(void *ext, Method *method, Frame *prev, uint32_t nregs)
96         : prev_(prev),
97           method_(method),
98           nregs_(nregs),
99           num_actual_args_(0),
100           bc_offset_(0),
101           flags_(0),
102           ext_(ext),
103           next_inst_(nullptr),
104           inst_(nullptr)
105     {
106     }
Frame(void * ext,Method * method,Frame * prev,uint32_t nregs,uint32_t num_actual_args)107     ALWAYS_INLINE inline Frame(void *ext, Method *method, Frame *prev, uint32_t nregs, uint32_t num_actual_args)
108         : prev_(prev),
109           method_(method),
110           nregs_(nregs),
111           num_actual_args_(num_actual_args),
112           bc_offset_(0),
113           flags_(0),
114           ext_(ext),
115           next_inst_(nullptr),
116           inst_(nullptr)
117     {
118     }
119 
ToExt(Frame * frame,size_t ext_sz)120     ALWAYS_INLINE static void *ToExt(Frame *frame, size_t ext_sz)
121     {
122         return reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(frame) - ext_sz);
123     }
124 
FromExt(void * ext,size_t ext_sz)125     ALWAYS_INLINE static Frame *FromExt(void *ext, size_t ext_sz)
126     {
127         return reinterpret_cast<Frame *>(reinterpret_cast<uintptr_t>(ext) + ext_sz);
128     }
129 
GetExt()130     ALWAYS_INLINE inline void *GetExt()
131     {
132         return ext_;
133     }
134 
GetVReg(size_t i)135     ALWAYS_INLINE inline const interpreter::VRegister &GetVReg(size_t i) const
136     {
137         return vregs_[i];
138     }
139 
GetVReg(size_t i)140     ALWAYS_INLINE inline interpreter::VRegister &GetVReg(size_t i)
141     {
142         return vregs_[i];
143     }
144 
SetAcc(const interpreter::AccVRegister & acc)145     ALWAYS_INLINE inline void SetAcc(const interpreter::AccVRegister &acc)
146     {
147         acc_ = acc;
148     }
149 
GetAcc()150     ALWAYS_INLINE inline interpreter::AccVRegister &GetAcc()
151     {
152         return acc_;
153     }
154 
GetAcc()155     ALWAYS_INLINE inline const interpreter::AccVRegister &GetAcc() const
156     {
157         return acc_;
158     }
159 
SetMethod(Method * method)160     ALWAYS_INLINE inline void SetMethod(Method *method)
161     {
162         method_ = method;
163     }
164 
GetMethod()165     ALWAYS_INLINE inline Method *GetMethod() const
166     {
167         return method_;
168     }
169 
170     ALWAYS_INLINE const uint8_t *GetInstrOffset();
171 
SetPrevFrame(Frame * prev)172     ALWAYS_INLINE inline void SetPrevFrame(Frame *prev)
173     {
174         prev_ = prev;
175     }
176 
GetPrevFrame()177     ALWAYS_INLINE inline Frame *GetPrevFrame() const
178     {
179         return prev_;
180     }
181 
GetSize()182     ALWAYS_INLINE inline uint32_t GetSize() const
183     {
184         return nregs_;
185     }
186 
GetNumActualArgs()187     ALWAYS_INLINE inline uint32_t GetNumActualArgs() const
188     {
189         return num_actual_args_;
190     }
191 
SetBytecodeOffset(uint32_t bc_offset)192     ALWAYS_INLINE inline void SetBytecodeOffset(uint32_t bc_offset)
193     {
194         bc_offset_ = bc_offset;
195     }
196 
GetBytecodeOffset()197     ALWAYS_INLINE inline uint32_t GetBytecodeOffset() const
198     {
199         return bc_offset_;
200     }
201 
SetNextInstruction(BytecodeInstruction inst)202     ALWAYS_INLINE inline void SetNextInstruction(BytecodeInstruction inst)
203     {
204         next_inst_ = inst;
205     }
206 
GetNextInstruction()207     ALWAYS_INLINE inline BytecodeInstruction GetNextInstruction() const
208     {
209         return next_inst_;
210     }
211 
SetInstruction(const uint8_t * inst)212     ALWAYS_INLINE inline void SetInstruction(const uint8_t *inst)
213     {
214         inst_ = inst;
215     }
216 
GetInstruction()217     ALWAYS_INLINE inline const uint8_t *GetInstruction() const
218     {
219         return inst_;
220     }
221 
GetAllocSize(size_t size,uint32_t ext_sz)222     ALWAYS_INLINE static inline size_t GetAllocSize(size_t size, uint32_t ext_sz)
223     {
224         return AlignUp(sizeof(Frame) + sizeof(interpreter::VRegister) * size + ext_sz,
225                        GetAlignmentInBytes(DEFAULT_FRAME_ALIGNMENT));
226     }
227 
IsForcePop()228     ALWAYS_INLINE inline bool IsForcePop() const
229     {
230         return (flags_ & FORCE_POP) != 0;
231     }
232 
ClearForcePop()233     ALWAYS_INLINE inline void ClearForcePop()
234     {
235         flags_ = flags_ & ~FORCE_POP;
236     }
237 
SetForcePop()238     ALWAYS_INLINE inline void SetForcePop()
239     {
240         flags_ = flags_ | FORCE_POP;
241     }
242 
IsRetryInstruction()243     ALWAYS_INLINE inline bool IsRetryInstruction() const
244     {
245         return (flags_ & RETRY_INSTRUCTION) != 0;
246     }
247 
ClearRetryInstruction()248     ALWAYS_INLINE inline void ClearRetryInstruction()
249     {
250         flags_ = flags_ & ~RETRY_INSTRUCTION;
251     }
252 
SetRetryInstruction()253     ALWAYS_INLINE inline void SetRetryInstruction()
254     {
255         flags_ = flags_ | RETRY_INSTRUCTION;
256     }
257 
IsNotifyPop()258     ALWAYS_INLINE inline bool IsNotifyPop() const
259     {
260         return (flags_ & NOTIFY_POP) != 0;
261     }
262 
ClearNotifyPop()263     ALWAYS_INLINE inline void ClearNotifyPop()
264     {
265         flags_ = flags_ & ~NOTIFY_POP;
266     }
267 
SetNotifyPop()268     ALWAYS_INLINE inline void SetNotifyPop()
269     {
270         flags_ = flags_ | NOTIFY_POP;
271     }
272 
IsDeoptimized()273     ALWAYS_INLINE inline bool IsDeoptimized() const
274     {
275         return (flags_ & IS_DEOPTIMIZED) != 0;
276     }
277 
SetDeoptimized()278     ALWAYS_INLINE inline void SetDeoptimized()
279     {
280         flags_ |= IS_DEOPTIMIZED;
281     }
282 
DisableOsr()283     ALWAYS_INLINE inline void DisableOsr()
284     {
285         SetDeoptimized();
286     }
287 
IsStackless()288     ALWAYS_INLINE inline bool IsStackless() const
289     {
290         return (flags_ & IS_STACKLESS) != 0;
291     }
292 
SetStackless()293     ALWAYS_INLINE inline void SetStackless()
294     {
295         flags_ = flags_ | IS_STACKLESS;
296     }
297 
IsInitobj()298     ALWAYS_INLINE inline bool IsInitobj() const
299     {
300         return (flags_ & IS_INITOBJ) != 0;
301     }
302 
SetInitobj()303     ALWAYS_INLINE inline void SetInitobj()
304     {
305         flags_ = flags_ | IS_INITOBJ;
306     }
307 
SetInvoke()308     ALWAYS_INLINE inline void SetInvoke()
309     {
310         flags_ = flags_ | IS_INVOKE;
311     }
312 
IsInvoke()313     ALWAYS_INLINE inline bool IsInvoke() const
314     {
315         return (flags_ & IS_INVOKE) != 0;
316     }
317 
IsDynamic()318     ALWAYS_INLINE inline bool IsDynamic() const
319     {
320         return (flags_ & IS_DYNAMIC) != 0;
321     }
322 
SetDynamic()323     ALWAYS_INLINE inline void SetDynamic()
324     {
325         flags_ = flags_ | IS_DYNAMIC;
326     }
327 
328     template <bool is_dynamic = false>
GetAccAsVReg()329     ALWAYS_INLINE inline typename std::enable_if<is_dynamic, interpreter::DynamicVRegisterRef>::type GetAccAsVReg()
330     {
331         return GetAcc().template AsVRegRef<true>();
332     }
333 
334     template <bool is_dynamic = false>
GetAccAsVReg()335     ALWAYS_INLINE inline typename std::enable_if<!is_dynamic, interpreter::StaticVRegisterRef>::type GetAccAsVReg()
336     {
337         return GetAcc().template AsVRegRef<false>();
338     }
339 
340     template <bool is_dynamic = false>
GetActualSize(uint32_t nregs)341     ALWAYS_INLINE static inline uint32_t GetActualSize(uint32_t nregs)
342     {
343         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
344         if constexpr (is_dynamic) {
345             return nregs;
346         }
347         return nregs * 2U;
348     }
349 
GetMethodOffset()350     ALWAYS_INLINE static inline constexpr uint32_t GetMethodOffset()
351     {
352         return MEMBER_OFFSET(Frame, method_);
353     }
354 
GetPrevFrameOffset()355     ALWAYS_INLINE static inline constexpr uint32_t GetPrevFrameOffset()
356     {
357         return MEMBER_OFFSET(Frame, prev_);
358     }
359 
GetNumVregsOffset()360     ALWAYS_INLINE static inline constexpr uint32_t GetNumVregsOffset()
361     {
362         return MEMBER_OFFSET(Frame, nregs_);
363     }
364 
GetVregsOffset()365     ALWAYS_INLINE static inline constexpr uint32_t GetVregsOffset()
366     {
367         return MEMBER_OFFSET(Frame, vregs_);
368     }
369 
GetAccOffset()370     ALWAYS_INLINE static inline constexpr uint32_t GetAccOffset()
371     {
372         return MEMBER_OFFSET(Frame, acc_);
373     }
374 
GetFlagsOffset()375     ALWAYS_INLINE static inline constexpr uint32_t GetFlagsOffset()
376     {
377         return MEMBER_OFFSET(Frame, flags_);
378     }
379 
GetNextInstructionOffset()380     ALWAYS_INLINE static inline constexpr uint32_t GetNextInstructionOffset()
381     {
382         return MEMBER_OFFSET(Frame, next_inst_);
383     }
384 
GetInstructionsOffset()385     ALWAYS_INLINE static inline constexpr uint32_t GetInstructionsOffset()
386     {
387         return MEMBER_OFFSET(Frame, inst_);
388     }
389 
390     ~Frame() = default;
391 
392     NO_COPY_SEMANTIC(Frame);
393     NO_MOVE_SEMANTIC(Frame);
394 
395 private:
396     Frame *prev_;
397     Method *method_;
398     uint32_t nregs_;
399     uint32_t num_actual_args_;
400     uint32_t bc_offset_;
401     size_t flags_;
402 
403     // ExtFrame<Ext> allocation ptr
404     void *ext_;
405 
406     interpreter::AccVRegister acc_;
407     BytecodeInstruction next_inst_;
408     const uint8_t *inst_;
409 
410     __extension__ interpreter::VRegister vregs_[0];  // NOLINT(modernize-avoid-c-arrays)
411 };
412 
413 class FrameHandler {
414 public:
FrameHandler(Frame * frame)415     ALWAYS_INLINE inline explicit FrameHandler(Frame *frame) : frame_(frame) {}
416 
SetAcc(const interpreter::AccVRegister & acc)417     ALWAYS_INLINE inline void SetAcc(const interpreter::AccVRegister &acc)
418     {
419         frame_->SetAcc(acc);
420     }
421 
GetAcc()422     ALWAYS_INLINE inline interpreter::AccVRegister &GetAcc()
423     {
424         return frame_->GetAcc();
425     }
426 
GetAcc()427     ALWAYS_INLINE inline const interpreter::AccVRegister &GetAcc() const
428     {
429         return frame_->GetAcc();
430     }
431 
SetMethod(Method * method)432     ALWAYS_INLINE inline void SetMethod(Method *method)
433     {
434         frame_->SetMethod(method);
435     }
436 
GetMethod()437     ALWAYS_INLINE inline Method *GetMethod() const
438     {
439         return frame_->GetMethod();
440     }
441 
GetInstrOffset()442     ALWAYS_INLINE const uint8_t *GetInstrOffset() const
443     {
444         return frame_->GetInstrOffset();
445     }
446 
SetPrevFrame(Frame * prev)447     ALWAYS_INLINE inline void SetPrevFrame(Frame *prev)
448     {
449         frame_->SetPrevFrame(prev);
450     }
451 
GetPrevFrame()452     ALWAYS_INLINE inline Frame *GetPrevFrame() const
453     {
454         return frame_->GetPrevFrame();
455     }
456 
GetSize()457     ALWAYS_INLINE inline uint32_t GetSize() const
458     {
459         return frame_->GetSize();
460     }
461 
GetNumActualArgs()462     ALWAYS_INLINE inline uint32_t GetNumActualArgs() const
463     {
464         return frame_->GetNumActualArgs();
465     }
466 
SetBytecodeOffset(uint32_t bc_offset)467     ALWAYS_INLINE inline void SetBytecodeOffset(uint32_t bc_offset)
468     {
469         frame_->SetBytecodeOffset(bc_offset);
470     }
471 
GetBytecodeOffset()472     ALWAYS_INLINE inline uint32_t GetBytecodeOffset() const
473     {
474         return frame_->GetBytecodeOffset();
475     }
476 
SetNextInstruction(BytecodeInstruction inst)477     ALWAYS_INLINE inline void SetNextInstruction(BytecodeInstruction inst)
478     {
479         frame_->SetNextInstruction(inst);
480     }
481 
GetNextInstruction()482     ALWAYS_INLINE inline BytecodeInstruction GetNextInstruction() const
483     {
484         return frame_->GetNextInstruction();
485     }
486 
SetInstruction(const uint8_t * inst)487     ALWAYS_INLINE inline void SetInstruction(const uint8_t *inst)
488     {
489         frame_->SetInstruction(inst);
490     }
491 
GetInstruction()492     ALWAYS_INLINE inline const uint8_t *GetInstruction() const
493     {
494         return frame_->GetInstruction();
495     }
496 
IsForcePop()497     ALWAYS_INLINE inline bool IsForcePop() const
498     {
499         return frame_->IsForcePop();
500     }
501 
ClearForcePop()502     ALWAYS_INLINE inline void ClearForcePop()
503     {
504         frame_->ClearForcePop();
505     }
506 
SetForcePop()507     ALWAYS_INLINE inline void SetForcePop()
508     {
509         frame_->SetForcePop();
510     }
511 
IsRetryInstruction()512     ALWAYS_INLINE inline bool IsRetryInstruction() const
513     {
514         return frame_->IsRetryInstruction();
515     }
516 
ClearRetryInstruction()517     ALWAYS_INLINE inline void ClearRetryInstruction()
518     {
519         frame_->ClearRetryInstruction();
520     }
521 
SetRetryInstruction()522     ALWAYS_INLINE inline void SetRetryInstruction()
523     {
524         frame_->SetRetryInstruction();
525     }
526 
IsNotifyPop()527     ALWAYS_INLINE inline bool IsNotifyPop() const
528     {
529         return frame_->IsNotifyPop();
530     }
531 
ClearNotifyPop()532     ALWAYS_INLINE inline void ClearNotifyPop()
533     {
534         frame_->ClearNotifyPop();
535     }
536 
SetNotifyPop()537     ALWAYS_INLINE inline void SetNotifyPop()
538     {
539         frame_->SetNotifyPop();
540     }
541 
IsDeoptimized()542     ALWAYS_INLINE inline bool IsDeoptimized() const
543     {
544         return frame_->IsDeoptimized();
545     }
546 
SetDeoptimized()547     ALWAYS_INLINE inline void SetDeoptimized()
548     {
549         frame_->SetDeoptimized();
550     }
551 
DisableOsr()552     ALWAYS_INLINE inline void DisableOsr()
553     {
554         frame_->SetDeoptimized();
555     }
556 
IsStackless()557     ALWAYS_INLINE inline bool IsStackless() const
558     {
559         return frame_->IsStackless();
560     }
561 
SetStackless()562     ALWAYS_INLINE inline void SetStackless()
563     {
564         frame_->SetStackless();
565     }
566 
IsInitobj()567     ALWAYS_INLINE inline bool IsInitobj() const
568     {
569         return frame_->IsInitobj();
570     }
571 
SetInitobj()572     ALWAYS_INLINE inline void SetInitobj()
573     {
574         frame_->SetInitobj();
575     }
576 
IsInvoke()577     ALWAYS_INLINE inline bool IsInvoke() const
578     {
579         return frame_->IsInvoke();
580     }
581 
SetInvoke()582     ALWAYS_INLINE inline void SetInvoke()
583     {
584         frame_->SetInvoke();
585     }
586 
IsDynamic()587     ALWAYS_INLINE inline bool IsDynamic() const
588     {
589         return frame_->IsDynamic();
590     }
591 
SetDynamic()592     ALWAYS_INLINE inline void SetDynamic()
593     {
594         frame_->SetDynamic();
595     }
596 
597     ALWAYS_INLINE inline Frame *operator*() const
598     {
599         return frame_;
600     }
601 
602     ~FrameHandler() = default;
603 
604     DEFAULT_COPY_SEMANTIC(FrameHandler);
605     DEFAULT_MOVE_SEMANTIC(FrameHandler);
606 
607 protected:
GetVRegisters()608     ALWAYS_INLINE inline interpreter::VRegister *GetVRegisters()
609     {
610         return reinterpret_cast<interpreter::VRegister *>(reinterpret_cast<uintptr_t>(frame_) +
611                                                           Frame::GetVregsOffset());
612     }
613 
614     Frame *frame_ {nullptr};  // NOLINT(misc-non-private-member-variables-in-classes)
615 };
616 
617 class StaticFrameHandler : public FrameHandler {
618 public:
StaticFrameHandler(Frame * frame)619     ALWAYS_INLINE inline explicit StaticFrameHandler(Frame *frame) : FrameHandler(frame) {}
620 
GetVReg(size_t i)621     ALWAYS_INLINE inline interpreter::StaticVRegisterRef GetVReg(size_t i)
622     {
623         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
624         return interpreter::StaticVRegisterRef(&GetVRegisters()[i], &GetMirrorVRegisters()[i]);
625     }
626 
GetAccAsVReg()627     ALWAYS_INLINE inline interpreter::StaticVRegisterRef GetAccAsVReg()
628     {
629         return GetAcc().template AsVRegRef<false>();
630     }
631 
632 private:
GetMirrorVRegisters()633     ALWAYS_INLINE inline interpreter::VRegister *GetMirrorVRegisters()
634     {
635         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
636         return &GetVRegisters()[frame_->GetSize()];
637     }
638 };
639 
640 class DynamicFrameHandler : public FrameHandler {
641 public:
DynamicFrameHandler(Frame * frame)642     ALWAYS_INLINE inline explicit DynamicFrameHandler(Frame *frame) : FrameHandler(frame) {}
643 
GetVReg(size_t i)644     ALWAYS_INLINE inline interpreter::DynamicVRegisterRef GetVReg(size_t i)
645     {
646         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
647         return interpreter::DynamicVRegisterRef(&GetVRegisters()[i]);
648     }
649 
GetAccAsVReg()650     ALWAYS_INLINE inline interpreter::DynamicVRegisterRef GetAccAsVReg()
651     {
652         return GetAcc().template AsVRegRef<true>();
653     }
654 };
655 
656 template <bool is_dynamic = false>
GetFrameHandler(Frame * frame)657 ALWAYS_INLINE inline typename std::enable_if<is_dynamic, DynamicFrameHandler>::type GetFrameHandler(Frame *frame)
658 {
659     return DynamicFrameHandler(frame);
660 }
661 
662 template <bool is_dynamic = false>
GetFrameHandler(Frame * frame)663 ALWAYS_INLINE inline typename std::enable_if<!is_dynamic, StaticFrameHandler>::type GetFrameHandler(Frame *frame)
664 {
665     return StaticFrameHandler(frame);
666 }
667 
668 // ExtFrame<ExtData> is an extended panda::Frame. It's used to hold any
669 // language-specific data, which is required to be associated with panda::Frame.
670 //
671 //                      Allocated ExtFrame looks like that:
672 //
673 //   ExtFrame<ExtData>*  ---->  | ExtData.field1 |  <---- ExtFrame::ExtData*
674 //                              | ExtData.field2 |
675 //                              | ExtData.field3 |
676 //    inserted by compiler ---- |     padding    |
677 //                              |  Frame.field1  |  <---- ExtFame::Frame*
678 //                              |  Frame.field2  |
679 //               VRegs VLA --|--|     vreg[0]    |
680 //                           |  |     vreg[1]    |
681 //                           |  |      ....      |
682 //                           |--|  vreg[nregs-1] |
683 //
684 // Generic panda interpreter operates panda::Frames, while any language extension
685 // may access its LangSpecData via panda::Frame *base_frame
686 //     ExtFrame<LangSpecData>::FromFrame(base_frame)->GetExtData()
687 // if it's known that this frame was properly allocated.
688 template <class ExtData>
689 class ExtFrame {
690 public:
691     ExtFrame() = delete;
692     ~ExtFrame() = delete;
693     NO_COPY_SEMANTIC(ExtFrame);
694     NO_MOVE_SEMANTIC(ExtFrame);
695 
GetFrame()696     ALWAYS_INLINE inline Frame *GetFrame()
697     {
698         return &frame;
699     }
700 
GetExtData()701     ALWAYS_INLINE inline ExtData *GetExtData()
702     {
703         return &ext_data;
704     }
705 
GetExtSize()706     ALWAYS_INLINE static inline constexpr uint32_t GetExtSize()
707     {
708         return frame_offset;
709     }
710 
FromFrame(Frame * base)711     ALWAYS_INLINE static inline ExtFrame<ExtData> *FromFrame(Frame *base)
712     {
713         auto *res = reinterpret_cast<ExtFrame<ExtData> *>(reinterpret_cast<uintptr_t>(base) - frame_offset);
714         ASSERT(res == base->GetExt());
715         return res;
716     }
717 
718 private:
719     static constexpr uint32_t frame_offset = MEMBER_OFFSET(ExtFrame<ExtData>, frame);
720 
721 #pragma GCC diagnostic push
722 #pragma GCC diagnostic ignored "-Wpedantic"
723     ExtData ext_data;
724     __extension__ Frame frame;
725 #pragma GCC diagnostic pop
726 };
727 
728 #pragma GCC diagnostic push
729 #pragma GCC diagnostic ignored "-Wpedantic"
730 // Zero-size template parameter for ExtFrame in case where no language
731 // extension required
732 union EmptyExtFrameData {
733     __extension__ int v[0];  // NOLINT(modernize-avoid-c-arrays)
734 };
735 constexpr uint32_t EmptyExtFrameDataSize = ExtFrame<EmptyExtFrameData>::GetExtSize();
736 static_assert(EmptyExtFrameDataSize == 0, "Nonzero EmptyExtFrameDataSize");
737 #pragma GCC diagnostic pop
738 
739 template <class ExtT = EmptyExtFrameData>
CreateFrame(mem::StackFrameAllocator * stack_frame_allocator,uint32_t nregs_size,Method * method,Frame * prev,uint32_t nregs,uint32_t num_actual_args)740 ALWAYS_INLINE inline Frame *CreateFrame(mem::StackFrameAllocator *stack_frame_allocator, uint32_t nregs_size,
741                                         Method *method, Frame *prev, uint32_t nregs, uint32_t num_actual_args)
742 {
743     constexpr uint32_t ext_size = ExtFrame<ExtT>::GetExtSize();
744 
745     size_t ext_frame_size = Frame::GetAllocSize(nregs_size, ext_size);
746     void *mem = stack_frame_allocator->Alloc(ext_frame_size);
747     if (UNLIKELY(mem == nullptr)) {
748         return nullptr;
749     }
750     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
751     return new (Frame::FromExt(mem, ext_size)) Frame(mem, method, prev, nregs, num_actual_args);
752 }
753 
DestroyFrame(mem::StackFrameAllocator * stack_frame_allocator,Frame * frame)754 ALWAYS_INLINE inline void DestroyFrame(mem::StackFrameAllocator *stack_frame_allocator, Frame *frame)
755 {
756     ASSERT(frame->GetExt() != nullptr);
757     stack_frame_allocator->Free(frame->GetExt());
758 }
759 
760 }  // namespace panda
761 
762 #endif  // PANDA_INTERPRETER_FRAME_H_
763