project64/Source/Project64/UserInterface/Debugger/ScriptInstance.h

256 lines
10 KiB
C
Raw Normal View History

2017-08-18 05:08:22 +00:00
#pragma once
#include "stdafx.h"
#include <3rdParty/duktape/duktape.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
class CScriptSystem;
typedef enum {
2017-09-13 10:36:03 +00:00
STATE_STARTED, // initial evaluation & execution
STATE_RUNNING, // event loop running with pending events
STATE_STOPPED, // no pending events
STATE_INVALID
2017-08-18 05:08:22 +00:00
} INSTANCE_STATE;
class CScriptInstance
{
2017-09-13 10:36:03 +00:00
typedef enum {
EVENT_READ,
EVENT_WRITE,
EVENT_ACCEPT,
EVENT_CONNECT
} IOEVENTTYPE;
typedef struct {
OVERLAPPED ovl;
IOEVENTTYPE eventType;
HANDLE fd;
HANDLE childFd; // accepted socket
bool bSocket;
UINT id;
void* data;
DWORD dataLen; // changed to bytes transferred after event is fired
void* callback;
} IOLISTENER;
// Wrapper for file/socket descriptor and completion port
typedef struct {
HANDLE fd;
HANDLE iocp;
bool bSocket;
} IOFD;
typedef enum {
EVENT_STATUS_OK,
EVENT_STATUS_INTERRUPTED,
EVENT_STATUS_ERROR
} EVENT_STATUS;
2017-08-18 05:08:22 +00:00
// For synchronous file operations
typedef struct
{
FILE* fp;
int fd;
} FILE_FD;
typedef BOOL(__stdcall *Dynamic_CancelIoEx)(HANDLE, LPOVERLAPPED);
2017-08-18 05:08:22 +00:00
public:
2017-09-13 10:36:03 +00:00
CScriptInstance(CDebuggerUI* debugger);
~CScriptInstance();
2017-08-18 05:08:22 +00:00
2017-09-13 10:36:03 +00:00
void Start(char* path);
void ForceStop();
void Invoke(void* heapptr, uint32_t param = 0);
void Invoke2(void* heapptr, uint32_t param = 0, uint32_t param2 = 0);
2017-09-13 10:36:03 +00:00
INSTANCE_STATE GetState();
friend class PendingEval;
void EvalAsync(const char* jsCode);
const char* Eval(const char* jsCode);
2017-08-18 05:08:22 +00:00
private:
2017-09-13 10:36:03 +00:00
duk_context* m_Ctx;
duk_context* DukContext();
char* m_TempPath;
HANDLE m_hThread;
HANDLE m_hIOCompletionPort;
CRITICAL_SECTION m_CriticalSection;
vector<IOFD> m_AsyncFiles;
2017-09-13 10:36:03 +00:00
vector<IOLISTENER*> m_Listeners;
UINT m_NextListenerId;
vector<FILE_FD> m_Files;
2017-09-13 10:36:03 +00:00
CDebuggerUI* m_Debugger;
CScriptSystem* m_ScriptSystem;
INSTANCE_STATE m_State;
static DWORD CALLBACK StartThread(CScriptInstance* _this);
void StartScriptProc();
void StartEventLoop();
bool HaveEvents();
EVENT_STATUS WaitForEvent(IOLISTENER** lpListener);
void SetState(INSTANCE_STATE state);
void StateChanged();
void CleanUp();
2017-09-13 10:36:03 +00:00
void QueueAPC(PAPCFUNC userProc, ULONG_PTR param = 0);
void AddAsyncFile(HANDLE fd, bool bSocket = false);
void CloseAsyncFile(HANDLE fd);
void CloseAllAsyncFiles();
void RemoveAsyncFile(HANDLE fd);
2017-09-13 10:36:03 +00:00
HANDLE CreateSocket();
IOLISTENER* AddListener(HANDLE fd, IOEVENTTYPE evt, void* jsCallback, void* data = NULL, int dataLen = 0);
void RemoveListener(IOLISTENER* lpListener);
void RemoveListenerByIndex(UINT index);
void RemoveListenersByFd(HANDLE fd);
void InvokeListenerCallback(IOLISTENER* lpListener);
static void CALLBACK EvalAsyncCallback(ULONG_PTR evalWait);
bool AddFile(const char* path, const char* mode, int* fd); // return fd
void CloseFile(int fd);
FILE* GetFilePointer(int fd);
void CloseAllFiles();
2017-09-13 10:36:03 +00:00
const char* EvalFile(const char* jsPath);
// Handle to to dynamically load CancelIoEx for Windows XP compatibility
HMODULE m_hKernel;
Dynamic_CancelIoEx m_CancelIoEx;
2017-09-13 10:36:03 +00:00
// Lookup list of CScriptInstance instances for static js_* functions
static vector<CScriptInstance*> Cache;
static void CacheInstance(CScriptInstance* _this);
static void UncacheInstance(CScriptInstance* _this);
static CScriptInstance* FetchInstance(duk_context* ctx);
// Bound functions (_native object)
static duk_ret_t js_ioSockCreate(duk_context*);
static duk_ret_t js_ioSockListen(duk_context*);
static duk_ret_t js_ioSockAccept(duk_context*); // async
static duk_ret_t js_ioSockConnect(duk_context*); // async
static duk_ret_t js_ioRead(duk_context*); // async
static duk_ret_t js_ioWrite(duk_context*); // async
static duk_ret_t js_ioClose(duk_context*); // (fd) ; file or socket
static duk_ret_t js_MsgBox(duk_context*); // (message, caption)
static duk_ret_t js_AddCallback(duk_context*); // (hookId, callback, tag) ; external events
static duk_ret_t js_RemoveCallback(duk_context*); // (callbackId)
static duk_ret_t js_GetPCVal(duk_context*); // ()
static duk_ret_t js_SetPCVal(duk_context*); // (value)
static duk_ret_t js_GetHIVal(duk_context*); // (bUpper)
static duk_ret_t js_SetHIVal(duk_context*); // (bUpper, value)
static duk_ret_t js_GetLOVal(duk_context*); // (bUpper)
static duk_ret_t js_SetLOVal(duk_context*); // (bUpper, value)
static duk_ret_t js_GetGPRVal(duk_context*); // (regNum, bUpper)
static duk_ret_t js_SetGPRVal(duk_context*); // (regNum, bUpper, value)
static duk_ret_t js_GetFPRVal(duk_context*); // (regNum, bDouble)
static duk_ret_t js_SetFPRVal(duk_context*); // (regNum, bDouble, value)
2019-01-24 18:48:26 +00:00
static duk_ret_t js_GetCauseVal(duk_context*); // ()
static duk_ret_t js_SetCauseVal(duk_context*); // (value)
2017-09-13 10:36:03 +00:00
static duk_ret_t js_GetROMInt(duk_context*); // (address, bitwidth, signed)
static duk_ret_t js_GetROMFloat(duk_context*); // (address, bDouble)
static duk_ret_t js_GetROMBlock(duk_context*); // (address, nBytes) ; returns Buffer
static duk_ret_t js_GetROMString(duk_context*); // (address[, maxLen]) ; fetch zero terminated string from memory
static duk_ret_t js_GetRDRAMInt(duk_context*); // (address, bitwidth, signed)
static duk_ret_t js_SetRDRAMInt(duk_context*); // (address, bitwidth, signed, newValue)
static duk_ret_t js_GetRDRAMFloat(duk_context*); // (address, bDouble)
static duk_ret_t js_SetRDRAMFloat(duk_context*); // (address, bDouble, newValue)
static duk_ret_t js_GetRDRAMBlock(duk_context*); // (address, nBytes) ; returns Buffer
static duk_ret_t js_GetRDRAMString(duk_context*); // (address[, maxLen]) ; fetch zero terminated string from memory
static duk_ret_t js_ConsolePrint(duk_context*);
static duk_ret_t js_ConsoleClear(duk_context*);
static duk_ret_t js_BreakHere(duk_context*);
2017-09-13 10:36:03 +00:00
static duk_ret_t js_Pause(duk_context*); // () ; pauses emulation
static duk_ret_t js_ShowCommands(duk_context*); // ([address]) ; shows commands window
static duk_ret_t js_ScreenPrint(duk_context*); // (x, y, text)
static duk_ret_t js_FSOpen(duk_context*); // (path, flags) ; returns fd
static duk_ret_t js_FSClose(duk_context*); // (fd)
static duk_ret_t js_FSWrite(duk_context*); // (fd, buffer[, offset[, length[, position]]])
static duk_ret_t js_FSRead(duk_context*); // (fd, buffer, offset, length, position)
static duk_ret_t js_FSFStat(duk_context*); // (fd)
static duk_ret_t js_FSStat(duk_context*); // (path)
static duk_ret_t js_FSMkDir(duk_context*); // (path)
static duk_ret_t js_FSRmDir(duk_context*); // (path)
static duk_ret_t js_FSUnlink(duk_context*); // (path)
static duk_ret_t js_FSReadDir(duk_context*); // (path)
2017-09-13 10:36:03 +00:00
static constexpr duk_function_list_entry NativeFunctions[] =
{
{ "addCallback", js_AddCallback, DUK_VARARGS },
{ "removeCallback", js_RemoveCallback, DUK_VARARGS },
{ "setPCVal", js_SetPCVal, DUK_VARARGS },
{ "getPCVal", js_GetPCVal, DUK_VARARGS },
{ "setHIVal", js_SetHIVal, DUK_VARARGS },
{ "getHIVal", js_GetHIVal, DUK_VARARGS },
{ "setLOVal", js_SetLOVal, DUK_VARARGS },
{ "getLOVal", js_GetLOVal, DUK_VARARGS },
{ "setGPRVal", js_SetGPRVal, DUK_VARARGS },
{ "getGPRVal", js_GetGPRVal, DUK_VARARGS },
{ "setFPRVal", js_SetFPRVal, DUK_VARARGS },
{ "getFPRVal", js_GetFPRVal, DUK_VARARGS },
2019-01-24 18:48:26 +00:00
{ "setCauseVal", js_SetCauseVal, DUK_VARARGS },
{ "getCauseVal", js_GetCauseVal, DUK_VARARGS },
2017-09-13 10:36:03 +00:00
{ "getROMInt", js_GetROMInt, DUK_VARARGS },
{ "getROMFloat", js_GetROMFloat, DUK_VARARGS },
{ "getROMString", js_GetROMString, DUK_VARARGS },
{ "getROMBlock", js_GetROMBlock, DUK_VARARGS },
{ "getRDRAMInt", js_GetRDRAMInt, DUK_VARARGS },
{ "setRDRAMInt", js_SetRDRAMInt, DUK_VARARGS },
{ "getRDRAMFloat", js_GetRDRAMFloat, DUK_VARARGS },
{ "setRDRAMFloat", js_SetRDRAMFloat, DUK_VARARGS },
{ "getRDRAMBlock", js_GetRDRAMBlock, DUK_VARARGS },
{ "getRDRAMString", js_GetRDRAMString, DUK_VARARGS },
{ "sockCreate", js_ioSockCreate, DUK_VARARGS },
{ "sockListen", js_ioSockListen, DUK_VARARGS },
{ "sockAccept", js_ioSockAccept, DUK_VARARGS },
{ "sockConnect", js_ioSockConnect, DUK_VARARGS },
{ "close", js_ioClose, DUK_VARARGS },
{ "write", js_ioWrite, DUK_VARARGS },
{ "read", js_ioRead, DUK_VARARGS },
{ "msgBox", js_MsgBox, DUK_VARARGS },
{ "consolePrint", js_ConsolePrint, DUK_VARARGS },
{ "consoleClear", js_ConsoleClear, DUK_VARARGS },
{ "pause", js_Pause, DUK_VARARGS },
{ "showCommands", js_ShowCommands, DUK_VARARGS },
{ "breakHere", js_BreakHere, DUK_VARARGS },
2017-09-13 10:36:03 +00:00
{ "screenPrint", js_ScreenPrint, DUK_VARARGS },
{ "fsOpen", js_FSOpen, DUK_VARARGS },
{ "fsClose", js_FSClose, DUK_VARARGS },
{ "fsWrite", js_FSWrite, DUK_VARARGS },
{ "fsRead", js_FSRead, DUK_VARARGS },
{ "fsFStat", js_FSFStat, DUK_VARARGS },
{ "fsStat", js_FSStat, DUK_VARARGS },
{ "fsUnlink", js_FSUnlink, DUK_VARARGS },
{ "fsMkDir", js_FSMkDir, DUK_VARARGS },
{ "fsRmDir", js_FSRmDir, DUK_VARARGS },
{ "fsReadDir", js_FSReadDir, DUK_VARARGS },
2017-09-13 10:36:03 +00:00
{ NULL, NULL, 0 }
};
2017-08-18 05:08:22 +00:00
};