2015-02-24 03:19:33 +01:00
|
|
|
// 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_environment_h_
|
|
|
|
#define _include_sourcepawn_vm_environment_h_
|
|
|
|
|
|
|
|
#include <sp_vm_api.h>
|
|
|
|
#include <am-utility.h> // Replace with am-cxx later.
|
2015-02-24 08:49:39 +01:00
|
|
|
#include <am-inlinelist.h>
|
|
|
|
#include <am-thread-utils.h>
|
2015-02-24 08:12:45 +01:00
|
|
|
#include "code-allocator.h"
|
2015-02-24 08:49:39 +01:00
|
|
|
#include "plugin-runtime.h"
|
2015-02-24 03:19:33 +01:00
|
|
|
|
|
|
|
namespace sp {
|
|
|
|
|
|
|
|
using namespace SourcePawn;
|
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
class PluginRuntime;
|
2015-02-24 10:12:23 +01:00
|
|
|
class CodeStubs;
|
2015-02-24 07:47:08 +01:00
|
|
|
class WatchdogTimer;
|
|
|
|
|
2015-02-24 03:19:33 +01:00
|
|
|
// An Environment encapsulates everything that's needed to load and run
|
|
|
|
// instances of plugins on a single thread. There can be at most one
|
|
|
|
// environment per thread.
|
|
|
|
//
|
|
|
|
// Currently, the VM is single threaded in that no more than one
|
|
|
|
// Environment can be created per process.
|
|
|
|
class Environment : public ISourcePawnEnvironment
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Environment();
|
2015-02-24 07:47:08 +01:00
|
|
|
~Environment();
|
2015-02-24 03:19:33 +01:00
|
|
|
|
|
|
|
static Environment *New();
|
|
|
|
|
|
|
|
void Shutdown() KE_OVERRIDE;
|
|
|
|
ISourcePawnEngine *APIv1() KE_OVERRIDE;
|
|
|
|
ISourcePawnEngine2 *APIv2() KE_OVERRIDE;
|
|
|
|
int ApiVersion() KE_OVERRIDE {
|
|
|
|
return SOURCEPAWN_API_VERSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access the current Environment.
|
|
|
|
static Environment *get();
|
|
|
|
|
|
|
|
bool InstallWatchdogTimer(int timeout_ms);
|
|
|
|
|
|
|
|
// Runtime functions.
|
|
|
|
const char *GetErrorString(int err);
|
|
|
|
void ReportError(PluginRuntime *runtime, int err, const char *errstr, cell_t rp_start);
|
|
|
|
|
2015-02-24 08:12:45 +01:00
|
|
|
// Allocate and free executable memory.
|
|
|
|
void *AllocateCode(size_t size);
|
|
|
|
void FreeCode(void *code);
|
2015-02-24 10:12:23 +01:00
|
|
|
CodeStubs *stubs() {
|
|
|
|
return code_stubs_;
|
|
|
|
}
|
2015-02-24 08:12:45 +01:00
|
|
|
|
2015-02-24 08:49:39 +01:00
|
|
|
// Runtime management.
|
|
|
|
void RegisterRuntime(PluginRuntime *rt);
|
|
|
|
void DeregisterRuntime(PluginRuntime *rt);
|
|
|
|
void PatchAllJumpsForTimeout();
|
|
|
|
void UnpatchAllJumpsFromTimeout();
|
|
|
|
ke::Mutex *lock() {
|
|
|
|
return &mutex_;
|
|
|
|
}
|
2015-02-24 10:12:23 +01:00
|
|
|
int Invoke(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result);
|
2015-02-24 08:49:39 +01:00
|
|
|
|
2015-02-24 03:19:33 +01:00
|
|
|
// Helpers.
|
|
|
|
void SetProfiler(IProfilingTool *profiler) {
|
|
|
|
profiler_ = profiler;
|
|
|
|
}
|
|
|
|
IProfilingTool *profiler() const {
|
|
|
|
return profiler_;
|
|
|
|
}
|
|
|
|
bool IsProfilingEnabled() const {
|
|
|
|
return profiling_enabled_;
|
|
|
|
}
|
|
|
|
void EnableProfiling();
|
|
|
|
void DisableProfiling();
|
|
|
|
|
|
|
|
void SetJitEnabled(bool enabled) {
|
|
|
|
}
|
|
|
|
bool IsJitEnabled() const {
|
|
|
|
return jit_enabled_;
|
|
|
|
}
|
|
|
|
void SetDebugger(IDebugListener *debugger) {
|
|
|
|
debugger_ = debugger;
|
|
|
|
}
|
|
|
|
IDebugListener *debugger() const {
|
|
|
|
return debugger_;
|
|
|
|
}
|
|
|
|
|
2015-02-24 07:47:08 +01:00
|
|
|
WatchdogTimer *watchdog() const {
|
|
|
|
return watchdog_timer_;
|
|
|
|
}
|
|
|
|
|
2015-02-24 08:49:39 +01:00
|
|
|
// These are indicators used for the watchdog timer.
|
|
|
|
uintptr_t FrameId() const {
|
|
|
|
return frame_id_;
|
|
|
|
}
|
|
|
|
bool RunningCode() const {
|
|
|
|
return invoke_depth_ != 0;
|
|
|
|
}
|
|
|
|
void EnterInvoke() {
|
|
|
|
if (invoke_depth_++ == 0)
|
|
|
|
frame_id_++;
|
|
|
|
}
|
|
|
|
void LeaveInvoke() {
|
|
|
|
invoke_depth_--;
|
|
|
|
}
|
|
|
|
|
2015-02-24 03:19:33 +01:00
|
|
|
private:
|
|
|
|
bool Initialize();
|
|
|
|
|
|
|
|
private:
|
|
|
|
ke::AutoPtr<ISourcePawnEngine> api_v1_;
|
|
|
|
ke::AutoPtr<ISourcePawnEngine2> api_v2_;
|
2015-02-24 07:47:08 +01:00
|
|
|
ke::AutoPtr<WatchdogTimer> watchdog_timer_;
|
2015-02-24 08:49:39 +01:00
|
|
|
ke::Mutex mutex_;
|
2015-02-24 03:19:33 +01:00
|
|
|
|
|
|
|
IDebugListener *debugger_;
|
|
|
|
IProfilingTool *profiler_;
|
|
|
|
bool jit_enabled_;
|
|
|
|
bool profiling_enabled_;
|
2015-02-24 08:12:45 +01:00
|
|
|
|
|
|
|
Knight::KeCodeCache *code_pool_;
|
2015-02-24 08:49:39 +01:00
|
|
|
ke::InlineList<PluginRuntime> runtimes_;
|
|
|
|
|
|
|
|
uintptr_t frame_id_;
|
|
|
|
uintptr_t invoke_depth_;
|
2015-02-24 10:12:23 +01:00
|
|
|
|
|
|
|
ke::AutoPtr<CodeStubs> code_stubs_;
|
2015-02-24 03:19:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class EnterProfileScope
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EnterProfileScope(const char *group, const char *name)
|
|
|
|
{
|
|
|
|
if (Environment::get()->IsProfilingEnabled())
|
|
|
|
Environment::get()->profiler()->EnterScope(group, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
~EnterProfileScope()
|
|
|
|
{
|
|
|
|
if (Environment::get()->IsProfilingEnabled())
|
|
|
|
Environment::get()->profiler()->LeaveScope();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-02-24 08:49:39 +01:00
|
|
|
} // namespace sp
|
2015-02-24 03:19:33 +01:00
|
|
|
|
|
|
|
#endif // _include_sourcepawn_vm_environment_h_
|