sourcemod/sourcepawn/vm/stack-frames.h
2015-03-07 10:50:35 -08:00

136 lines
3.1 KiB
C++

// 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 <sp_vm_api.h>
#include <assert.h>
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_