2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2009/09/05 Turley: Added struct .? and .- as shortcut for .exists() and .erase()
|
|
|
|
|
*/
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __EXECUTOR_H
|
|
|
|
|
#define __EXECUTOR_H
|
|
|
|
|
|
2026-07-25 23:01:18 +02:00
|
|
|
#include <pol_global_config.h>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2026-07-25 23:01:18 +02:00
|
|
|
#include "bscript/bobject.h"
|
|
|
|
|
#include "bscript/exectype.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <exception>
|
2024-08-25 11:44:06 +02:00
|
|
|
#include <map>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <memory>
|
2024-08-10 17:43:21 +02:00
|
|
|
#include <optional>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <set>
|
|
|
|
|
#include <string>
|
2024-08-25 11:44:06 +02:00
|
|
|
#include <utility>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <vector>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2026-07-25 23:01:18 +02:00
|
|
|
#include "bscript/bapplicobj.h"
|
|
|
|
|
#include "bscript/bobject.h"
|
|
|
|
|
#include "bscript/eprog.h"
|
|
|
|
|
#include "bscript/executortype.h"
|
|
|
|
|
#include "clib/refptr.h"
|
|
|
|
|
#include "clib/spinlock.h"
|
2024-01-16 17:55:42 +01:00
|
|
|
|
2024-01-10 18:29:10 +01:00
|
|
|
#ifdef ESCRIPT_PROFILE
|
2025-08-08 09:08:12 +02:00
|
|
|
#include "clib/timer.h"
|
2024-01-10 18:29:10 +01:00
|
|
|
#include <map>
|
|
|
|
|
#endif
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Core
|
|
|
|
|
{
|
|
|
|
|
class UOExecutor;
|
2018-01-29 21:55:48 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void list_script( UOExecutor* uoexec );
|
2018-12-31 11:59:47 +01:00
|
|
|
} // namespace Core
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Bscript
|
|
|
|
|
{
|
2024-07-28 22:51:04 +02:00
|
|
|
class BContinuation;
|
|
|
|
|
class BFunctionRef;
|
2016-02-19 19:26:35 +01:00
|
|
|
class Executor;
|
2018-01-29 21:55:48 +01:00
|
|
|
class ExecutorModule;
|
|
|
|
|
class ModuleFunction;
|
2016-02-19 19:26:35 +01:00
|
|
|
class String;
|
2018-01-01 21:49:30 +01:00
|
|
|
class Token;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2024-01-28 15:49:55 +07:00
|
|
|
class ExecutorDebugListener
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-01-10 18:12:09 +01:00
|
|
|
virtual void on_halt() {};
|
|
|
|
|
virtual void on_destroy() {};
|
|
|
|
|
virtual void on_print( const std::string& /*str*/ ) {};
|
2024-01-28 15:49:55 +07:00
|
|
|
};
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// FIXME: how to make this a nested struct in Executor?
|
|
|
|
|
struct ReturnContext
|
|
|
|
|
{
|
2024-08-10 17:43:21 +02:00
|
|
|
struct External
|
|
|
|
|
{
|
|
|
|
|
External( ref_ptr<EScriptProgram> program, std::vector<ExecutorModule*> modules,
|
|
|
|
|
std::shared_ptr<BObjectRefVec> globals )
|
|
|
|
|
: Program( std::move( program ) ),
|
|
|
|
|
Modules( std::move( modules ) ),
|
|
|
|
|
Globals( std::move( globals ) )
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
ref_ptr<EScriptProgram> Program;
|
|
|
|
|
std::vector<ExecutorModule*> Modules;
|
|
|
|
|
std::shared_ptr<BObjectRefVec> Globals;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
unsigned PC;
|
|
|
|
|
unsigned ValueStackDepth;
|
2024-07-28 22:51:04 +02:00
|
|
|
BObjectRef Continuation = BObjectRef();
|
2024-08-10 17:43:21 +02:00
|
|
|
|
|
|
|
|
std::optional<External> ExternalContext;
|
2016-02-19 19:26:35 +01:00
|
|
|
};
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
struct BackupStruct
|
|
|
|
|
{
|
|
|
|
|
std::unique_ptr<BObjectRefVec> Locals;
|
|
|
|
|
ValueStackCont ValueStack;
|
|
|
|
|
unsigned PC;
|
|
|
|
|
};
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2020-02-08 09:21:35 +01:00
|
|
|
enum class ExecutorType
|
|
|
|
|
{
|
2020-12-16 18:56:10 +01:00
|
|
|
EXECUTOR,
|
|
|
|
|
POL
|
2020-02-08 09:21:35 +01:00
|
|
|
};
|
|
|
|
|
|
2024-01-28 15:49:55 +07:00
|
|
|
enum class ExecutorDebugState
|
|
|
|
|
{
|
|
|
|
|
ATTACHING,
|
|
|
|
|
ATTACHED,
|
|
|
|
|
INS_TRACE,
|
|
|
|
|
RUN,
|
|
|
|
|
BREAK_INTO,
|
|
|
|
|
STEP_INTO,
|
|
|
|
|
STEPPING_INTO,
|
|
|
|
|
STEP_OVER,
|
|
|
|
|
STEPPING_OVER,
|
|
|
|
|
STEP_OUT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ExecutorDebugEnvironment
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ExecutorDebugEnvironment( std::weak_ptr<ExecutorDebugListener> listener, bool set_attaching );
|
|
|
|
|
|
|
|
|
|
// Return `false` to skip the instruction from executing.
|
|
|
|
|
bool on_instruction( Executor& );
|
|
|
|
|
size_t sizeEstimate() const;
|
|
|
|
|
|
|
|
|
|
ExecutorDebugState debug_state;
|
|
|
|
|
std::set<unsigned> breakpoints;
|
|
|
|
|
std::set<unsigned> tmpbreakpoints;
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
unsigned line;
|
|
|
|
|
size_t control;
|
|
|
|
|
} break_on_linechange_from;
|
|
|
|
|
unsigned bp_skip;
|
|
|
|
|
std::weak_ptr<ExecutorDebugListener> listener;
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
class Executor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static Clib::SpinLock _executor_lock;
|
|
|
|
|
virtual size_t sizeEstimate() const;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
friend void Core::list_script( Core::UOExecutor* uoexec );
|
|
|
|
|
int done;
|
|
|
|
|
void seterror( bool err );
|
|
|
|
|
bool error() const;
|
|
|
|
|
bool error_;
|
|
|
|
|
bool halt_;
|
|
|
|
|
bool run_ok_;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2020-12-16 18:56:10 +01:00
|
|
|
virtual ExecutorType type() { return ExecutorType::EXECUTOR; }
|
2020-02-08 09:21:35 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
enum DEBUG_LEVEL
|
|
|
|
|
{
|
|
|
|
|
NONE,
|
|
|
|
|
SOURCELINES,
|
|
|
|
|
INSTRUCTIONS
|
|
|
|
|
};
|
|
|
|
|
DEBUG_LEVEL debug_level;
|
|
|
|
|
unsigned PC; // program counter
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
bool AttachFunctionalityModules();
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
bool setProgram( EScriptProgram* prog );
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2024-08-10 17:43:21 +02:00
|
|
|
std::shared_ptr<BObjectRefVec> Globals2;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2017-07-29 21:51:19 +02:00
|
|
|
std::vector<BObjectRefVec*> upperLocals2;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2017-07-29 21:51:19 +02:00
|
|
|
std::vector<ReturnContext> ControlStack;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
BObjectRefVec* Locals2;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
static UninitObject* m_SharedUninitObject;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
ValueStackCont ValueStack;
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
static ExecInstrFunc GetInstrFunc( const Token& token );
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
/*
|
|
|
|
|
These must both be deleted. instr references _symbols, so it should be deleted first.
|
|
|
|
|
FIXME: there should be a separate object, called EProgram or something,
|
|
|
|
|
that owns both the instructions and the symbols. It should be ref_counted,
|
|
|
|
|
so a code repository can store programs that multiple Executors use.
|
|
|
|
|
That means debugger stuff has to come out of Instruction.
|
|
|
|
|
*/
|
|
|
|
|
unsigned nLines;
|
|
|
|
|
|
|
|
|
|
std::vector<BObjectRef> fparams;
|
|
|
|
|
|
|
|
|
|
friend class ExecutorModule;
|
|
|
|
|
void setFunctionResult( BObjectImp* imp );
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
int getParams( unsigned howMany );
|
2024-08-06 23:34:24 +02:00
|
|
|
void expandParams();
|
2016-02-19 19:26:35 +01:00
|
|
|
void cleanParams();
|
|
|
|
|
|
|
|
|
|
public:
|
2024-07-28 22:51:04 +02:00
|
|
|
// Creates a new continuation object to call `funcref` with arguments `args`,
|
|
|
|
|
// calling a core `callback` with the return value.
|
|
|
|
|
//
|
|
|
|
|
// Responsible for moving the arguments to the `ValueStack` stack,
|
|
|
|
|
// expanding/shrinking as needed. The executor, when seeing a `BContinuation`
|
|
|
|
|
// inside `ins_call_method_id`, will "translate" it to a `BFunctionRef` to
|
|
|
|
|
// call. The handling of `BFunctionRef`s _inside_ `ins_call_method_id`
|
|
|
|
|
// requires arguments to be on `ValueStack`.
|
|
|
|
|
//
|
|
|
|
|
// Since this runs inside `ins_call_method_id`, it can **only** be used in
|
|
|
|
|
// `<object>.<method>` calls. Extending where this is called will require
|
|
|
|
|
// changing implementation.
|
|
|
|
|
//
|
|
|
|
|
// Returns `BContinuation*` on success, `BError*` on failure (if provided
|
|
|
|
|
// funcref is not a BFunctionRef).
|
|
|
|
|
template <typename Callback>
|
2025-11-17 18:02:45 +01:00
|
|
|
BObjectImp* makeContinuation( BObjectRef funcref, Callback&& callback, BObjectRefVec args = {} );
|
2024-07-28 22:51:04 +02:00
|
|
|
|
|
|
|
|
// Runs the existing continuation object with arguments `args`.
|
|
|
|
|
//
|
|
|
|
|
// Responsible for moving the arguments to the `fparams` stack. The handling
|
|
|
|
|
// of `BFunctionRef`s _outside_ `ins_call_method_id` requires arguments to be
|
|
|
|
|
// on `fparams` (as they are moved to `ValueStack` in `ins_call_method_id`).
|
|
|
|
|
BContinuation* withContinuation( BContinuation* continuation, BObjectRefVec args = {} );
|
|
|
|
|
|
2025-01-05 17:22:55 +01:00
|
|
|
// Runs `callback( unsigned int PC )` for every frame in the call stack.
|
|
|
|
|
template <typename Callback>
|
2025-11-17 18:02:45 +01:00
|
|
|
void walkCallStack( Callback&& callback );
|
2025-01-05 17:22:55 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int makeString( unsigned param );
|
|
|
|
|
bool hasParams( unsigned howmany ) const { return ( fparams.size() >= howmany ); }
|
|
|
|
|
size_t numParams() const { return fparams.size(); }
|
|
|
|
|
BObjectImp* getParamImp( unsigned param );
|
|
|
|
|
BObjectImp* getParamImp( unsigned param, BObjectImp::BObjectType type );
|
|
|
|
|
BObjectImp* getParamImp2( unsigned param, BObjectImp::BObjectType type );
|
|
|
|
|
BObject* getParamObj( unsigned param );
|
|
|
|
|
|
|
|
|
|
const String* getStringParam( unsigned param );
|
|
|
|
|
const BLong* getLongParam( unsigned param );
|
|
|
|
|
|
|
|
|
|
bool getStringParam( unsigned param, const String*& pstr );
|
2018-12-31 11:59:47 +01:00
|
|
|
bool getUnicodeStringParam( unsigned param, const String*& pstr ); // accepts also BLong array
|
2016-02-19 19:26:35 +01:00
|
|
|
bool getParam( unsigned param, int& value );
|
|
|
|
|
bool getParam( unsigned param, int& value, int maxval );
|
|
|
|
|
bool getParam( unsigned param, int& value, int minval, int maxval );
|
|
|
|
|
bool getRealParam( unsigned param, double& value );
|
|
|
|
|
bool getObjArrayParam( unsigned param, ObjArray*& pobjarr );
|
|
|
|
|
|
|
|
|
|
bool getParam( unsigned param, unsigned& value );
|
|
|
|
|
|
|
|
|
|
bool getParam( unsigned param, unsigned short& value );
|
|
|
|
|
bool getParam( unsigned param, unsigned short& value, unsigned short maxval );
|
|
|
|
|
bool getParam( unsigned param, unsigned short& value, unsigned short minval,
|
|
|
|
|
unsigned short maxval );
|
|
|
|
|
|
|
|
|
|
bool getParam( unsigned param, short& value );
|
|
|
|
|
bool getParam( unsigned param, short& value, short maxval );
|
|
|
|
|
bool getParam( unsigned param, short& value, short minval, short maxval );
|
2021-09-12 14:39:06 +02:00
|
|
|
bool getParam( unsigned param, signed char& value );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2024-01-20 12:38:25 +08:00
|
|
|
bool getParam( unsigned param, bool& value );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
BApplicObjBase* getApplicObjParam( unsigned param, const BApplicObjType* object_type );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* paramAsString( unsigned param );
|
|
|
|
|
double paramAsDouble( unsigned param );
|
|
|
|
|
int paramAsLong( unsigned param );
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
int makeDouble( unsigned param );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BObject* getParam( unsigned param );
|
|
|
|
|
|
2026-01-16 13:22:43 +01:00
|
|
|
BObject getValue();
|
|
|
|
|
BObjectRef getObjRef();
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
int getToken( Token& token, unsigned position );
|
|
|
|
|
BObjectRef& LocalVar( unsigned int varnum );
|
|
|
|
|
BObjectRef& GlobalVar( unsigned int varnum );
|
|
|
|
|
int makeGlobal( const Token& token );
|
|
|
|
|
void popParam( const Token& token );
|
|
|
|
|
void popParamByRef( const Token& token );
|
|
|
|
|
void getArg( const Token& token );
|
|
|
|
|
void pushArg( BObjectImp* arg );
|
|
|
|
|
void pushArg( const BObjectRef& ref );
|
|
|
|
|
|
|
|
|
|
static BObjectRef addmember( BObject& left, const BObject& right );
|
|
|
|
|
static BObjectRef removemember( BObject& left, const BObject& right );
|
|
|
|
|
static BObjectRef checkmember( BObject& left, const BObject& right );
|
|
|
|
|
void addmember2( BObject& left, const BObject& right );
|
2018-10-13 21:46:41 +02:00
|
|
|
static bool builtinMethodForced( const char*& methodname );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
// execmodules: modules associated with the current program. References modules owned by
|
|
|
|
|
// availmodules.
|
|
|
|
|
std::vector<ExecutorModule*> execmodules;
|
|
|
|
|
std::vector<ExecutorModule*> availmodules; // owns
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Executor();
|
|
|
|
|
virtual ~Executor();
|
2024-08-04 15:13:00 +02:00
|
|
|
Executor( const Executor& exec ) = delete;
|
|
|
|
|
Executor& operator=( const Executor& exec ) = delete;
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
void addModule( ExecutorModule* module ); // NOTE, executor deletes its modules when done
|
|
|
|
|
ExecutorModule* findModule( const std::string& name );
|
|
|
|
|
|
|
|
|
|
ModuleFunction* current_module_function;
|
|
|
|
|
// NOTE: the debugger code expects these to be virtual..
|
|
|
|
|
void execFunc( const Token& token );
|
|
|
|
|
void execInstr();
|
|
|
|
|
|
|
|
|
|
void ins_nop( const Instruction& ins );
|
|
|
|
|
void ins_jmpiftrue( const Instruction& ins );
|
|
|
|
|
void ins_jmpiffalse( const Instruction& ins );
|
2020-04-23 19:12:04 -07:00
|
|
|
void ins_skipiftrue_else_consume( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_globalvar( const Instruction& ins );
|
|
|
|
|
void ins_localvar( const Instruction& ins );
|
|
|
|
|
void ins_makeLocal( const Instruction& ins );
|
|
|
|
|
void ins_declareArray( const Instruction& ins );
|
2024-01-20 12:38:25 +08:00
|
|
|
void ins_bool( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_long( const Instruction& ins );
|
|
|
|
|
void ins_double( const Instruction& ins );
|
2024-08-10 15:27:25 +02:00
|
|
|
void ins_classinst( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_string( const Instruction& ins );
|
2025-11-17 18:02:45 +01:00
|
|
|
void ins_regexp( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_error( const Instruction& ins );
|
|
|
|
|
void ins_struct( const Instruction& ins );
|
2024-08-06 23:34:24 +02:00
|
|
|
void ins_spread( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_array( const Instruction& ins );
|
|
|
|
|
void ins_dictionary( const Instruction& ins );
|
|
|
|
|
void ins_uninit( const Instruction& ins );
|
|
|
|
|
void ins_ident( const Instruction& ins );
|
|
|
|
|
void ins_unminus( const Instruction& ins );
|
2019-09-21 14:56:06 +02:00
|
|
|
void ins_unplusplus( const Instruction& ins );
|
|
|
|
|
void ins_unminusminus( const Instruction& ins );
|
2019-09-22 00:34:14 +02:00
|
|
|
void ins_unplusplus_post( const Instruction& ins );
|
2019-09-22 11:04:57 +02:00
|
|
|
void ins_unminusminus_post( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
void ins_logical_and( const Instruction& ins );
|
|
|
|
|
void ins_logical_or( const Instruction& ins );
|
|
|
|
|
void ins_logical_not( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_bitwise_not( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_set_member( const Instruction& ins );
|
|
|
|
|
void ins_set_member_consume( const Instruction& ins );
|
|
|
|
|
void ins_get_member( const Instruction& ins );
|
2018-01-29 21:55:48 +01:00
|
|
|
void ins_get_member_id( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_consume( const Instruction& ins ); // test id
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_set_member_id_consume_plusequal( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_consume_minusequal( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_consume_timesequal( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_consume_divideequal( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_consume_modulusequal( const Instruction& ins ); // test id
|
2019-09-26 07:06:45 +02:00
|
|
|
void ins_set_member_id_unplusplus( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_unminusminus( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_unplusplus_post( const Instruction& ins ); // test id
|
|
|
|
|
void ins_set_member_id_unminusminus_post( const Instruction& ins ); // test id
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
void ins_assign_localvar( const Instruction& ins );
|
|
|
|
|
void ins_assign_globalvar( const Instruction& ins );
|
|
|
|
|
void ins_assign_consume( const Instruction& ins );
|
|
|
|
|
void ins_consume( const Instruction& ins );
|
|
|
|
|
void ins_assign( const Instruction& ins );
|
|
|
|
|
void ins_array_assign( const Instruction& ins );
|
|
|
|
|
void ins_array_assign_consume( const Instruction& ins );
|
|
|
|
|
void ins_multisubscript_assign( const Instruction& ins );
|
|
|
|
|
void ins_multisubscript_assign_consume( const Instruction& ins );
|
|
|
|
|
void ins_multisubscript( const Instruction& ins );
|
|
|
|
|
|
2025-02-17 21:59:42 +01:00
|
|
|
void ins_unpack_sequence( const Instruction& ins );
|
|
|
|
|
void ins_unpack_indices( const Instruction& ins );
|
|
|
|
|
void ins_take_local( const Instruction& ins );
|
|
|
|
|
void ins_take_global( const Instruction& ins );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_add( const Instruction& ins );
|
|
|
|
|
void ins_subtract( const Instruction& ins );
|
|
|
|
|
void ins_mult( const Instruction& ins );
|
|
|
|
|
void ins_div( const Instruction& ins );
|
|
|
|
|
void ins_modulus( const Instruction& ins );
|
|
|
|
|
|
2024-08-26 22:37:22 +02:00
|
|
|
void ins_is( const Instruction& ins );
|
|
|
|
|
|
2021-03-11 22:48:16 +01:00
|
|
|
void ins_interpolate_string( const Instruction& ins );
|
|
|
|
|
void ins_format_expression( const Instruction& ins );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_insert_into( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_plusequal( const Instruction& ins );
|
|
|
|
|
void ins_minusequal( const Instruction& ins );
|
|
|
|
|
void ins_timesequal( const Instruction& ins );
|
|
|
|
|
void ins_divideequal( const Instruction& ins );
|
|
|
|
|
void ins_modulusequal( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_bitshift_right( const Instruction& ins );
|
|
|
|
|
void ins_bitshift_left( const Instruction& ins );
|
|
|
|
|
void ins_bitwise_and( const Instruction& ins );
|
|
|
|
|
void ins_bitwise_xor( const Instruction& ins );
|
|
|
|
|
void ins_bitwise_or( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_equal( const Instruction& ins );
|
|
|
|
|
void ins_notequal( const Instruction& ins );
|
|
|
|
|
void ins_lessthan( const Instruction& ins );
|
|
|
|
|
void ins_lessequal( const Instruction& ins );
|
|
|
|
|
void ins_greaterthan( const Instruction& ins );
|
|
|
|
|
void ins_greaterequal( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_goto( const Instruction& ins );
|
|
|
|
|
void ins_arraysubscript( const Instruction& ins );
|
|
|
|
|
void ins_func( const Instruction& ins );
|
|
|
|
|
void ins_call_method( const Instruction& ins );
|
|
|
|
|
void ins_call_method_id( const Instruction& ins );
|
|
|
|
|
void ins_statementbegin( const Instruction& ins );
|
|
|
|
|
void ins_progend( const Instruction& ins );
|
|
|
|
|
void ins_makelocal( const Instruction& ins );
|
2024-08-25 11:44:06 +02:00
|
|
|
void ins_check_mro( const Instruction& ins );
|
2016-02-19 19:26:35 +01:00
|
|
|
void ins_jsr_userfunc( const Instruction& ins );
|
|
|
|
|
void ins_pop_param( const Instruction& ins );
|
|
|
|
|
void ins_pop_param_byref( const Instruction& ins );
|
|
|
|
|
void ins_get_arg( const Instruction& ins );
|
|
|
|
|
void ins_leave_block( const Instruction& ins );
|
|
|
|
|
void ins_gosub( const Instruction& ins );
|
|
|
|
|
void ins_return( const Instruction& ins );
|
|
|
|
|
void ins_exit( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_member( const Instruction& ins );
|
|
|
|
|
void ins_addmember( const Instruction& ins );
|
|
|
|
|
void ins_removemember( const Instruction& ins );
|
|
|
|
|
void ins_checkmember( const Instruction& ins );
|
|
|
|
|
void ins_dictionary_addmember( const Instruction& ins );
|
|
|
|
|
void ins_addmember2( const Instruction& ins );
|
|
|
|
|
void ins_addmember_assign( const Instruction& ins );
|
|
|
|
|
void ins_in( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_initforeach( const Instruction& ins );
|
|
|
|
|
void ins_stepforeach( const Instruction& ins );
|
|
|
|
|
|
|
|
|
|
void ins_casejmp( const Instruction& ins );
|
|
|
|
|
void ins_initfor( const Instruction& ins );
|
|
|
|
|
void ins_nextfor( const Instruction& ins );
|
|
|
|
|
|
2018-02-03 19:05:22 +01:00
|
|
|
void ins_funcref( const Instruction& ins );
|
2024-07-29 22:30:52 +02:00
|
|
|
void ins_functor( const Instruction& ins );
|
2018-02-03 19:05:22 +01:00
|
|
|
|
2025-07-28 21:48:34 +02:00
|
|
|
void ins_logical_jump( const Instruction& ins );
|
|
|
|
|
void ins_logical_convert( const Instruction& ins );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
static int ins_casejmp_findlong( const Token& token, BLong* blong );
|
2024-01-20 12:38:25 +08:00
|
|
|
static int ins_casejmp_findbool( const Token& token, BBoolean* bbool );
|
2016-02-19 19:26:35 +01:00
|
|
|
static int ins_casejmp_findstring( const Token& token, String* bstringimp );
|
2024-01-20 12:38:25 +08:00
|
|
|
static int ins_casejmp_finduninit( const Token& token );
|
2016-02-19 19:26:35 +01:00
|
|
|
static int ins_casejmp_finddefault( const Token& token );
|
|
|
|
|
|
2017-07-30 20:10:19 +02:00
|
|
|
bool running_to_completion() const;
|
|
|
|
|
void set_running_to_completion( bool to_completion );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
bool runnable() const;
|
|
|
|
|
void calcrunnable();
|
|
|
|
|
|
|
|
|
|
bool halt() const;
|
|
|
|
|
void sethalt( bool halt );
|
|
|
|
|
|
2024-08-10 17:43:21 +02:00
|
|
|
// Takes ownership of `continuation`. If `funcref` is present, checks if jump
|
|
|
|
|
// is "external" (ie. current program is different than funcref's), and if so,
|
|
|
|
|
// sets up members (Globals2, nLines, prog_, execmodules) accordingly.
|
|
|
|
|
void jump( int target_PC, BContinuation* continuation, BFunctionRef* funcref );
|
|
|
|
|
|
2025-01-05 17:22:55 +01:00
|
|
|
// Returns the current execution stack of this executor. The returned object
|
|
|
|
|
// is either a string containing a line for each stack frame, or an array of
|
|
|
|
|
// objects representing each stack frame.
|
|
|
|
|
//
|
|
|
|
|
// Will load the debug symbols for the current program. If debug symbols are
|
|
|
|
|
// not available, only program counter information will be available, and
|
|
|
|
|
// filename+line+function name will be empty.
|
|
|
|
|
BObjectImp* get_stacktrace( bool as_array );
|
2024-08-10 17:43:21 +02:00
|
|
|
|
2024-01-28 15:49:55 +07:00
|
|
|
bool attach_debugger( std::weak_ptr<ExecutorDebugListener> listener = {},
|
|
|
|
|
bool set_attaching = true );
|
2016-02-19 19:26:35 +01:00
|
|
|
void detach_debugger();
|
2024-07-16 12:41:55 +02:00
|
|
|
void print_to_debugger( const std::string& message );
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string dbg_get_instruction( size_t atPC ) const;
|
2024-01-12 06:51:44 +01:00
|
|
|
void dbg_get_instruction( size_t atPC, std::string& os ) const;
|
2016-02-19 19:26:35 +01:00
|
|
|
void dbg_ins_trace();
|
|
|
|
|
void dbg_step_into();
|
|
|
|
|
void dbg_step_over();
|
2024-01-28 15:49:55 +07:00
|
|
|
void dbg_step_out();
|
2016-02-19 19:26:35 +01:00
|
|
|
void dbg_run();
|
|
|
|
|
void dbg_break();
|
|
|
|
|
void dbg_setbp( unsigned atPC );
|
|
|
|
|
void dbg_clrbp( unsigned atPC );
|
2024-01-28 15:49:55 +07:00
|
|
|
void dbg_clrbps( const std::set<unsigned>& PCs );
|
2016-02-19 19:26:35 +01:00
|
|
|
void dbg_clrallbp();
|
|
|
|
|
|
|
|
|
|
bool exec();
|
|
|
|
|
void reinitExec();
|
|
|
|
|
void initForFnCall( unsigned in_PC );
|
|
|
|
|
void show_context( unsigned atPC );
|
2024-01-12 06:51:44 +01:00
|
|
|
void show_context( std::string& os, unsigned atPC );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2024-08-04 17:13:30 +02:00
|
|
|
void call_function_reference( BFunctionRef* funcref, BContinuation* continuation,
|
2024-09-04 13:28:50 +02:00
|
|
|
const Instruction& jmp );
|
2024-08-04 17:13:30 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int getDebugLevel() { return debug_level; }
|
|
|
|
|
void setDebugLevel( DEBUG_LEVEL level ) { debug_level = level; }
|
|
|
|
|
void setViewMode( bool vm ) { viewmode_ = vm; }
|
|
|
|
|
const std::string& scriptname() const;
|
|
|
|
|
bool empty_scriptname();
|
|
|
|
|
const EScriptProgram* prog() const;
|
|
|
|
|
|
2026-05-31 11:45:35 +02:00
|
|
|
virtual unsigned int pid() const { return 0; };
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
private:
|
|
|
|
|
ref_ptr<EScriptProgram> prog_;
|
|
|
|
|
bool prog_ok_;
|
|
|
|
|
bool viewmode_;
|
2018-01-29 21:55:48 +01:00
|
|
|
|
2017-07-30 20:10:19 +02:00
|
|
|
bool runs_to_completion_;
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2024-01-28 15:49:55 +07:00
|
|
|
std::unique_ptr<ExecutorDebugEnvironment> dbg_env_;
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
BObjectImp* func_result_;
|
|
|
|
|
|
2024-07-28 22:51:04 +02:00
|
|
|
void printStack( const std::string& message );
|
|
|
|
|
|
2024-08-04 15:13:00 +02:00
|
|
|
protected:
|
2026-01-14 19:12:19 +01:00
|
|
|
friend class BClassInstance;
|
2024-08-04 15:13:00 +02:00
|
|
|
void cleanup();
|
2024-08-25 11:44:06 +02:00
|
|
|
|
|
|
|
|
struct ClassMethodKey
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<EScriptProgram> prog;
|
|
|
|
|
unsigned index;
|
|
|
|
|
std::string method_name;
|
|
|
|
|
bool operator<( const ClassMethodKey& other ) const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::map<ClassMethodKey, BObjectRef /*function ref*/> class_methods;
|
2016-02-19 19:26:35 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline const std::string& Executor::scriptname() const
|
|
|
|
|
{
|
|
|
|
|
return prog_->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool Executor::empty_scriptname()
|
|
|
|
|
{
|
|
|
|
|
return prog_->name.get().empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const EScriptProgram* Executor::prog() const
|
|
|
|
|
{
|
|
|
|
|
return prog_.get();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 13:22:43 +01:00
|
|
|
inline bool Executor::runnable() const
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
return run_ok_;
|
|
|
|
|
}
|
|
|
|
|
inline void Executor::calcrunnable()
|
|
|
|
|
{
|
|
|
|
|
run_ok_ = !error_ && !halt_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void Executor::seterror( bool err )
|
|
|
|
|
{
|
|
|
|
|
error_ = err;
|
|
|
|
|
calcrunnable();
|
|
|
|
|
}
|
|
|
|
|
inline bool Executor::error() const
|
|
|
|
|
{
|
|
|
|
|
return error_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool Executor::halt() const
|
|
|
|
|
{
|
|
|
|
|
return halt_;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 20:10:19 +02:00
|
|
|
inline bool Executor::running_to_completion() const
|
|
|
|
|
{
|
|
|
|
|
return runs_to_completion_;
|
|
|
|
|
}
|
|
|
|
|
inline void Executor::set_running_to_completion( bool to_completion )
|
|
|
|
|
{
|
|
|
|
|
runs_to_completion_ = to_completion;
|
|
|
|
|
}
|
2025-08-08 09:08:12 +02:00
|
|
|
|
|
|
|
|
#ifdef ESCRIPT_PROFILE
|
|
|
|
|
class EscriptProfiler
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
EscriptProfiler( ExecutorModule* em, const ModuleFunction* modfunc,
|
|
|
|
|
const std::vector<BObjectRef>& fparams );
|
|
|
|
|
|
|
|
|
|
EscriptProfiler( const Instruction& ins, const BObjectRef& leftref,
|
|
|
|
|
const std::vector<BObjectRef>& fparams );
|
|
|
|
|
EscriptProfiler( const Instruction& ins, const BObjectImp* callee, const char* method_name,
|
|
|
|
|
const std::vector<BObjectRef>& fparams );
|
|
|
|
|
~EscriptProfiler();
|
|
|
|
|
static std::string result();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Tools::HighPerfTimer timer_{};
|
|
|
|
|
std::string name_{};
|
|
|
|
|
struct profile_instr
|
|
|
|
|
{
|
|
|
|
|
int64_t sum;
|
|
|
|
|
int64_t max;
|
|
|
|
|
int64_t min;
|
|
|
|
|
int64_t count;
|
|
|
|
|
};
|
|
|
|
|
static std::map<std::string, profile_instr> escript_profile_map_;
|
|
|
|
|
};
|
|
|
|
|
#define ESCRIPT_PROFILER EscriptProfiler escript_profiler
|
|
|
|
|
#else
|
|
|
|
|
#define ESCRIPT_PROFILER( ... )
|
|
|
|
|
#endif
|
2018-12-31 11:59:47 +01:00
|
|
|
} // namespace Bscript
|
|
|
|
|
} // namespace Pol
|
2016-02-11 22:54:43 +01:00
|
|
|
#endif
|