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