// vim: set sts=2 ts=8 sw=2 tw=99 et: // // Copyright (C) 2006-2015 AlliedModders LLC // // This file is part of SourcePawn. SourcePawn is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public // License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // You should have received a copy of the GNU General Public License along with // SourcePawn. If not, see http://www.gnu.org/licenses/. // #ifndef _include_sourcepawn_vm_stack_frames_h_ #define _include_sourcepawn_vm_stack_frames_h_ #include #include namespace sp { using namespace SourcePawn; class PluginContext; class PluginRuntime; // An ExitFrame represents the state of the most recent exit from VM state to // the outside world. Because this transition is on a critical path, we declare // exactly one ExitFrame and save/restore it in InvokeFrame(). Anytime we're in // the VM, we are guaranteed to have an ExitFrame for each InvokeFrame(). class ExitFrame { public: ExitFrame() : exit_sp_(nullptr), exit_native_(-1) {} public: const intptr_t *exit_sp() const { return exit_sp_; } bool has_exit_native() const { return exit_native_ != -1; } uint32_t exit_native() const { assert(has_exit_native()); return exit_native_; } public: static inline size_t offsetOfExitSp() { return offsetof(ExitFrame, exit_sp_); } static inline size_t offsetOfExitNative() { return offsetof(ExitFrame, exit_native_); } private: const intptr_t *exit_sp_; int exit_native_; }; // An InvokeFrame represents one activation of Execute2(). class InvokeFrame { public: InvokeFrame(PluginContext *cx, ucell_t cip); ~InvokeFrame(); InvokeFrame *prev() const { return prev_; } PluginContext *cx() const { return cx_; } const ExitFrame &prev_exit_frame() const { return prev_exit_frame_; } const intptr_t *entry_sp() const { return entry_sp_; } ucell_t entry_cip() const { return entry_cip_; } public: static inline size_t offsetOfEntrySp() { return offsetof(InvokeFrame, entry_sp_); } private: InvokeFrame *prev_; PluginContext *cx_; ExitFrame prev_exit_frame_; ucell_t entry_cip_; const intptr_t *entry_sp_; }; class FrameIterator : public SourcePawn::IFrameIterator { public: FrameIterator(); bool Done() const KE_OVERRIDE { return !ivk_; } void Next() KE_OVERRIDE; void Reset() KE_OVERRIDE; bool IsNativeFrame() const KE_OVERRIDE; bool IsScriptedFrame() const KE_OVERRIDE; const char *FunctionName() const KE_OVERRIDE; const char *FilePath() const KE_OVERRIDE; unsigned LineNumber() const KE_OVERRIDE; IPluginContext *Context() const KE_OVERRIDE; private: void nextInvokeFrame(); cell_t findCip() const; private: InvokeFrame *ivk_; ExitFrame exit_frame_; PluginRuntime *runtime_; const intptr_t *sp_iter_; const intptr_t *sp_stop_; ucell_t function_cip_; mutable ucell_t cip_; void *pc_; }; } // namespace sp #endif // _include_sourcepawn_vm_stack_frames_h_