Common: reformat (#4720)

* common: format AlignedMalloc.cpp

* common: format AppTrait.h

* common: format Assertions.h

* common: format CheckedStaticBox

* common: format Console

* common: format Dependencies.h

* common: format EmbeddedImage

* common: format EventSource

* common: format Exceptions

* common: format FastFormatString.cpp

* common: format General.h

* common: format InitInterface

* common: format MathUtils.h

* common: format MemsetFast/MemcpyFast

* common: format Mutex.cpp

* common: format PageFaultSource.h

* common: format Path.h

* common: format PathUtils.cpp

* common: format Pcsx2Types.h

* common: format Perf

* common: format PersistentThread.h

* common: format RwMutex

* common: format SafeArray

* common: format ScopedAlloc.h

* common: format ScopedPtrMT.h

* common: format Semaphore.cpp

* common: format StringHelpers

* common: format ThreadTools.cpp

* common: format Threading.h

* common: format ThreadingDialogs

* common: format ThreadingInternal.h

* common: format TraceLog.h

* common: format VirtualMemory.cpp

* common: format pxCheckBox

* common: format pxEvents.h

* common: format pxForwardDefs.h

* common: format pxRadioPanel

* common: format pxStaticText

* common: format pxStreams

* common: format pxTranslate.cpp

* common: format pxWindowTextWriter.cpp

* common: format wxAppWithHelpers

* common: format wxBaseTools.h

* common: format wxGuiTools

* common: format wxHelpers.cpp

* common: format Darwin directory

* common: format Linux directory

* common: format Windows directory

* common: format LnxCpuDetect.cpp

* common: format WinCpuDetect.cpp

* common: format bmi.cpp

* common: format cpudetect.cpp

* common: format cpu_detect_internal.h

* common: format fpu.cpp

* common: format groups.cpp

* common: format instructions.h

* common: format internal.h

* common: format jmp.cpp

* common: format legacy.cpp

* common: format legacy_instructions.h

* common: format legacy_internal.h

* common: format movs.cpp

* common: format simd.cpp

* common: format tools.h

* common: format x86emitter.cpp

* common: format x86types.h

* common: format bmi.h

* common: format dwshift.h

* common: format group1.h group2.h group3.h

* common: format incdec.h

* common: format jmpcall.h

* common: format movs.h

* common: format simd_arithmetic.h

* common: format simd_comparisons.h

* common: format simd_helpers.h

* common: format simd_moremovs.h

* common: format simd_shufflepack.h

* common: format simd_templated_helpers.h

* common: format test.h
This commit is contained in:
Kojin 2021-09-06 14:28:26 -04:00 committed by GitHub
parent f9bf87f50d
commit 13dfceff48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
102 changed files with 13189 additions and 12692 deletions

View File

@ -21,33 +21,34 @@
#include "common/Assertions.h" #include "common/Assertions.h"
#include "common/ScopedAlloc.h" #include "common/ScopedAlloc.h"
void *__fastcall _aligned_malloc(size_t size, size_t align) void* __fastcall _aligned_malloc(size_t size, size_t align)
{ {
pxAssert(align < 0x10000); pxAssert(align < 0x10000);
#if defined(__USE_ISOC11) && !defined(ASAN_WORKAROUND) // not supported yet on gcc 4.9 #if defined(__USE_ISOC11) && !defined(ASAN_WORKAROUND) // not supported yet on gcc 4.9
return aligned_alloc(align, size); return aligned_alloc(align, size);
#else #else
void *result = 0; void* result = 0;
posix_memalign(&result, align, size); posix_memalign(&result, align, size);
return result; return result;
#endif #endif
} }
void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size) void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size)
{ {
pxAssert(align < 0x10000); pxAssert(align < 0x10000);
void *newbuf = _aligned_malloc(new_size, align); void* newbuf = _aligned_malloc(new_size, align);
if (newbuf != NULL && handle != NULL) { if (newbuf != NULL && handle != NULL)
memcpy(newbuf, handle, std::min(old_size, new_size)); {
_aligned_free(handle); memcpy(newbuf, handle, std::min(old_size, new_size));
} _aligned_free(handle);
return newbuf; }
return newbuf;
} }
__fi void _aligned_free(void *pmem) __fi void _aligned_free(void* pmem)
{ {
free(pmem); free(pmem);
} }
#endif #endif

View File

@ -27,13 +27,13 @@
// //
class Pcsx2AppTraits : public wxGUIAppTraits class Pcsx2AppTraits : public wxGUIAppTraits
{ {
typedef wxGUIAppTraits _parent; typedef wxGUIAppTraits _parent;
public: public:
virtual ~Pcsx2AppTraits() {} virtual ~Pcsx2AppTraits() {}
wxMessageOutput *CreateMessageOutput(); wxMessageOutput* CreateMessageOutput();
#ifdef wxUSE_STDPATHS #ifdef wxUSE_STDPATHS
wxStandardPaths &GetStandardPaths(); wxStandardPaths& GetStandardPaths();
#endif #endif
}; };

View File

@ -27,7 +27,7 @@
#endif #endif
#ifndef wxNullChar #ifndef wxNullChar
#define wxNullChar ((wxChar *)NULL) #define wxNullChar ((wxChar*)NULL)
#endif #endif
// FnChar_t - function name char type; typedef'd in case it ever changes between compilers // FnChar_t - function name char type; typedef'd in case it ever changes between compilers
@ -39,29 +39,29 @@ typedef char FnChar_t;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct DiagnosticOrigin struct DiagnosticOrigin
{ {
const wxChar *srcfile; const wxChar* srcfile;
const FnChar_t *function; const FnChar_t* function;
const wxChar *condition; const wxChar* condition;
int line; int line;
DiagnosticOrigin(const wxChar *_file, int _line, const FnChar_t *_func, const wxChar *_cond = NULL) DiagnosticOrigin(const wxChar* _file, int _line, const FnChar_t* _func, const wxChar* _cond = NULL)
: srcfile(_file) : srcfile(_file)
, function(_func) , function(_func)
, condition(_cond) , condition(_cond)
, line(_line) , line(_line)
{ {
} }
wxString ToString(const wxChar *msg = NULL) const; wxString ToString(const wxChar* msg = NULL) const;
}; };
// Returns ture if the assertion is to trap into the debugger, or false if execution // Returns ture if the assertion is to trap into the debugger, or false if execution
// of the program should continue unimpeded. // of the program should continue unimpeded.
typedef bool pxDoAssertFnType(const DiagnosticOrigin &origin, const wxChar *msg); typedef bool pxDoAssertFnType(const DiagnosticOrigin& origin, const wxChar* msg);
extern pxDoAssertFnType pxAssertImpl_LogIt; extern pxDoAssertFnType pxAssertImpl_LogIt;
extern pxDoAssertFnType *pxDoAssert; extern pxDoAssertFnType* pxDoAssert;
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// pxAssert / pxAssertDev // pxAssert / pxAssertDev
@ -159,11 +159,14 @@ extern pxDoAssertFnType *pxDoAssert;
#define pxAssumeDev(cond, msg) (__assume(cond)) #define pxAssumeDev(cond, msg) (__assume(cond))
#define pxFail(msg) \ #define pxFail(msg) \
do { \ do \
} while (0) { \
} while (0)
#define pxFailDev(msg) \ #define pxFailDev(msg) \
do { \ do \
} while (0) { \
} while (0)
#endif #endif
@ -177,18 +180,18 @@ extern pxDoAssertFnType *pxDoAssert;
// IndexBoundsCheckDev. // IndexBoundsCheckDev.
#define IndexBoundsCheck(objname, idx, sze) pxAssertMsg((uint)(idx) < (uint)(sze), \ #define IndexBoundsCheck(objname, idx, sze) pxAssertMsg((uint)(idx) < (uint)(sze), \
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze))) pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
#define IndexBoundsCheckDev(objname, idx, sze) pxAssertDev((uint)(idx) < (uint)(sze), \ #define IndexBoundsCheckDev(objname, idx, sze) pxAssertDev((uint)(idx) < (uint)(sze), \
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze))) pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
#define IndexBoundsAssume(objname, idx, sze) pxAssumeMsg((uint)(idx) < (uint)(sze), \ #define IndexBoundsAssume(objname, idx, sze) pxAssumeMsg((uint)(idx) < (uint)(sze), \
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze))) pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
#define IndexBoundsAssumeDev(objname, idx, sze) pxAssumeDev((uint)(idx) < (uint)(sze), \ #define IndexBoundsAssumeDev(objname, idx, sze) pxAssumeDev((uint)(idx) < (uint)(sze), \
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze))) pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg); extern void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization // jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
@ -201,9 +204,10 @@ extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
// * In debug/devel builds the default case will cause an assertion. // * In debug/devel builds the default case will cause an assertion.
// //
#ifndef jNO_DEFAULT #ifndef jNO_DEFAULT
#define jNO_DEFAULT \ #define jNO_DEFAULT \
default: { \ default: \
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \ { \
break; \ pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
} break; \
}
#endif #endif

View File

@ -15,62 +15,64 @@
#include "common/CheckedStaticBox.h" #include "common/CheckedStaticBox.h"
CheckedStaticBox::CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title) CheckedStaticBox::CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title)
: wxPanelWithHelpers(parent, wxVERTICAL) : wxPanelWithHelpers(parent, wxVERTICAL)
, ThisSizer(*new wxStaticBoxSizer(orientation, this)) , ThisSizer(*new wxStaticBoxSizer(orientation, this))
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0))) , ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
{ {
*this += ThisToggle; *this += ThisToggle;
*this += ThisSizer | pxExpand; *this += ThisSizer | pxExpand;
// Ensure that the right-side of the static group box isn't too cozy: // Ensure that the right-side of the static group box isn't too cozy:
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32); SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId()); Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId());
} }
// Event handler for click events for the main checkbox (default behavior: enables/disables all child controls) // Event handler for click events for the main checkbox (default behavior: enables/disables all child controls)
// This function can be overridden to implement custom handling of check enable/disable behavior. // This function can be overridden to implement custom handling of check enable/disable behavior.
void CheckedStaticBox::MainToggle_Click(wxCommandEvent &evt) void CheckedStaticBox::MainToggle_Click(wxCommandEvent& evt)
{ {
SetValue(evt.IsChecked()); SetValue(evt.IsChecked());
evt.Skip(); evt.Skip();
} }
// Sets the main checkbox status, and enables/disables all child controls // Sets the main checkbox status, and enables/disables all child controls
// bound to the StaticBox accordingly. // bound to the StaticBox accordingly.
void CheckedStaticBox::SetValue(bool val) void CheckedStaticBox::SetValue(bool val)
{ {
wxWindowList &list = GetChildren(); wxWindowList& list = GetChildren();
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) { for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
wxWindow *current = *iter; {
if (current != &ThisToggle) wxWindow* current = *iter;
current->Enable(IsEnabled() && val); if (current != &ThisToggle)
} current->Enable(IsEnabled() && val);
ThisToggle.SetValue(val); }
ThisToggle.SetValue(val);
} }
bool CheckedStaticBox::GetValue() const bool CheckedStaticBox::GetValue() const
{ {
return ThisToggle.GetValue(); return ThisToggle.GetValue();
} }
// This override is here so to only enable the children if both the main toggle and // This override is here so to only enable the children if both the main toggle and
// the enable request are true. If not, disable them! // the enable request are true. If not, disable them!
bool CheckedStaticBox::Enable(bool enable) bool CheckedStaticBox::Enable(bool enable)
{ {
if (!_parent::Enable(enable)) if (!_parent::Enable(enable))
return false; return false;
bool val = enable && ThisToggle.GetValue(); bool val = enable && ThisToggle.GetValue();
wxWindowList &list = GetChildren(); wxWindowList& list = GetChildren();
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) { for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
wxWindow *current = *iter; {
if (current != &ThisToggle) wxWindow* current = *iter;
current->Enable(val); if (current != &ThisToggle)
} current->Enable(val);
}
return true; return true;
} }

View File

@ -19,19 +19,19 @@
class CheckedStaticBox : public wxPanelWithHelpers class CheckedStaticBox : public wxPanelWithHelpers
{ {
typedef wxPanelWithHelpers _parent; typedef wxPanelWithHelpers _parent;
public: public:
wxBoxSizer &ThisSizer; // Boxsizer which holds all child items. wxBoxSizer& ThisSizer; // Boxsizer which holds all child items.
wxCheckBox &ThisToggle; // toggle which can enable/disable all child controls wxCheckBox& ThisToggle; // toggle which can enable/disable all child controls
public: public:
CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title = wxEmptyString); CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title = wxEmptyString);
void SetValue(bool val); void SetValue(bool val);
bool GetValue() const; bool GetValue() const;
bool Enable(bool enable = true); bool Enable(bool enable = true);
public: public:
virtual void MainToggle_Click(wxCommandEvent &evt); virtual void MainToggle_Click(wxCommandEvent& evt);
}; };

View File

@ -26,11 +26,11 @@ static DeclareTls(int) conlog_Indent(0);
static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor); static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor);
#ifdef __POSIX__ #ifdef __POSIX__
static FILE *stdout_fp = stdout; static FILE* stdout_fp = stdout;
void Console_SetStdout(FILE *fp) void Console_SetStdout(FILE* fp)
{ {
stdout_fp = fp; stdout_fp = fp;
} }
#endif #endif
@ -41,33 +41,33 @@ void Console_SetStdout(FILE *fp)
// Important! Only Assert and Null console loggers are allowed during C++ startup init (when // Important! Only Assert and Null console loggers are allowed during C++ startup init (when
// the program or DLL first loads). Other log targets rely on the static buffer and a // the program or DLL first loads). Other log targets rely on the static buffer and a
// threaded mutex lock, which are only valid after C++ initialization has finished. // threaded mutex lock, which are only valid after C++ initialization has finished.
void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp) void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp)
{ {
pxAssertDev( pxAssertDev(
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) && (writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
(writer.Newline != NULL) && (writer.SetTitle != NULL) && (writer.Newline != NULL) && (writer.SetTitle != NULL) &&
(writer.DoSetColor != NULL), (writer.DoSetColor != NULL),
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented."); "Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
Console = writer; Console = writer;
DevConWriter = writer; DevConWriter = writer;
#ifdef PCSX2_DEBUG #ifdef PCSX2_DEBUG
DbgCon = writer; DbgCon = writer;
#endif #endif
} }
// Writes text to the Visual Studio Output window (Microsoft Windows only). // Writes text to the Visual Studio Output window (Microsoft Windows only).
// On all other platforms this pipes to Stdout instead. // On all other platforms this pipes to Stdout instead.
void MSW_OutputDebugString(const wxString &text) void MSW_OutputDebugString(const wxString& text)
{ {
#if defined(__WXMSW__) && !defined(__WXMICROWIN__) #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
static bool hasDebugger = wxIsDebuggerRunning(); static bool hasDebugger = wxIsDebuggerRunning();
if (hasDebugger) if (hasDebugger)
OutputDebugString(text); OutputDebugString(text);
#else #else
fputs(text.utf8_str(), stdout_fp); fputs(text.utf8_str(), stdout_fp);
fflush(stdout_fp); fflush(stdout_fp);
#endif #endif
} }
@ -76,23 +76,23 @@ void MSW_OutputDebugString(const wxString &text)
// ConsoleNull // ConsoleNull
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
static void __concall ConsoleNull_SetTitle(const wxString &title) {} static void __concall ConsoleNull_SetTitle(const wxString& title) {}
static void __concall ConsoleNull_DoSetColor(ConsoleColors color) {} static void __concall ConsoleNull_DoSetColor(ConsoleColors color) {}
static void __concall ConsoleNull_Newline() {} static void __concall ConsoleNull_Newline() {}
static void __concall ConsoleNull_DoWrite(const wxString &fmt) {} static void __concall ConsoleNull_DoWrite(const wxString& fmt) {}
static void __concall ConsoleNull_DoWriteLn(const wxString &fmt) {} static void __concall ConsoleNull_DoWriteLn(const wxString& fmt) {}
const IConsoleWriter ConsoleWriter_Null = const IConsoleWriter ConsoleWriter_Null =
{ {
ConsoleNull_DoWrite, ConsoleNull_DoWrite,
ConsoleNull_DoWriteLn, ConsoleNull_DoWriteLn,
ConsoleNull_DoSetColor, ConsoleNull_DoSetColor,
ConsoleNull_DoWrite, ConsoleNull_DoWrite,
ConsoleNull_Newline, ConsoleNull_Newline,
ConsoleNull_SetTitle, ConsoleNull_SetTitle,
0, // instance-level indentation (should always be 0) 0, // instance-level indentation (should always be 0)
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -100,133 +100,134 @@ const IConsoleWriter ConsoleWriter_Null =
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
#if defined(__unix__) #if defined(__unix__)
static __fi const char *GetLinuxConsoleColor(ConsoleColors color) static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
{ {
switch (color) { switch (color)
case Color_Black: {
case Color_StrongBlack: case Color_Black:
return "\033[30m\033[1m"; case Color_StrongBlack:
return "\033[30m\033[1m";
case Color_Red: case Color_Red:
return "\033[31m"; return "\033[31m";
case Color_StrongRed: case Color_StrongRed:
return "\033[31m\033[1m"; return "\033[31m\033[1m";
case Color_Green: case Color_Green:
return "\033[32m"; return "\033[32m";
case Color_StrongGreen: case Color_StrongGreen:
return "\033[32m\033[1m"; return "\033[32m\033[1m";
case Color_Yellow: case Color_Yellow:
return "\033[33m"; return "\033[33m";
case Color_StrongYellow: case Color_StrongYellow:
return "\033[33m\033[1m"; return "\033[33m\033[1m";
case Color_Blue: case Color_Blue:
return "\033[34m"; return "\033[34m";
case Color_StrongBlue: case Color_StrongBlue:
return "\033[34m\033[1m"; return "\033[34m\033[1m";
// No orange, so use magenta. // No orange, so use magenta.
case Color_Orange: case Color_Orange:
case Color_Magenta: case Color_Magenta:
return "\033[35m"; return "\033[35m";
case Color_StrongOrange: case Color_StrongOrange:
case Color_StrongMagenta: case Color_StrongMagenta:
return "\033[35m\033[1m"; return "\033[35m\033[1m";
case Color_Cyan: case Color_Cyan:
return "\033[36m"; return "\033[36m";
case Color_StrongCyan: case Color_StrongCyan:
return "\033[36m\033[1m"; return "\033[36m\033[1m";
// Use 'white' instead of grey. // Use 'white' instead of grey.
case Color_Gray: case Color_Gray:
case Color_White: case Color_White:
return "\033[37m"; return "\033[37m";
case Color_StrongGray: case Color_StrongGray:
case Color_StrongWhite: case Color_StrongWhite:
return "\033[37m\033[1m"; return "\033[37m\033[1m";
// On some other value being passed, clear any formatting. // On some other value being passed, clear any formatting.
case Color_Default: case Color_Default:
default: default:
return "\033[0m"; return "\033[0m";
} }
} }
#endif #endif
// One possible default write action at startup and shutdown is to use the stdout. // One possible default write action at startup and shutdown is to use the stdout.
static void __concall ConsoleStdout_DoWrite(const wxString &fmt) static void __concall ConsoleStdout_DoWrite(const wxString& fmt)
{ {
MSW_OutputDebugString(fmt); MSW_OutputDebugString(fmt);
} }
// Default write action at startup and shutdown is to use the stdout. // Default write action at startup and shutdown is to use the stdout.
static void __concall ConsoleStdout_DoWriteLn(const wxString &fmt) static void __concall ConsoleStdout_DoWriteLn(const wxString& fmt)
{ {
MSW_OutputDebugString(fmt + L"\n"); MSW_OutputDebugString(fmt + L"\n");
} }
static void __concall ConsoleStdout_Newline() static void __concall ConsoleStdout_Newline()
{ {
MSW_OutputDebugString(L"\n"); MSW_OutputDebugString(L"\n");
} }
static void __concall ConsoleStdout_DoSetColor(ConsoleColors color) static void __concall ConsoleStdout_DoSetColor(ConsoleColors color)
{ {
#if defined(__unix__) #if defined(__unix__)
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color)); fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
fflush(stdout_fp); fflush(stdout_fp);
#endif #endif
} }
static void __concall ConsoleStdout_SetTitle(const wxString &title) static void __concall ConsoleStdout_SetTitle(const wxString& title)
{ {
#if defined(__unix__) #if defined(__unix__)
fputs("\033]0;", stdout_fp); fputs("\033]0;", stdout_fp);
fputs(title.utf8_str(), stdout_fp); fputs(title.utf8_str(), stdout_fp);
fputs("\007", stdout_fp); fputs("\007", stdout_fp);
#endif #endif
} }
const IConsoleWriter ConsoleWriter_Stdout = const IConsoleWriter ConsoleWriter_Stdout =
{ {
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam. ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
ConsoleStdout_DoWriteLn, ConsoleStdout_DoWriteLn,
ConsoleStdout_DoSetColor, ConsoleStdout_DoSetColor,
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_< ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
ConsoleStdout_Newline, ConsoleStdout_Newline,
ConsoleStdout_SetTitle, ConsoleStdout_SetTitle,
0, // instance-level indentation (should always be 0) 0, // instance-level indentation (should always be 0)
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ConsoleAssert // ConsoleAssert
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
static void __concall ConsoleAssert_DoWrite(const wxString &fmt) static void __concall ConsoleAssert_DoWrite(const wxString& fmt)
{ {
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt); pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
} }
static void __concall ConsoleAssert_DoWriteLn(const wxString &fmt) static void __concall ConsoleAssert_DoWriteLn(const wxString& fmt)
{ {
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt); pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
} }
const IConsoleWriter ConsoleWriter_Assert = const IConsoleWriter ConsoleWriter_Assert =
{ {
ConsoleAssert_DoWrite, ConsoleAssert_DoWrite,
ConsoleAssert_DoWriteLn, ConsoleAssert_DoWriteLn,
ConsoleNull_DoSetColor, ConsoleNull_DoSetColor,
ConsoleNull_DoWrite, ConsoleNull_DoWrite,
ConsoleNull_Newline, ConsoleNull_Newline,
ConsoleNull_SetTitle, ConsoleNull_SetTitle,
0, // instance-level indentation (should always be 0) 0, // instance-level indentation (should always be 0)
}; };
// ===================================================================================================== // =====================================================================================================
@ -239,170 +240,170 @@ const IConsoleWriter ConsoleWriter_Assert =
// glob_indent - this parameter is used to specify a global indentation setting. It is used by // glob_indent - this parameter is used to specify a global indentation setting. It is used by
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always // WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
// applies to all writes. // applies to all writes.
wxString IConsoleWriter::_addIndentation(const wxString &src, int glob_indent = 0) const wxString IConsoleWriter::_addIndentation(const wxString& src, int glob_indent = 0) const
{ {
const int indent = glob_indent + _imm_indentation; const int indent = glob_indent + _imm_indentation;
if (indent == 0) if (indent == 0)
return src; return src;
wxString result(src); wxString result(src);
const wxString indentStr(L'\t', indent); const wxString indentStr(L'\t', indent);
result.Replace(L"\n", L"\n" + indentStr); result.Replace(L"\n", L"\n" + indentStr);
return indentStr + result; return indentStr + result;
} }
// Sets the indentation to be applied to all WriteLn's. The indentation is added to the // Sets the indentation to be applied to all WriteLn's. The indentation is added to the
// primary write, and to any newlines specified within the write. Note that this applies // primary write, and to any newlines specified within the write. Note that this applies
// to calls to WriteLn *only* -- calls to Write bypass the indentation parser. // to calls to WriteLn *only* -- calls to Write bypass the indentation parser.
const IConsoleWriter &IConsoleWriter::SetIndent(int tabcount) const const IConsoleWriter& IConsoleWriter::SetIndent(int tabcount) const
{ {
conlog_Indent += tabcount; conlog_Indent += tabcount;
pxAssert(conlog_Indent >= 0); pxAssert(conlog_Indent >= 0);
return *this; return *this;
} }
IConsoleWriter IConsoleWriter::Indent(int tabcount) const IConsoleWriter IConsoleWriter::Indent(int tabcount) const
{ {
IConsoleWriter retval = *this; IConsoleWriter retval = *this;
retval._imm_indentation = tabcount; retval._imm_indentation = tabcount;
return retval; return retval;
} }
// Changes the active console color. // Changes the active console color.
// This color will be unset by calls to colored text methods // This color will be unset by calls to colored text methods
// such as ErrorMsg and Notice. // such as ErrorMsg and Notice.
const IConsoleWriter &IConsoleWriter::SetColor(ConsoleColors color) const const IConsoleWriter& IConsoleWriter::SetColor(ConsoleColors color) const
{ {
// Ignore current color requests since, well, the current color is already set. ;) // Ignore current color requests since, well, the current color is already set. ;)
if (color == Color_Current) if (color == Color_Current)
return *this; return *this;
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified."); pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
if (conlog_Color != color) if (conlog_Color != color)
DoSetColor(conlog_Color = color); DoSetColor(conlog_Color = color);
return *this; return *this;
} }
ConsoleColors IConsoleWriter::GetColor() const ConsoleColors IConsoleWriter::GetColor() const
{ {
return conlog_Color; return conlog_Color;
} }
// Restores the console color to default (usually black, or low-intensity white if the console uses a black background) // Restores the console color to default (usually black, or low-intensity white if the console uses a black background)
const IConsoleWriter &IConsoleWriter::ClearColor() const const IConsoleWriter& IConsoleWriter::ClearColor() const
{ {
if (conlog_Color != DefaultConsoleColor) if (conlog_Color != DefaultConsoleColor)
DoSetColor(conlog_Color = DefaultConsoleColor); DoSetColor(conlog_Color = DefaultConsoleColor);
return *this; return *this;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ASCII/UTF8 (char*) // ASCII/UTF8 (char*)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
bool IConsoleWriter::FormatV(const char *fmt, va_list args) const bool IConsoleWriter::FormatV(const char* fmt, va_list args) const
{ {
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent)); DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
return false; return false;
} }
bool IConsoleWriter::WriteLn(const char *fmt, ...) const bool IConsoleWriter::WriteLn(const char* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::WriteLn(ConsoleColors color, const char *fmt, ...) const bool IConsoleWriter::WriteLn(ConsoleColors color, const char* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(color); ConsoleColorScope cs(color);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Error(const char *fmt, ...) const bool IConsoleWriter::Error(const char* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed); ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Warning(const char *fmt, ...) const bool IConsoleWriter::Warning(const char* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange); ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Write Variants - Unicode/UTF16 style // Write Variants - Unicode/UTF16 style
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
bool IConsoleWriter::FormatV(const wxChar *fmt, va_list args) const bool IConsoleWriter::FormatV(const wxChar* fmt, va_list args) const
{ {
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent)); DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
return false; return false;
} }
bool IConsoleWriter::WriteLn(const wxChar *fmt, ...) const bool IConsoleWriter::WriteLn(const wxChar* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar *fmt, ...) const bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(color); ConsoleColorScope cs(color);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Error(const wxChar *fmt, ...) const bool IConsoleWriter::Error(const wxChar* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed); ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Warning(const wxChar *fmt, ...) const bool IConsoleWriter::Warning(const wxChar* fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange); ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, args); FormatV(fmt, args);
va_end(args); va_end(args);
return false; return false;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -410,45 +411,45 @@ bool IConsoleWriter::Warning(const wxChar *fmt, ...) const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
bool IConsoleWriter::WriteLn(const wxString fmt, ...) const bool IConsoleWriter::WriteLn(const wxString fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
FormatV(fmt.wx_str(), args); FormatV(fmt.wx_str(), args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(color); ConsoleColorScope cs(color);
FormatV(fmt.wx_str(), args); FormatV(fmt.wx_str(), args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Error(const wxString fmt, ...) const bool IConsoleWriter::Error(const wxString fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed); ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt.wx_str(), args); FormatV(fmt.wx_str(), args);
va_end(args); va_end(args);
return false; return false;
} }
bool IConsoleWriter::Warning(const wxString fmt, ...) const bool IConsoleWriter::Warning(const wxString fmt, ...) const
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange); ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt.wx_str(), args); FormatV(fmt.wx_str(), args);
va_end(args); va_end(args);
return false; return false;
} }
@ -458,70 +459,73 @@ bool IConsoleWriter::Warning(const wxString fmt, ...) const
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor) ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
{ {
m_IsScoped = false; m_IsScoped = false;
m_newcolor = newcolor; m_newcolor = newcolor;
EnterScope(); EnterScope();
} }
ConsoleColorScope::~ConsoleColorScope() ConsoleColorScope::~ConsoleColorScope()
{ {
LeaveScope(); LeaveScope();
} }
void ConsoleColorScope::EnterScope() void ConsoleColorScope::EnterScope()
{ {
if (!m_IsScoped) { if (!m_IsScoped)
m_old_color = Console.GetColor(); {
Console.SetColor(m_newcolor); m_old_color = Console.GetColor();
m_IsScoped = true; Console.SetColor(m_newcolor);
} m_IsScoped = true;
}
} }
void ConsoleColorScope::LeaveScope() void ConsoleColorScope::LeaveScope()
{ {
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false); m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
} }
ConsoleIndentScope::ConsoleIndentScope(int tabs) ConsoleIndentScope::ConsoleIndentScope(int tabs)
{ {
m_IsScoped = false; m_IsScoped = false;
m_amount = tabs; m_amount = tabs;
EnterScope(); EnterScope();
} }
ConsoleIndentScope::~ConsoleIndentScope() ConsoleIndentScope::~ConsoleIndentScope()
{ {
try { try
LeaveScope(); {
} LeaveScope();
DESTRUCTOR_CATCHALL }
DESTRUCTOR_CATCHALL
} }
void ConsoleIndentScope::EnterScope() void ConsoleIndentScope::EnterScope()
{ {
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true); m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
} }
void ConsoleIndentScope::LeaveScope() void ConsoleIndentScope::LeaveScope()
{ {
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false); m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
} }
ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent) ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
{ {
m_old_color = Console.GetColor(); m_old_color = Console.GetColor();
Console.SetIndent(m_tabsize = indent); Console.SetIndent(m_tabsize = indent);
Console.SetColor(newcolor); Console.SetColor(newcolor);
} }
ConsoleAttrScope::~ConsoleAttrScope() ConsoleAttrScope::~ConsoleAttrScope()
{ {
try { try
Console.SetColor(m_old_color); {
Console.SetIndent(-m_tabsize); Console.SetColor(m_old_color);
} Console.SetIndent(-m_tabsize);
DESTRUCTOR_CATCHALL }
DESTRUCTOR_CATCHALL
} }
@ -552,31 +556,31 @@ NullConsoleWriter NullCon = {};
// Writes to the console using the specified color. This overrides the default color setting // Writes to the console using the specified color. This overrides the default color setting
// for this log. // for this log.
bool ConsoleLogSource::WriteV(ConsoleColors color, const char *fmt, va_list list) const bool ConsoleLogSource::WriteV(ConsoleColors color, const char* fmt, va_list list) const
{ {
ConsoleColorScope cs(color); ConsoleColorScope cs(color);
DoWrite(pxsFmtV(fmt, list).c_str()); DoWrite(pxsFmtV(fmt, list).c_str());
return false; return false;
} }
bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const
{ {
ConsoleColorScope cs(color); ConsoleColorScope cs(color);
DoWrite(pxsFmtV(fmt, list).c_str()); DoWrite(pxsFmtV(fmt, list).c_str());
return false; return false;
} }
// Writes to the console using the source's default color. Note that the source's default // Writes to the console using the source's default color. Note that the source's default
// color will always be used, thus ConsoleColorScope() will not be effectual unless the // color will always be used, thus ConsoleColorScope() will not be effectual unless the
// console's default color is Color_Default. // console's default color is Color_Default.
bool ConsoleLogSource::WriteV(const char *fmt, va_list list) const bool ConsoleLogSource::WriteV(const char* fmt, va_list list) const
{ {
WriteV(DefaultColor, fmt, list); WriteV(DefaultColor, fmt, list);
return false; return false;
} }
bool ConsoleLogSource::WriteV(const wxChar *fmt, va_list list) const bool ConsoleLogSource::WriteV(const wxChar* fmt, va_list list) const
{ {
WriteV(DefaultColor, fmt, list); WriteV(DefaultColor, fmt, list);
return false; return false;
} }

View File

@ -15,40 +15,41 @@
#pragma once #pragma once
#include "StringHelpers.h" #include "common/StringHelpers.h"
enum ConsoleColors { enum ConsoleColors
Color_Current = -1, {
Color_Current = -1,
Color_Default = 0, Color_Default = 0,
Color_Black, Color_Black,
Color_Green, Color_Green,
Color_Red, Color_Red,
Color_Blue, Color_Blue,
Color_Magenta, Color_Magenta,
Color_Orange, Color_Orange,
Color_Gray, Color_Gray,
Color_Cyan, // faint visibility, intended for logging PS2/IOP output Color_Cyan, // faint visibility, intended for logging PS2/IOP output
Color_Yellow, // faint visibility, intended for logging PS2/IOP output Color_Yellow, // faint visibility, intended for logging PS2/IOP output
Color_White, // faint visibility, intended for logging PS2/IOP output Color_White, // faint visibility, intended for logging PS2/IOP output
// Strong text *may* result in mis-aligned text in the console, depending on the // Strong text *may* result in mis-aligned text in the console, depending on the
// font and the platform, so use these with caution. // font and the platform, so use these with caution.
Color_StrongBlack, Color_StrongBlack,
Color_StrongRed, // intended for errors Color_StrongRed, // intended for errors
Color_StrongGreen, // intended for infrequent state information Color_StrongGreen, // intended for infrequent state information
Color_StrongBlue, // intended for block headings Color_StrongBlue, // intended for block headings
Color_StrongMagenta, Color_StrongMagenta,
Color_StrongOrange, // intended for warnings Color_StrongOrange, // intended for warnings
Color_StrongGray, Color_StrongGray,
Color_StrongCyan, Color_StrongCyan,
Color_StrongYellow, Color_StrongYellow,
Color_StrongWhite, Color_StrongWhite,
ConsoleColors_Count ConsoleColors_Count
}; };
static const ConsoleColors DefaultConsoleColor = Color_Default; static const ConsoleColors DefaultConsoleColor = Color_Default;
@ -70,60 +71,60 @@ static const ConsoleColors DefaultConsoleColor = Color_Default;
// //
struct IConsoleWriter struct IConsoleWriter
{ {
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick // A direct console write, without tabbing or newlines. Useful to devs who want to do quick
// logging of various junk; but should *not* be used in production code due. // logging of various junk; but should *not* be used in production code due.
void(__concall *WriteRaw)(const wxString &fmt); void(__concall* WriteRaw)(const wxString& fmt);
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other // WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
// formatting. // formatting.
void(__concall *DoWriteLn)(const wxString &fmt); void(__concall* DoWriteLn)(const wxString& fmt);
// SetColor implementation for internal use only. // SetColor implementation for internal use only.
void(__concall *DoSetColor)(ConsoleColors color); void(__concall* DoSetColor)(ConsoleColors color);
// Special implementation of DoWrite that's pretty much for MSVC use only. // Special implementation of DoWrite that's pretty much for MSVC use only.
// All implementations should map to DoWrite, except Stdio which should map to Null. // All implementations should map to DoWrite, except Stdio which should map to Null.
// (This avoids circular/recursive stdio output) // (This avoids circular/recursive stdio output)
void(__concall *DoWriteFromStdout)(const wxString &fmt); void(__concall* DoWriteFromStdout)(const wxString& fmt);
void(__concall *Newline)(); void(__concall* Newline)();
void(__concall *SetTitle)(const wxString &title); void(__concall* SetTitle)(const wxString& title);
// internal value for indentation of individual lines. Use the Indent() member to invoke. // internal value for indentation of individual lines. Use the Indent() member to invoke.
int _imm_indentation; int _imm_indentation;
// For internal use only. // For internal use only.
wxString _addIndentation(const wxString &src, int glob_indent) const; wxString _addIndentation(const wxString& src, int glob_indent) const;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Public members; call these to print stuff to console! // Public members; call these to print stuff to console!
// //
// All functions always return false. Return value is provided only so that we can easily // All functions always return false. Return value is provided only so that we can easily
// disable logs at compile time using the "0&&action" macro trick. // disable logs at compile time using the "0&&action" macro trick.
ConsoleColors GetColor() const; ConsoleColors GetColor() const;
const IConsoleWriter &SetColor(ConsoleColors color) const; const IConsoleWriter& SetColor(ConsoleColors color) const;
const IConsoleWriter &ClearColor() const; const IConsoleWriter& ClearColor() const;
const IConsoleWriter &SetIndent(int tabcount = 1) const; const IConsoleWriter& SetIndent(int tabcount = 1) const;
IConsoleWriter Indent(int tabcount = 1) const; IConsoleWriter Indent(int tabcount = 1) const;
bool FormatV(const char *fmt, va_list args) const; bool FormatV(const char* fmt, va_list args) const;
bool WriteLn(ConsoleColors color, const char *fmt, ...) const; bool WriteLn(ConsoleColors color, const char* fmt, ...) const;
bool WriteLn(const char *fmt, ...) const; bool WriteLn(const char* fmt, ...) const;
bool Error(const char *fmt, ...) const; bool Error(const char* fmt, ...) const;
bool Warning(const char *fmt, ...) const; bool Warning(const char* fmt, ...) const;
bool FormatV(const wxChar *fmt, va_list args) const; bool FormatV(const wxChar* fmt, va_list args) const;
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const; bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const;
bool WriteLn(const wxChar *fmt, ...) const; bool WriteLn(const wxChar* fmt, ...) const;
bool Error(const wxChar *fmt, ...) const; bool Error(const wxChar* fmt, ...) const;
bool Warning(const wxChar *fmt, ...) const; bool Warning(const wxChar* fmt, ...) const;
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const; bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
bool WriteLn(const wxString fmt, ...) const; bool WriteLn(const wxString fmt, ...) const;
bool Error(const wxString fmt, ...) const; bool Error(const wxString fmt, ...) const;
bool Warning(const wxString fmt, ...) const; bool Warning(const wxString fmt, ...) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -133,37 +134,37 @@ struct IConsoleWriter
// //
struct NullConsoleWriter struct NullConsoleWriter
{ {
void WriteRaw(const wxString &fmt) {} void WriteRaw(const wxString& fmt) {}
void DoWriteLn(const wxString &fmt) {} void DoWriteLn(const wxString& fmt) {}
void DoSetColor(ConsoleColors color) {} void DoSetColor(ConsoleColors color) {}
void DoWriteFromStdout(const wxString &fmt) {} void DoWriteFromStdout(const wxString& fmt) {}
void Newline() {} void Newline() {}
void SetTitle(const wxString &title) {} void SetTitle(const wxString& title) {}
ConsoleColors GetColor() const { return Color_Current; } ConsoleColors GetColor() const { return Color_Current; }
const NullConsoleWriter &SetColor(ConsoleColors color) const { return *this; } const NullConsoleWriter& SetColor(ConsoleColors color) const { return *this; }
const NullConsoleWriter &ClearColor() const { return *this; } const NullConsoleWriter& ClearColor() const { return *this; }
const NullConsoleWriter &SetIndent(int tabcount = 1) const { return *this; } const NullConsoleWriter& SetIndent(int tabcount = 1) const { return *this; }
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); } NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
bool FormatV(const char *fmt, va_list args) const { return false; } bool FormatV(const char* fmt, va_list args) const { return false; }
bool WriteLn(ConsoleColors color, const char *fmt, ...) const { return false; } bool WriteLn(ConsoleColors color, const char* fmt, ...) const { return false; }
bool WriteLn(const char *fmt, ...) const { return false; } bool WriteLn(const char* fmt, ...) const { return false; }
bool Error(const char *fmt, ...) const { return false; } bool Error(const char* fmt, ...) const { return false; }
bool Warning(const char *fmt, ...) const { return false; } bool Warning(const char* fmt, ...) const { return false; }
bool FormatV(const wxChar *fmt, va_list args) const { return false; } bool FormatV(const wxChar* fmt, va_list args) const { return false; }
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const { return false; } bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const { return false; }
bool WriteLn(const wxChar *fmt, ...) const { return false; } bool WriteLn(const wxChar* fmt, ...) const { return false; }
bool Error(const wxChar *fmt, ...) const { return false; } bool Error(const wxChar* fmt, ...) const { return false; }
bool Warning(const wxChar *fmt, ...) const { return false; } bool Warning(const wxChar* fmt, ...) const { return false; }
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; } bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; }
bool WriteLn(const wxString fmt, ...) const { return false; } bool WriteLn(const wxString fmt, ...) const { return false; }
bool Error(const wxString fmt, ...) const { return false; } bool Error(const wxString fmt, ...) const { return false; }
bool Warning(const wxString fmt, ...) const { return false; } bool Warning(const wxString fmt, ...) const { return false; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -179,19 +180,19 @@ struct NullConsoleWriter
// //
class ConsoleIndentScope class ConsoleIndentScope
{ {
DeclareNoncopyableObject(ConsoleIndentScope); DeclareNoncopyableObject(ConsoleIndentScope);
protected: protected:
int m_amount; int m_amount;
bool m_IsScoped; bool m_IsScoped;
public: public:
// Constructor: The specified number of tabs will be appended to the current indentation // Constructor: The specified number of tabs will be appended to the current indentation
// setting. The tabs will be unrolled when the object leaves scope or is destroyed. // setting. The tabs will be unrolled when the object leaves scope or is destroyed.
ConsoleIndentScope(int tabs = 1); ConsoleIndentScope(int tabs = 1);
virtual ~ConsoleIndentScope(); virtual ~ConsoleIndentScope();
void EnterScope(); void EnterScope();
void LeaveScope(); void LeaveScope();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -199,18 +200,18 @@ public:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class ConsoleColorScope class ConsoleColorScope
{ {
DeclareNoncopyableObject(ConsoleColorScope); DeclareNoncopyableObject(ConsoleColorScope);
protected: protected:
ConsoleColors m_newcolor; ConsoleColors m_newcolor;
ConsoleColors m_old_color; ConsoleColors m_old_color;
bool m_IsScoped; bool m_IsScoped;
public: public:
ConsoleColorScope(ConsoleColors newcolor); ConsoleColorScope(ConsoleColors newcolor);
virtual ~ConsoleColorScope(); virtual ~ConsoleColorScope();
void EnterScope(); void EnterScope();
void LeaveScope(); void LeaveScope();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -220,23 +221,23 @@ public:
// //
class ConsoleAttrScope class ConsoleAttrScope
{ {
DeclareNoncopyableObject(ConsoleAttrScope); DeclareNoncopyableObject(ConsoleAttrScope);
protected: protected:
ConsoleColors m_old_color; ConsoleColors m_old_color;
int m_tabsize; int m_tabsize;
public: public:
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0); ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
virtual ~ConsoleAttrScope(); virtual ~ConsoleAttrScope();
}; };
extern IConsoleWriter Console; extern IConsoleWriter Console;
#if defined(__unix__) || defined(__APPLE__) #if defined(__unix__) || defined(__APPLE__)
extern void Console_SetStdout(FILE *fp); extern void Console_SetStdout(FILE* fp);
#endif #endif
extern void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp = NULL); extern void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp = NULL);
extern const IConsoleWriter ConsoleWriter_Null; extern const IConsoleWriter ConsoleWriter_Null;
extern const IConsoleWriter ConsoleWriter_Stdout; extern const IConsoleWriter ConsoleWriter_Stdout;
@ -250,7 +251,7 @@ extern bool DevConWriterEnabled;
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
#define DevCon DevConWriter #define DevCon DevConWriter
#else #else
#define DevCon DevConWriterEnabled &&DevConWriter #define DevCon DevConWriterEnabled&& DevConWriter
#endif #endif
#ifdef PCSX2_DEBUG #ifdef PCSX2_DEBUG

View File

@ -25,7 +25,7 @@
#include "common/Pcsx2Types.h" #include "common/Pcsx2Types.h"
#define NELEM(x) \ #define NELEM(x) \
((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
// Darwin (OSX) is a bit different from Linux when requesting properties of // Darwin (OSX) is a bit different from Linux when requesting properties of
// the OS because of its BSD/Mach heritage. Helpfully, most of this code // the OS because of its BSD/Mach heritage. Helpfully, most of this code
@ -39,23 +39,25 @@
// failure (not supported by the operating system). // failure (not supported by the operating system).
u64 GetPhysicalMemory() u64 GetPhysicalMemory()
{ {
static u64 mem = 0; static u64 mem = 0;
// fetch the total memory only once, as its an expensive system call and // fetch the total memory only once, as its an expensive system call and
// doesn't change during the course of the program. Thread-safety is // doesn't change during the course of the program. Thread-safety is
// ensured by atomic operations with full-barriers (usually compiled // ensured by atomic operations with full-barriers (usually compiled
// down to XCHG on x86). // down to XCHG on x86).
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) { if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0)
u64 getmem = 0; {
size_t len = sizeof(getmem); u64 getmem = 0;
int mib[] = {CTL_HW, HW_MEMSIZE}; size_t len = sizeof(getmem);
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) { int mib[] = {CTL_HW, HW_MEMSIZE};
perror("sysctl:"); if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0)
} {
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST); perror("sysctl:");
} }
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
}
return mem; return mem;
} }
void InitCPUTicks() void InitCPUTicks()
@ -72,26 +74,28 @@ void InitCPUTicks()
// GetTickFrequency() to maintain good precision. // GetTickFrequency() to maintain good precision.
u64 GetTickFrequency() u64 GetTickFrequency()
{ {
static u64 freq = 0; static u64 freq = 0;
// by the time denom is not 0, the structure will have been fully // by the time denom is not 0, the structure will have been fully
// updated and no more atomic accesses are necessary. // updated and no more atomic accesses are necessary.
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) { if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0)
mach_timebase_info_data_t info; {
mach_timebase_info_data_t info;
// mach_timebase_info() is a syscall, very slow, that's why we take // mach_timebase_info() is a syscall, very slow, that's why we take
// pains to only do it once. On x86(-64), the result is guaranteed // pains to only do it once. On x86(-64), the result is guaranteed
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9, // to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
// which means GetCPUTicks is just nanoseconds). // which means GetCPUTicks is just nanoseconds).
if (mach_timebase_info(&info) != KERN_SUCCESS) { if (mach_timebase_info(&info) != KERN_SUCCESS)
abort(); {
} abort();
}
// store the calculated value atomically // store the calculated value atomically
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST); __atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
} }
return freq; return freq;
} }
// return the number of "ticks" since some arbitrary, fixed time in the // return the number of "ticks" since some arbitrary, fixed time in the
@ -100,53 +104,55 @@ u64 GetTickFrequency()
// nanoseconds. // nanoseconds.
u64 GetCPUTicks() u64 GetCPUTicks()
{ {
return mach_absolute_time(); return mach_absolute_time();
} }
wxString GetOSVersionString() wxString GetOSVersionString()
{ {
wxString version; wxString version;
static int initialized = 0; static int initialized = 0;
// fetch the OS description only once (thread-safely) // fetch the OS description only once (thread-safely)
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) { if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0)
char type[32] = {0}; {
char release[32] = {0}; char type[32] = {0};
char arch[32] = {0}; char release[32] = {0};
char arch[32] = {0};
#define SYSCTL_GET(var, base, name) \ #define SYSCTL_GET(var, base, name) \
do { \ do \
int mib[] = {base, name}; \ { \
size_t len = sizeof(var); \ int mib[] = {base, name}; \
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \ size_t len = sizeof(var); \
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \ sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
} while (0) sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
} while (0)
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE); SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE); SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
SYSCTL_GET(arch, CTL_HW, HW_MACHINE); SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
#undef SYSCTL_KERN #undef SYSCTL_KERN
// I know strcat is not good, but stpcpy is not universally // I know strcat is not good, but stpcpy is not universally
// available yet. // available yet.
char buf[128] = {0}; char buf[128] = {0};
strcat(buf, type); strcat(buf, type);
strcat(buf, " "); strcat(buf, " ");
strcat(buf, release); strcat(buf, release);
strcat(buf, " "); strcat(buf, " ");
strcat(buf, arch); strcat(buf, arch);
version = buf; version = buf;
__atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST); __atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST);
} }
return version; return version;
} }
void ScreensaverAllow(bool allow) void ScreensaverAllow(bool allow)
{ {
// no-op // no-op
} }
#endif #endif

View File

@ -20,10 +20,10 @@
#include <pthread.h> // pthread_setcancelstate() #include <pthread.h> // pthread_setcancelstate()
#include <sys/time.h> // gettimeofday() #include <sys/time.h> // gettimeofday()
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/task.h> // semaphore_create() and semaphore_destroy() #include <mach/task.h> // semaphore_create() and semaphore_destroy()
#include <mach/semaphore.h> // semaphore_*() #include <mach/semaphore.h> // semaphore_*()
#include <mach/mach_error.h> // mach_error_string() #include <mach/mach_error.h> // mach_error_string()
#include <mach/mach_time.h> // mach_absolute_time() #include <mach/mach_time.h> // mach_absolute_time()
#include "common/Threading.h" #include "common/Threading.h"
#include "common/ThreadingInternal.h" #include "common/ThreadingInternal.h"
@ -45,107 +45,113 @@
static void MACH_CHECK(kern_return_t mach_retval) static void MACH_CHECK(kern_return_t mach_retval)
{ {
switch (mach_retval) { switch (mach_retval)
case KERN_SUCCESS: break; {
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel) case KERN_SUCCESS:
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points break;
// fallthrough case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
default: pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
fprintf(stderr, "mach error: %s", mach_error_string(mach_retval)); // fallthrough
assert(mach_retval == KERN_SUCCESS); default:
} fprintf(stderr, "mach error: %s", mach_error_string(mach_retval));
assert(mach_retval == KERN_SUCCESS);
}
} }
Threading::Semaphore::Semaphore() Threading::Semaphore::Semaphore()
{ {
// other platforms explicitly make a thread-private (unshared) semaphore // other platforms explicitly make a thread-private (unshared) semaphore
// here. But it seems Mach doesn't support that. // here. But it seems Mach doesn't support that.
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0)); MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
} }
Threading::Semaphore::~Semaphore() Threading::Semaphore::~Semaphore()
{ {
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema)); MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
} }
void Threading::Semaphore::Reset() void Threading::Semaphore::Reset()
{ {
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema)); MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0)); MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
} }
void Threading::Semaphore::Post() void Threading::Semaphore::Post()
{ {
MACH_CHECK(semaphore_signal(m_sema)); MACH_CHECK(semaphore_signal(m_sema));
__atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); __atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
} }
void Threading::Semaphore::Post(int multiple) void Threading::Semaphore::Post(int multiple)
{ {
for (int i = 0; i < multiple; ++i) { for (int i = 0; i < multiple; ++i)
MACH_CHECK(semaphore_signal(m_sema)); {
} MACH_CHECK(semaphore_signal(m_sema));
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST); }
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
} }
void Threading::Semaphore::WaitWithoutYield() void Threading::Semaphore::WaitWithoutYield()
{ {
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead."); pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
MACH_CHECK(semaphore_wait(m_sema)); MACH_CHECK(semaphore_wait(m_sema));
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); __atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
} }
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout) bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
{ {
// This method is the reason why there has to be a special Darwin // This method is the reason why there has to be a special Darwin
// implementation of Semaphore. Note that semaphore_timedwait() is prone // implementation of Semaphore. Note that semaphore_timedwait() is prone
// to returning with KERN_ABORTED, which basically signifies that some // to returning with KERN_ABORTED, which basically signifies that some
// signal has worken it up. The best official "documentation" for // signal has worken it up. The best official "documentation" for
// semaphore_timedwait() is the way it's used in Grand Central Dispatch, // semaphore_timedwait() is the way it's used in Grand Central Dispatch,
// which is open-source. // which is open-source.
// on x86 platforms, mach_absolute_time() returns nanoseconds // on x86 platforms, mach_absolute_time() returns nanoseconds
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary // TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
u64 const kOneThousand = 1000; u64 const kOneThousand = 1000;
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand; u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand); u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
mach_timespec_t ts; mach_timespec_t ts;
kern_return_t kr = KERN_ABORTED; kern_return_t kr = KERN_ABORTED;
for (u64 now = mach_absolute_time(), deadline = now + delta; for (u64 now = mach_absolute_time(), deadline = now + delta;
kr == KERN_ABORTED; now = mach_absolute_time()) { kr == KERN_ABORTED; now = mach_absolute_time())
if (now > deadline) { {
// timed out by definition if (now > deadline)
return false; {
} // timed out by definition
return false;
}
u64 timeleft = deadline - now; u64 timeleft = deadline - now;
ts.tv_sec = timeleft / kOneBillion; ts.tv_sec = timeleft / kOneBillion;
ts.tv_nsec = timeleft % kOneBillion; ts.tv_nsec = timeleft % kOneBillion;
// possible return values of semaphore_timedwait() (from XNU sources): // possible return values of semaphore_timedwait() (from XNU sources):
// internal kernel val -> return value // internal kernel val -> return value
// THREAD_INTERRUPTED -> KERN_ABORTED // THREAD_INTERRUPTED -> KERN_ABORTED
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT // THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
// THREAD_AWAKENED -> KERN_SUCCESS // THREAD_AWAKENED -> KERN_SUCCESS
// THREAD_RESTART -> KERN_TERMINATED // THREAD_RESTART -> KERN_TERMINATED
// default -> KERN_FAILURE // default -> KERN_FAILURE
kr = semaphore_timedwait(m_sema, ts); kr = semaphore_timedwait(m_sema, ts);
} }
if (kr == KERN_OPERATION_TIMED_OUT) { if (kr == KERN_OPERATION_TIMED_OUT)
return false; {
} return false;
}
// while it's entirely possible to have KERN_FAILURE here, we should // while it's entirely possible to have KERN_FAILURE here, we should
// probably assert so we can study and correct the actual error here // probably assert so we can study and correct the actual error here
// (the thread dying while someone is wainting for it). // (the thread dying while someone is wainting for it).
MACH_CHECK(kr); MACH_CHECK(kr);
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); __atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
return true; return true;
} }
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's // This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
@ -155,18 +161,24 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
void Threading::Semaphore::Wait() void Threading::Semaphore::Wait()
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
WaitWithoutYield(); {
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) { WaitWithoutYield();
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
WaitWithoutYield(); else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
} else { {
while (!WaitWithoutYield(def_yieldgui_interval)) { ScopedBusyCursor hourglass(Cursor_ReallyBusy);
YieldToMain(); WaitWithoutYield();
} }
} else
{
while (!WaitWithoutYield(def_yieldgui_interval))
{
YieldToMain();
}
}
#else #else
WaitWithoutYield(); WaitWithoutYield();
#endif #endif
} }
@ -179,29 +191,35 @@ void Threading::Semaphore::Wait()
// false if the wait timed out before the semaphore was signaled, or true if the signal was // false if the wait timed out before the semaphore was signaled, or true if the signal was
// reached prior to timeout. // reached prior to timeout.
// //
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout) bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
return WaitWithoutYield(timeout); {
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) { return WaitWithoutYield(timeout);
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
return WaitWithoutYield(timeout); else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
} else { {
//ScopedBusyCursor hourglass( Cursor_KindaBusy ); ScopedBusyCursor hourglass(Cursor_ReallyBusy);
wxTimeSpan countdown((timeout)); return WaitWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do { do
if (WaitWithoutYield(def_yieldgui_interval)) {
break; if (WaitWithoutYield(def_yieldgui_interval))
YieldToMain(); break;
countdown -= def_yieldgui_interval; YieldToMain();
} while (countdown.GetMilliseconds() > 0); countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0; return countdown.GetMilliseconds() > 0;
} }
#else #else
return WaitWithoutYield(timeout); return WaitWithoutYield(timeout);
#endif #endif
} }
@ -220,22 +238,22 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
// POSIX threads), this should work. -- aktau // POSIX threads), this should work. -- aktau
void Threading::Semaphore::WaitNoCancel() void Threading::Semaphore::WaitNoCancel()
{ {
int oldstate; int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
Wait(); Wait();
pthread_setcancelstate(oldstate, NULL); pthread_setcancelstate(oldstate, NULL);
} }
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout) void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
{ {
int oldstate; int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
Wait(timeout); Wait(timeout);
pthread_setcancelstate(oldstate, NULL); pthread_setcancelstate(oldstate, NULL);
} }
int Threading::Semaphore::Count() int Threading::Semaphore::Count()
{ {
return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST); return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST);
} }
#endif #endif

View File

@ -29,27 +29,27 @@
__forceinline void Threading::Sleep(int ms) __forceinline void Threading::Sleep(int ms)
{ {
usleep(1000 * ms); usleep(1000 * ms);
} }
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory // For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption. // improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait() __forceinline void Threading::SpinWait()
{ {
// If this doesn't compile you can just comment it out (it only serves as a // If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required). // performance hint and isn't required).
__asm__("pause"); __asm__("pause");
} }
__forceinline void Threading::EnableHiresScheduler() __forceinline void Threading::EnableHiresScheduler()
{ {
// Darwin has customizable schedulers, see xnu/osfmk/man. Not // Darwin has customizable schedulers, see xnu/osfmk/man. Not
// implemented yet though (and not sure if useful for pcsx2). // implemented yet though (and not sure if useful for pcsx2).
} }
__forceinline void Threading::DisableHiresScheduler() __forceinline void Threading::DisableHiresScheduler()
{ {
// see EnableHiresScheduler() // see EnableHiresScheduler()
} }
// Just like on Windows, this is not really the number of ticks per second, // Just like on Windows, this is not really the number of ticks per second,
@ -58,27 +58,28 @@ __forceinline void Threading::DisableHiresScheduler()
// doing this will of course yield precision loss. // doing this will of course yield precision loss.
u64 Threading::GetThreadTicksPerSecond() u64 Threading::GetThreadTicksPerSecond()
{ {
return 1000000; // the *CpuTime() functions return values in microseconds return 1000000; // the *CpuTime() functions return values in microseconds
} }
// gets the CPU time used by the current thread (both system and user), in // gets the CPU time used by the current thread (both system and user), in
// microseconds, returns 0 on failure // microseconds, returns 0 on failure
static u64 getthreadtime(thread_port_t thread) static u64 getthreadtime(thread_port_t thread)
{ {
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info; thread_basic_info_data_t info;
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO, kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
(thread_info_t)&info, &count); (thread_info_t)&info, &count);
if (kr != KERN_SUCCESS) { if (kr != KERN_SUCCESS)
return 0; {
} return 0;
}
// add system and user time // add system and user time
return (u64)info.user_time.seconds * (u64)1e6 + return (u64)info.user_time.seconds * (u64)1e6 +
(u64)info.user_time.microseconds + (u64)info.user_time.microseconds +
(u64)info.system_time.seconds * (u64)1e6 + (u64)info.system_time.seconds * (u64)1e6 +
(u64)info.system_time.microseconds; (u64)info.system_time.microseconds;
} }
// Returns the current timestamp (not relative to a real world clock) in // Returns the current timestamp (not relative to a real world clock) in
@ -88,44 +89,45 @@ static u64 getthreadtime(thread_port_t thread)
// not very good. // not very good.
u64 Threading::GetThreadCpuTime() u64 Threading::GetThreadCpuTime()
{ {
// we could also use mach_thread_self() and mach_port_deallocate(), but // we could also use mach_thread_self() and mach_port_deallocate(), but
// that calls upon mach traps (kinda like system calls). Unless I missed // that calls upon mach traps (kinda like system calls). Unless I missed
// something in the COMMPAGE (like Linux vDSO) which makes overrides it // something in the COMMPAGE (like Linux vDSO) which makes overrides it
// to be user-space instead. In contract, // to be user-space instead. In contract,
// pthread_mach_thread_np(pthread_self()) is entirely in user-space. // pthread_mach_thread_np(pthread_self()) is entirely in user-space.
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self())); u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
return us * 10ULL; return us * 10ULL;
} }
u64 Threading::pxThread::GetCpuTime() const u64 Threading::pxThread::GetCpuTime() const
{ {
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or // Get the cpu time for the thread belonging to this object. Use m_native_id and/or
// m_native_handle to implement it. Return value should be a measure of total time the // m_native_handle to implement it. Return value should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(), // thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort). // which typically would be an OS-provided scalar or some sort).
if (!m_native_id) { if (!m_native_id)
return 0; {
} return 0;
}
return getthreadtime((thread_port_t)m_native_id) * 10ULL; return getthreadtime((thread_port_t)m_native_id) * 10ULL;
} }
void Threading::pxThread::_platform_specific_OnStartInThread() void Threading::pxThread::_platform_specific_OnStartInThread()
{ {
m_native_id = (uptr)mach_thread_self(); m_native_id = (uptr)mach_thread_self();
} }
void Threading::pxThread::_platform_specific_OnCleanupInThread() void Threading::pxThread::_platform_specific_OnCleanupInThread()
{ {
// cleanup of handles that were upened in // cleanup of handles that were upened in
// _platform_specific_OnStartInThread // _platform_specific_OnStartInThread
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id); mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
} }
// name can be up to 16 bytes // name can be up to 16 bytes
void Threading::SetNameOfCurrentThread(const char *name) void Threading::SetNameOfCurrentThread(const char* name)
{ {
pthread_setname_np(name); pthread_setname_np(name);
} }
#endif #endif

View File

@ -61,44 +61,48 @@
// method is not implemented! You must implement it yourself if you want to use it: // method is not implemented! You must implement it yourself if you want to use it:
// EnumToString(value); // EnumToString(value);
// //
#define ImplementEnumOperators(enumName) \ #define ImplementEnumOperators(enumName) \
static __fi enumName &operator++(enumName &src) \ static __fi enumName& operator++(enumName& src) \
{ \ { \
src = (enumName)((int)src + 1); \ src = (enumName)((int)src + 1); \
return src; \ return src; \
} \ } \
static __fi enumName &operator--(enumName &src) \ \
{ \ static __fi enumName& operator--(enumName& src) \
src = (enumName)((int)src - 1); \ { \
return src; \ src = (enumName)((int)src - 1); \
} \ return src; \
static __fi enumName operator++(enumName &src, int) \ } \
{ \ \
enumName orig = src; \ static __fi enumName operator++(enumName& src, int) \
src = (enumName)((int)src + 1); \ { \
return orig; \ enumName orig = src; \
} \ src = (enumName)((int)src + 1); \
static __fi enumName operator--(enumName &src, int) \ return orig; \
{ \ } \
enumName orig = src; \ \
src = (enumName)((int)src - 1); \ static __fi enumName operator--(enumName& src, int) \
return orig; \ { \
} \ enumName orig = src; \
\ src = (enumName)((int)src - 1); \
static __fi bool operator<(const enumName &left, const pxEnumEnd_t &) { return (int)left < enumName##_COUNT; } \ return orig; \
static __fi bool operator!=(const enumName &left, const pxEnumEnd_t &) { return (int)left != enumName##_COUNT; } \ } \
static __fi bool operator==(const enumName &left, const pxEnumEnd_t &) { return (int)left == enumName##_COUNT; } \ \
\ static __fi bool operator<(const enumName& left, const pxEnumEnd_t&) { return (int)left < enumName##_COUNT; } \
static __fi bool EnumIsValid(enumName id) \ static __fi bool operator!=(const enumName& left, const pxEnumEnd_t&) { return (int)left != enumName##_COUNT; } \
{ \ static __fi bool operator==(const enumName& left, const pxEnumEnd_t&) { return (int)left == enumName##_COUNT; } \
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \ \
} \ static __fi bool EnumIsValid(enumName id) \
static __fi void EnumAssert(enumName id) \ { \
{ \ return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
pxAssert(EnumIsValid(id)); \ } \
} \ \
\ static __fi void EnumAssert(enumName id) \
extern const wxChar *EnumToString(enumName id) { \
pxAssert(EnumIsValid(id)); \
} \
\
extern const wxChar* EnumToString(enumName id)
class pxEnumEnd_t class pxEnumEnd_t
{ {
@ -130,9 +134,9 @@ static const pxEnumEnd_t pxEnumEnd = {};
// //
#ifndef DeclareNoncopyableObject #ifndef DeclareNoncopyableObject
#define DeclareNoncopyableObject(classname) \ #define DeclareNoncopyableObject(classname) \
private: \ private: \
explicit classname(const classname &); \ explicit classname(const classname&); \
classname &operator=(const classname &) classname& operator=(const classname&)
#endif #endif
@ -144,19 +148,19 @@ private: \
class ScopedBool class ScopedBool
{ {
protected: protected:
bool *m_boolme; bool* m_boolme;
public: public:
ScopedBool(bool &boolme) ScopedBool(bool& boolme)
{ {
boolme = true; boolme = true;
m_boolme = &boolme; m_boolme = &boolme;
} }
~ScopedBool() ~ScopedBool()
{ {
*m_boolme = false; *m_boolme = false;
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -218,7 +222,7 @@ public:
#include <stdexcept> #include <stdexcept>
#include <cstring> // string.h under c++ #include <cstring> // string.h under c++
#include <cstdio> // stdio.h under c++ #include <cstdio> // stdio.h under c++
#include <cstdlib> #include <cstdlib>
#include <vector> #include <vector>
#include <list> #include <list>
@ -262,12 +266,12 @@ static const s64 _4gb = _1gb * 4;
#define pxE_dev(english) pxExpandMsg((english)) #define pxE_dev(english) pxExpandMsg((english))
extern const wxChar *__fastcall pxExpandMsg(const wxChar *message); extern const wxChar* __fastcall pxExpandMsg(const wxChar* message);
extern const wxChar *__fastcall pxGetTranslation(const wxChar *message); extern const wxChar* __fastcall pxGetTranslation(const wxChar* message);
extern bool pxIsEnglish(int id); extern bool pxIsEnglish(int id);
extern wxString fromUTF8(const char *src); extern wxString fromUTF8(const char* src);
extern wxString fromAscii(const char *src); extern wxString fromAscii(const char* src);
#include "common/Assertions.h" #include "common/Assertions.h"

View File

@ -25,8 +25,8 @@
class IEmbeddedImage class IEmbeddedImage
{ {
public: public:
virtual const wxImage &Get() = 0; virtual const wxImage& Get() = 0;
virtual wxImage Scale(int width, int height) = 0; virtual wxImage Scale(int width, int height) = 0;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -42,79 +42,80 @@ template <typename ImageType>
class EmbeddedImage : public IEmbeddedImage class EmbeddedImage : public IEmbeddedImage
{ {
protected: protected:
wxImage m_Image; wxImage m_Image;
const wxSize m_ResampleTo; const wxSize m_ResampleTo;
protected: protected:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Internal function used to ensure the image is loaded before returning the image // Internal function used to ensure the image is loaded before returning the image
// handle (called from all methods that return an image handle). // handle (called from all methods that return an image handle).
// //
void _loadImage() void _loadImage()
{ {
if (!m_Image.Ok()) { if (!m_Image.Ok())
wxMemoryInputStream joe(ImageType::Data, ImageType::Length); {
m_Image.LoadFile(joe, ImageType::GetFormat()); wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
m_Image.LoadFile(joe, ImageType::GetFormat());
if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight())) if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight()))
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH); m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
} }
} }
public: public:
EmbeddedImage() EmbeddedImage()
: m_Image() : m_Image()
, m_ResampleTo(wxDefaultSize) , m_ResampleTo(wxDefaultSize)
{ {
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Constructor for creating an embedded image that gets resampled to the specified size when // Constructor for creating an embedded image that gets resampled to the specified size when
// loaded. // loaded.
// //
// Implementation Note: This function uses wxWidgets ResamplBox method to resize the image. // Implementation Note: This function uses wxWidgets ResamplBox method to resize the image.
// wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down- // wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down-
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner // sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
// results. // results.
// //
EmbeddedImage(int newWidth, int newHeight) EmbeddedImage(int newWidth, int newHeight)
: m_Image() : m_Image()
, m_ResampleTo(newWidth, newHeight) , m_ResampleTo(newWidth, newHeight)
{ {
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Loads and retrieves the embedded image. The embedded image is only loaded from its em- // Loads and retrieves the embedded image. The embedded image is only loaded from its em-
// bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use // bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use
// the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once, // the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once,
// and only happens when the image is actually fetched. Simply creating an instance // and only happens when the image is actually fetched. Simply creating an instance
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :) // of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
// //
const wxImage &Get() const wxImage& Get()
{ {
_loadImage(); _loadImage();
return m_Image; return m_Image;
} }
wxIcon GetIcon() wxIcon GetIcon()
{ {
wxIcon retval; wxIcon retval;
retval.CopyFromBitmap(Get()); retval.CopyFromBitmap(Get());
return retval; return retval;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage // Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
// is left unmodified). // is left unmodified).
// //
wxImage Scale(int width, int height) wxImage Scale(int width, int height)
{ {
_loadImage(); _loadImage();
// Not strictly necessary - wxWidgets does the dimensions check anyway. // Not strictly necessary - wxWidgets does the dimensions check anyway.
if (width != m_Image.GetWidth() || height != m_Image.GetHeight()) if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH); return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
else else
return m_Image; return m_Image;
} }
}; };

View File

@ -26,54 +26,54 @@ template <typename ListenerType>
class EventSource class EventSource
{ {
public: public:
typedef typename ListenerType::EvtParams EvtParams; typedef typename ListenerType::EvtParams EvtParams;
typedef typename std::list<ListenerType *> ListenerList; typedef typename std::list<ListenerType*> ListenerList;
typedef typename ListenerList::iterator ListenerIterator; typedef typename ListenerList::iterator ListenerIterator;
protected: protected:
typedef typename ListenerList::const_iterator ConstIterator; typedef typename ListenerList::const_iterator ConstIterator;
ListenerList m_listeners; ListenerList m_listeners;
// This is a cached copy of the listener list used to handle standard dispatching, which // This is a cached copy of the listener list used to handle standard dispatching, which
// allows for self-modification of the EventSource's listener list by the listeners. // allows for self-modification of the EventSource's listener list by the listeners.
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation. // Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
ListenerList m_cache_copy; ListenerList m_cache_copy;
bool m_cache_valid; bool m_cache_valid;
Threading::Mutex m_listeners_lock; Threading::Mutex m_listeners_lock;
public: public:
EventSource() EventSource()
{ {
m_cache_valid = false; m_cache_valid = false;
} }
virtual ~EventSource() = default; virtual ~EventSource() = default;
virtual ListenerIterator Add(ListenerType &listener); virtual ListenerIterator Add(ListenerType& listener);
virtual void Remove(ListenerType &listener); virtual void Remove(ListenerType& listener);
virtual void Remove(const ListenerIterator &listenerHandle); virtual void Remove(const ListenerIterator& listenerHandle);
void Add(ListenerType *listener) void Add(ListenerType* listener)
{ {
if (listener == NULL) if (listener == NULL)
return; return;
Add(*listener); Add(*listener);
} }
void Remove(ListenerType *listener) void Remove(ListenerType* listener)
{ {
if (listener == NULL) if (listener == NULL)
return; return;
Remove(*listener); Remove(*listener);
} }
void Dispatch(const EvtParams &params); void Dispatch(const EvtParams& params);
protected: protected:
virtual ListenerIterator _AddFast_without_lock(ListenerType &listener); virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams &params); virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -86,9 +86,9 @@ template <typename EvtParams>
class IEventDispatcher class IEventDispatcher
{ {
protected: protected:
IEventDispatcher() {} IEventDispatcher() {}
public: public:
virtual ~IEventDispatcher() = default; virtual ~IEventDispatcher() = default;
virtual void DispatchEvent(const EvtParams &params) = 0; virtual void DispatchEvent(const EvtParams& params) = 0;
}; };

View File

@ -20,79 +20,92 @@
using Threading::ScopedLock; using Threading::ScopedLock;
template <typename ListenerType> template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType &listener) typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
{ {
ScopedLock locker(m_listeners_lock); ScopedLock locker(m_listeners_lock);
// Check for duplicates before adding the event. // Check for duplicates before adding the event.
if (IsDebugBuild) { if (IsDebugBuild)
ListenerIterator iter = m_listeners.begin(); {
while (iter != m_listeners.end()) { ListenerIterator iter = m_listeners.begin();
if ((*iter) == &listener) while (iter != m_listeners.end())
return iter; {
++iter; if ((*iter) == &listener)
} return iter;
} ++iter;
return _AddFast_without_lock(listener); }
}
return _AddFast_without_lock(listener);
} }
template <typename ListenerType> template <typename ListenerType>
void EventSource<ListenerType>::Remove(ListenerType &listener) void EventSource<ListenerType>::Remove(ListenerType& listener)
{ {
ScopedLock locker(m_listeners_lock); ScopedLock locker(m_listeners_lock);
m_cache_valid = false; m_cache_valid = false;
m_listeners.remove(&listener); m_listeners.remove(&listener);
} }
template <typename ListenerType> template <typename ListenerType>
void EventSource<ListenerType>::Remove(const ListenerIterator &listenerHandle) void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
{ {
ScopedLock locker(m_listeners_lock); ScopedLock locker(m_listeners_lock);
m_cache_valid = false; m_cache_valid = false;
m_listeners.erase(listenerHandle); m_listeners.erase(listenerHandle);
} }
template <typename ListenerType> template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType &listener) typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
{ {
m_cache_valid = false; m_cache_valid = false;
m_listeners.push_front(&listener); m_listeners.push_front(&listener);
return m_listeners.begin(); return m_listeners.begin();
} }
template <typename ListenerType> template <typename ListenerType>
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams &evtparams) __fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
{ {
while (iter != iend) { while (iter != iend)
try { {
(*iter)->DispatchEvent(evtparams); try
} catch (Exception::RuntimeError &ex) { {
if (IsDevBuild) { (*iter)->DispatchEvent(evtparams);
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage()); }
} else { catch (Exception::RuntimeError& ex)
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage()); {
} if (IsDevBuild)
} catch (BaseException &ex) { {
if (IsDevBuild) { pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg(); }
throw; else
} {
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage()); Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
} }
++iter; }
} catch (BaseException& ex)
{
if (IsDevBuild)
{
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
throw;
}
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage());
}
++iter;
}
} }
template <typename ListenerType> template <typename ListenerType>
void EventSource<ListenerType>::Dispatch(const EvtParams &evtparams) void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
{ {
if (!m_cache_valid) { if (!m_cache_valid)
m_cache_copy = m_listeners; {
m_cache_valid = true; m_cache_copy = m_listeners;
} m_cache_valid = true;
}
if (m_cache_copy.empty()) if (m_cache_copy.empty())
return; return;
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams); _DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
} }

View File

@ -42,28 +42,28 @@ Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
// That's ok. What we don't want is the *same* thread recurse-asserting. // That's ok. What we don't want is the *same* thread recurse-asserting.
static DeclareTls(int) s_assert_guard(0); static DeclareTls(int) s_assert_guard(0);
pxDoAssertFnType *pxDoAssert = pxAssertImpl_LogIt; pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
// make life easier for people using VC++ IDE by using this format, which allows double-click // make life easier for people using VC++ IDE by using this format, which allows double-click
// response times from the Output window... // response times from the Output window...
wxString DiagnosticOrigin::ToString(const wxChar *msg) const wxString DiagnosticOrigin::ToString(const wxChar* msg) const
{ {
FastFormatUnicode message; FastFormatUnicode message;
message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line); message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line);
if (function != NULL) if (function != NULL)
message.Write(" Function: %s\n", function); message.Write(" Function: %s\n", function);
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName())); message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
if (condition != NULL) if (condition != NULL)
message.Write(L" Condition: %ls\n", condition); message.Write(L" Condition: %ls\n", condition);
if (msg != NULL) if (msg != NULL)
message.Write(L" Message: %ls\n", msg); message.Write(L" Message: %ls\n", msg);
return message; return message;
} }
@ -71,191 +71,196 @@ wxString DiagnosticOrigin::ToString(const wxChar *msg) const
void pxTrap() void pxTrap()
{ {
#if defined(__WXMSW__) && !defined(__WXMICROWIN__) #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
__debugbreak(); __debugbreak();
#elif defined(__WXMAC__) && !defined(__DARWIN__) #elif defined(__WXMAC__) && !defined(__DARWIN__)
#if __powerc #if __powerc
Debugger(); Debugger();
#else #else
SysBreak(); SysBreak();
#endif #endif
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
Debugger(); Debugger();
#elif defined(__UNIX__) #elif defined(__UNIX__)
raise(SIGTRAP); raise(SIGTRAP);
#else #else
// TODO // TODO
#endif // Win/Unix #endif // Win/Unix
} }
bool pxAssertImpl_LogIt(const DiagnosticOrigin &origin, const wxChar *msg) bool pxAssertImpl_LogIt(const DiagnosticOrigin& origin, const wxChar* msg)
{ {
//wxLogError( L"%s", origin.ToString( msg ).c_str() ); //wxLogError( L"%s", origin.ToString( msg ).c_str() );
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str()); wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
pxTrap(); pxTrap();
return false; return false;
} }
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg) DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg)
{ {
// Recursion guard: Allow at least one recursive call. This is useful because sometimes // Recursion guard: Allow at least one recursive call. This is useful because sometimes
// we get meaningless assertions while unwinding stack traces after exceptions have occurred. // we get meaningless assertions while unwinding stack traces after exceptions have occurred.
RecursionGuard guard(s_assert_guard); RecursionGuard guard(s_assert_guard);
if (guard.Counter > 2) { if (guard.Counter > 2)
return pxTrap(); {
} return pxTrap();
}
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make // wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
// it difficult to use the debug build (compilation failures). To handle these I've had to // it difficult to use the debug build (compilation failures). To handle these I've had to
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if // bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
// PCSX2 itself is compiled in debug mode (assertions enabled). // PCSX2 itself is compiled in debug mode (assertions enabled).
bool trapit; bool trapit;
if (pxDoAssert == NULL) { if (pxDoAssert == NULL)
// Note: Format uses MSVC's syntax for output window hotlinking. {
trapit = pxAssertImpl_LogIt(origin, msg.wc_str()); // Note: Format uses MSVC's syntax for output window hotlinking.
} else { trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
trapit = pxDoAssert(origin, msg.wc_str()); }
} else
{
trapit = pxDoAssert(origin, msg.wc_str());
}
if (trapit) { if (trapit)
pxTrap(); {
} pxTrap();
}
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseException (implementations) // BaseException (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
BaseException &BaseException::SetBothMsgs(const wxChar *msg_diag) BaseException& BaseException::SetBothMsgs(const wxChar* msg_diag)
{ {
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString(""); m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
return SetDiagMsg(msg_diag); return SetDiagMsg(msg_diag);
} }
BaseException &BaseException::SetDiagMsg(const wxString &msg_diag) BaseException& BaseException::SetDiagMsg(const wxString& msg_diag)
{ {
m_message_diag = msg_diag; m_message_diag = msg_diag;
return *this; return *this;
} }
BaseException &BaseException::SetUserMsg(const wxString &msg_user) BaseException& BaseException::SetUserMsg(const wxString& msg_user)
{ {
m_message_user = msg_user; m_message_user = msg_user;
return *this; return *this;
} }
wxString BaseException::FormatDiagnosticMessage() const wxString BaseException::FormatDiagnosticMessage() const
{ {
return m_message_diag; return m_message_diag;
} }
wxString BaseException::FormatDisplayMessage() const wxString BaseException::FormatDisplayMessage() const
{ {
return m_message_user.IsEmpty() ? m_message_diag : m_message_user; return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Exception::RuntimeError (implementations) // Exception::RuntimeError (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError(const std::runtime_error &ex, const wxString &prefix) Exception::RuntimeError::RuntimeError(const std::runtime_error& ex, const wxString& prefix)
{ {
IsSilent = false; IsSilent = false;
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s", SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()), (prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
WX_STR(fromUTF8(ex.what())))); WX_STR(fromUTF8(ex.what()))));
} }
Exception::RuntimeError::RuntimeError(const std::exception &ex, const wxString &prefix) Exception::RuntimeError::RuntimeError(const std::exception& ex, const wxString& prefix)
{ {
IsSilent = false; IsSilent = false;
SetDiagMsg(pxsFmt(L"STL Exception%s: %s", SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()), (prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
WX_STR(fromUTF8(ex.what())))); WX_STR(fromUTF8(ex.what()))));
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Exception::OutOfMemory (implementations) // Exception::OutOfMemory (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Exception::OutOfMemory::OutOfMemory(const wxString &allocdesc) Exception::OutOfMemory::OutOfMemory(const wxString& allocdesc)
{ {
AllocDescription = allocdesc; AllocDescription = allocdesc;
} }
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retmsg; FastFormatUnicode retmsg;
retmsg.Write(L"Out of memory"); retmsg.Write(L"Out of memory");
if (!AllocDescription.IsEmpty()) if (!AllocDescription.IsEmpty())
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription)); retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
if (!m_message_diag.IsEmpty()) if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag)); retmsg.Write(L":\n%s", WX_STR(m_message_diag));
return retmsg; return retmsg;
} }
wxString Exception::OutOfMemory::FormatDisplayMessage() const wxString Exception::OutOfMemory::FormatDisplayMessage() const
{ {
FastFormatUnicode retmsg; FastFormatUnicode retmsg;
retmsg.Write(L"%s", _("Oh noes! Out of memory!")); retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
if (!m_message_user.IsEmpty()) if (!m_message_user.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_user)); retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
return retmsg; return retmsg;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Exception::VirtualMemoryMapConflict (implementations) // Exception::VirtualMemoryMapConflict (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString &allocdesc) Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString& allocdesc)
{ {
AllocDescription = allocdesc; AllocDescription = allocdesc;
m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs."); m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.");
} }
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retmsg; FastFormatUnicode retmsg;
retmsg.Write(L"Virtual memory map failed"); retmsg.Write(L"Virtual memory map failed");
if (!AllocDescription.IsEmpty()) if (!AllocDescription.IsEmpty())
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription)); retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
if (!m_message_diag.IsEmpty()) if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag)); retmsg.Write(L":\n%s", WX_STR(m_message_diag));
return retmsg; return retmsg;
} }
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
{ {
FastFormatUnicode retmsg; FastFormatUnicode retmsg;
retmsg.Write(L"%s", retmsg.Write(L"%s",
pxE(L"There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs.")); pxE(L"There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs."));
if (!m_message_diag.IsEmpty()) if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag)); retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
return retmsg; return retmsg;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
wxString Exception::CancelEvent::FormatDiagnosticMessage() const wxString Exception::CancelEvent::FormatDiagnosticMessage() const
{ {
return L"Action canceled: " + m_message_diag; return L"Action canceled: " + m_message_diag;
} }
wxString Exception::CancelEvent::FormatDisplayMessage() const wxString Exception::CancelEvent::FormatDisplayMessage() const
{ {
return L"Action canceled: " + m_message_diag; return L"Action canceled: " + m_message_diag;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -263,40 +268,40 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString Exception::BadStream::FormatDiagnosticMessage() const wxString Exception::BadStream::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
_formatDiagMsg(retval); _formatDiagMsg(retval);
return retval; return retval;
} }
wxString Exception::BadStream::FormatDisplayMessage() const wxString Exception::BadStream::FormatDisplayMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
_formatUserMsg(retval); _formatUserMsg(retval);
return retval; return retval;
} }
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode &dest) const void Exception::BadStream::_formatDiagMsg(FastFormatUnicode& dest) const
{ {
dest.Write(L"Path: "); dest.Write(L"Path: ");
if (!StreamName.IsEmpty()) if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName)); dest.Write(L"%s", WX_STR(StreamName));
else else
dest.Write(L"[Unnamed or unknown]"); dest.Write(L"[Unnamed or unknown]");
if (!m_message_diag.IsEmpty()) if (!m_message_diag.IsEmpty())
dest.Write(L"\n%s", WX_STR(m_message_diag)); dest.Write(L"\n%s", WX_STR(m_message_diag));
} }
void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const void Exception::BadStream::_formatUserMsg(FastFormatUnicode& dest) const
{ {
dest.Write(_("Path: ")); dest.Write(_("Path: "));
if (!StreamName.IsEmpty()) if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName)); dest.Write(L"%s", WX_STR(StreamName));
else else
dest.Write(_("[Unnamed or unknown]")); dest.Write(_("[Unnamed or unknown]"));
if (!m_message_user.IsEmpty()) if (!m_message_user.IsEmpty())
dest.Write(L"\n%s", WX_STR(m_message_user)); dest.Write(L"\n%s", WX_STR(m_message_user));
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -304,19 +309,19 @@ void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write("File could not be created."); retval.Write("File could not be created.");
_formatDiagMsg(retval); _formatDiagMsg(retval);
return retval; return retval;
} }
wxString Exception::CannotCreateStream::FormatDisplayMessage() const wxString Exception::CannotCreateStream::FormatDisplayMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write(_("A file could not be created.")); retval.Write(_("A file could not be created."));
retval.Write("\n"); retval.Write("\n");
_formatUserMsg(retval); _formatUserMsg(retval);
return retval; return retval;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -324,19 +329,19 @@ wxString Exception::CannotCreateStream::FormatDisplayMessage() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString Exception::FileNotFound::FormatDiagnosticMessage() const wxString Exception::FileNotFound::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write("File not found.\n"); retval.Write("File not found.\n");
_formatDiagMsg(retval); _formatDiagMsg(retval);
return retval; return retval;
} }
wxString Exception::FileNotFound::FormatDisplayMessage() const wxString Exception::FileNotFound::FormatDisplayMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write(_("File not found.")); retval.Write(_("File not found."));
retval.Write("\n"); retval.Write("\n");
_formatUserMsg(retval); _formatUserMsg(retval);
return retval; return retval;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -344,19 +349,19 @@ wxString Exception::FileNotFound::FormatDisplayMessage() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString Exception::AccessDenied::FormatDiagnosticMessage() const wxString Exception::AccessDenied::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write("Permission denied to file.\n"); retval.Write("Permission denied to file.\n");
_formatDiagMsg(retval); _formatDiagMsg(retval);
return retval; return retval;
} }
wxString Exception::AccessDenied::FormatDisplayMessage() const wxString Exception::AccessDenied::FormatDisplayMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights.")); retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
retval.Write("\n"); retval.Write("\n");
_formatUserMsg(retval); _formatUserMsg(retval);
return retval; return retval;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -364,19 +369,19 @@ wxString Exception::AccessDenied::FormatDisplayMessage() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString Exception::EndOfStream::FormatDiagnosticMessage() const wxString Exception::EndOfStream::FormatDiagnosticMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write("Unexpected end of file or stream.\n"); retval.Write("Unexpected end of file or stream.\n");
_formatDiagMsg(retval); _formatDiagMsg(retval);
return retval; return retval;
} }
wxString Exception::EndOfStream::FormatDisplayMessage() const wxString Exception::EndOfStream::FormatDisplayMessage() const
{ {
FastFormatUnicode retval; FastFormatUnicode retval;
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted.")); retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
retval.Write("\n"); retval.Write("\n");
_formatUserMsg(retval); _formatUserMsg(retval);
return retval; return retval;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -385,34 +390,35 @@ wxString Exception::EndOfStream::FormatDisplayMessage() const
// Translates an Errno code into an exception. // Translates an Errno code into an exception.
// Throws an exception based on the given error code (usually taken from ANSI C's errno) // Throws an exception based on the given error code (usually taken from ANSI C's errno)
BaseException *Exception::FromErrno(const wxString &streamname, int errcode) BaseException* Exception::FromErrno(const wxString& streamname, int errcode)
{ {
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)"); pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
switch (errcode) { switch (errcode)
case EINVAL: {
pxFailDev(L"Invalid argument"); case EINVAL:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)"); pxFailDev(L"Invalid argument");
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
case EACCES: // Access denied! case EACCES: // Access denied!
return new Exception::AccessDenied(streamname); return new Exception::AccessDenied(streamname);
case EMFILE: // Too many open files! case EMFILE: // Too many open files!
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EEXIST: case EEXIST:
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists"); return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
case ENOENT: // File not found! case ENOENT: // File not found!
return new Exception::FileNotFound(streamname); return new Exception::FileNotFound(streamname);
case EPIPE: case EPIPE:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe"); return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
case EBADF: case EBADF:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number"); return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
default: default:
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode)); return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
} }
} }

View File

@ -32,115 +32,121 @@ void pxTrap();
// friendly error log in their wake. // friendly error log in their wake.
// //
// Note: Console can also fire an Exception::OutOfMemory // Note: Console can also fire an Exception::OutOfMemory
#define __DESTRUCTOR_CATCHALL(funcname) \ #define __DESTRUCTOR_CATCHALL(funcname) \
catch (BaseException & ex) \ catch (BaseException & ex) \
{ \ { \
try { \ try \
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \ { \
Console.Error(ex.FormatDiagnosticMessage()); \ Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
} catch (...) { \ Console.Error(ex.FormatDiagnosticMessage()); \
fprintf(stderr, "ERROR: (out of memory?)\n"); \ } \
} \ catch (...) \
} \ { \
catch (std::exception & ex) \ fprintf(stderr, "ERROR: (out of memory?)\n"); \
{ \ } \
try { \ } \
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \ catch (std::exception & ex) \
Console.Error(ex.what()); \ { \
} catch (...) { \ try \
fprintf(stderr, "ERROR: (out of memory?)\n"); \ { \
} \ Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
} \ Console.Error(ex.what()); \
catch (...) \ } \
{ \ catch (...) \
/* Unreachable code */ \ { \
} fprintf(stderr, "ERROR: (out of memory?)\n"); \
} \
} \
catch (...) \
{ \
/* Unreachable code */ \
}
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__) #define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
namespace Exception namespace Exception
{ {
class BaseException; class BaseException;
int MakeNewType(); int MakeNewType();
BaseException *FromErrno(const wxString &streamname, int errcode); BaseException* FromErrno(const wxString& streamname, int errcode);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseException // BaseException
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation, // std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
// so I made a replacement. The internal messages are non-const, which means that a // so I made a replacement. The internal messages are non-const, which means that a
// catch clause can optionally modify them and then re-throw to a top-level handler. // catch clause can optionally modify them and then re-throw to a top-level handler.
// //
// Note, this class is "abstract" which means you shouldn't use it directly like, ever. // Note, this class is "abstract" which means you shouldn't use it directly like, ever.
// Use Exception::RuntimeError instead for generic exceptions. // Use Exception::RuntimeError instead for generic exceptions.
// //
// Because exceptions are the (only!) really useful example of multiple inheritance, // Because exceptions are the (only!) really useful example of multiple inheritance,
// this class has only a trivial constructor, and must be manually initialized using // this class has only a trivial constructor, and must be manually initialized using
// InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence // InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
// is, by design, a lot of fail, especially when class initializers are mixed in. // is, by design, a lot of fail, especially when class initializers are mixed in.
// //
// [TODO] : Add an InnerException component, and Clone() facility. // [TODO] : Add an InnerException component, and Clone() facility.
// //
class BaseException class BaseException
{ {
protected: protected:
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred! wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred! wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
public: public:
virtual ~BaseException() = default; virtual ~BaseException() = default;
const wxString &DiagMsg() const { return m_message_diag; } const wxString& DiagMsg() const { return m_message_diag; }
const wxString &UserMsg() const { return m_message_user; } const wxString& UserMsg() const { return m_message_user; }
wxString &DiagMsg() { return m_message_diag; } wxString& DiagMsg() { return m_message_diag; }
wxString &UserMsg() { return m_message_user; } wxString& UserMsg() { return m_message_user; }
BaseException &SetBothMsgs(const wxChar *msg_diag); BaseException& SetBothMsgs(const wxChar* msg_diag);
BaseException &SetDiagMsg(const wxString &msg_diag); BaseException& SetDiagMsg(const wxString& msg_diag);
BaseException &SetUserMsg(const wxString &msg_user); BaseException& SetUserMsg(const wxString& msg_user);
// Returns a message suitable for diagnostic / logging purposes. // Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace. // This message is always in English, and includes a full stack trace.
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
// Returns a message suitable for end-user display. // Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such. // This message is usually meant for display in a user popup or such.
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual void Rethrow() const = 0; virtual void Rethrow() const = 0;
virtual BaseException *Clone() const = 0; virtual BaseException* Clone() const = 0;
}; };
typedef std::unique_ptr<BaseException> ScopedExcept; typedef std::unique_ptr<BaseException> ScopedExcept;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Ps2Generic Exception // Ps2Generic Exception
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc). // This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
// //
// Implementation note: does not derive from BaseException, so that we can use different // Implementation note: does not derive from BaseException, so that we can use different
// catch block hierarchies to handle them (if needed). // catch block hierarchies to handle them (if needed).
// //
// Translation Note: Currently these exceptions are never translated. English/diagnostic // Translation Note: Currently these exceptions are never translated. English/diagnostic
// format only. :) // format only. :)
// //
class Ps2Generic class Ps2Generic
{ {
protected: protected:
wxString m_message; // a "detailed" message of what disastrous thing has occurred! wxString m_message; // a "detailed" message of what disastrous thing has occurred!
public: public:
virtual ~Ps2Generic() = default; virtual ~Ps2Generic() = default;
virtual u32 GetPc() const = 0; virtual u32 GetPc() const = 0;
virtual bool IsDelaySlot() const = 0; virtual bool IsDelaySlot() const = 0;
virtual wxString &Message() { return m_message; } virtual wxString& Message() { return m_message; }
virtual void Rethrow() const = 0; virtual void Rethrow() const = 0;
virtual Ps2Generic *Clone() const = 0; virtual Ps2Generic* Clone() const = 0;
}; };
// Some helper macros for defining the standard constructors of internationalized constructors // Some helper macros for defining the standard constructors of internationalized constructors
// Parameters: // Parameters:
@ -157,240 +163,254 @@ public:
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010). // (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
// //
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \ #define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
private: \ private: \
typedef parent _parent; \ typedef parent _parent; \
\ \
public: \ public: \
virtual ~classname() = default; \ virtual ~classname() = default; \
virtual void Rethrow() const { throw * this; } \ \
virtual classname *Clone() const { return new classname(*this); } virtual void Rethrow() const \
{ \
throw *this; \
} \
\
virtual classname* Clone() const \
{ \
return new classname(*this); \
}
#define DEFINE_EXCEPTION_MESSAGES(classname) \ #define DEFINE_EXCEPTION_MESSAGES(classname) \
public: \ public: \
classname &SetBothMsgs(const wxChar *msg_diag) \ classname& SetBothMsgs(const wxChar* msg_diag) \
{ \ { \
BaseException::SetBothMsgs(msg_diag); \ BaseException::SetBothMsgs(msg_diag); \
return *this; \ return *this; \
} \ } \
classname &SetDiagMsg(const wxString &msg_diag) \ \
{ \ classname& SetDiagMsg(const wxString& msg_diag) \
m_message_diag = msg_diag; \ { \
return *this; \ m_message_diag = msg_diag; \
} \ return *this; \
classname &SetUserMsg(const wxString &msg_user) \ } \
{ \ \
m_message_user = msg_user; \ classname& SetUserMsg(const wxString& msg_user) \
return *this; \ { \
} m_message_user = msg_user; \
return *this; \
}
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \ #define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
DEFINE_EXCEPTION_COPYTORS(classname, parent) \ DEFINE_EXCEPTION_COPYTORS(classname, parent) \
classname() { SetDiagMsg(message); } \ classname() \
DEFINE_EXCEPTION_MESSAGES(classname) { \
SetDiagMsg(message); \
} \
DEFINE_EXCEPTION_MESSAGES(classname)
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits! // RuntimeError - Generalized Exceptions with Recoverable Traits!
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
class RuntimeError : public BaseException class RuntimeError : public BaseException
{ {
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException) DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
DEFINE_EXCEPTION_MESSAGES(RuntimeError) DEFINE_EXCEPTION_MESSAGES(RuntimeError)
public: public:
bool IsSilent; bool IsSilent;
RuntimeError() { IsSilent = false; } RuntimeError() { IsSilent = false; }
RuntimeError(const std::runtime_error &ex, const wxString &prefix = wxEmptyString); RuntimeError(const std::runtime_error& ex, const wxString& prefix = wxEmptyString);
RuntimeError(const std::exception &ex, const wxString &prefix = wxEmptyString); RuntimeError(const std::exception& ex, const wxString& prefix = wxEmptyString);
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion // CancelAppEvent - Exception for canceling an event in a non-verbose fashion
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception // Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
// instead issues a "silent" cancelation that is handled by the app gracefully (generates // instead issues a "silent" cancelation that is handled by the app gracefully (generates
// log, and resumes messages queue processing). // log, and resumes messages queue processing).
// //
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside // I chose to have this exception derive from RuntimeError, since if one is thrown from outside
// an App message loop we'll still want it to be handled in a reasonably graceful manner. // an App message loop we'll still want it to be handled in a reasonably graceful manner.
class CancelEvent : public RuntimeError class CancelEvent : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given.")) DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given."))
public: public:
explicit CancelEvent(const wxString &logmsg) explicit CancelEvent(const wxString& logmsg)
{ {
m_message_diag = logmsg; m_message_diag = logmsg;
// overridden message formatters only use the diagnostic version... // overridden message formatters only use the diagnostic version...
} }
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// OutOfMemory // OutOfMemory
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing // This exception has a custom-formatted Diagnostic string. The parameter give when constructing
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic // the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
// output. The default diagnostic message is "Out of memory exception, while allocating the %s." // output. The default diagnostic message is "Out of memory exception, while allocating the %s."
// where %s is filled in with the block name. // where %s is filled in with the block name.
// //
// The user string is not custom-formatted, and should contain *NO* %s tags. // The user string is not custom-formatted, and should contain *NO* %s tags.
// //
class OutOfMemory : public RuntimeError class OutOfMemory : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString) DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString)
public: public:
wxString AllocDescription; wxString AllocDescription;
public: public:
OutOfMemory(const wxString &allocdesc); OutOfMemory(const wxString& allocdesc);
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
class ParseError : public RuntimeError class ParseError : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error")); DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
}; };
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// Hardware/OS Exceptions: // Hardware/OS Exceptions:
// HardwareDeficiency / VirtualMemoryMapConflict // HardwareDeficiency / VirtualMemoryMapConflict
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// This exception is a specific type of OutOfMemory error that isn't "really" an out of // This exception is a specific type of OutOfMemory error that isn't "really" an out of
// memory error. More likely it's caused by a plugin or driver reserving a range of memory // memory error. More likely it's caused by a plugin or driver reserving a range of memory
// we'd really like to have access to. // we'd really like to have access to.
class VirtualMemoryMapConflict : public OutOfMemory class VirtualMemoryMapConflict : public OutOfMemory
{ {
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString) DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString)
VirtualMemoryMapConflict(const wxString &allocdesc); VirtualMemoryMapConflict(const wxString& allocdesc);
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
class HardwareDeficiency : public RuntimeError class HardwareDeficiency : public RuntimeError
{ {
public: public:
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood.")); DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
}; };
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// Streaming (file) Exceptions: // Streaming (file) Exceptions:
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream // Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \ #define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
virtual classname &SetStreamName(const wxString &name) \ virtual classname& SetStreamName(const wxString& name) \
{ \ { \
StreamName = name; \ StreamName = name; \
return *this; \ return *this; \
} \ } \
virtual classname &SetStreamName(const char *name) \ \
{ \ virtual classname& SetStreamName(const char* name) \
StreamName = fromUTF8(name); \ { \
return *this; \ StreamName = fromUTF8(name); \
} return *this; \
}
#define DEFINE_STREAM_EXCEPTION(classname, parent) \ #define DEFINE_STREAM_EXCEPTION(classname, parent) \
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \ DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
classname(const wxString &filename) \ classname(const wxString& filename) \
{ \ { \
StreamName = filename; \ StreamName = filename; \
} \ } \
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of // A generic base error class for bad streams -- corrupted data, sudden closures, loss of
// connection, or anything else that would indicate a failure to open a stream or read the // connection, or anything else that would indicate a failure to open a stream or read the
// data after the stream was successfully opened. // data after the stream was successfully opened.
// //
class BadStream : public RuntimeError class BadStream : public RuntimeError
{ {
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError) DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
public: public:
wxString StreamName; // name of the stream (if applicable) wxString StreamName; // name of the stream (if applicable)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
protected: protected:
void _formatDiagMsg(FastFormatUnicode &dest) const; void _formatDiagMsg(FastFormatUnicode& dest) const;
void _formatUserMsg(FastFormatUnicode &dest) const; void _formatUserMsg(FastFormatUnicode& dest) const;
}; };
// A generic exception for odd-ball stream creation errors. // A generic exception for odd-ball stream creation errors.
// //
class CannotCreateStream : public BadStream class CannotCreateStream : public BadStream
{ {
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream) DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
}; };
// Exception thrown when an attempt to open a non-existent file is made. // Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid) // (this exception can also mean file permissions are invalid)
// //
class FileNotFound : public CannotCreateStream class FileNotFound : public CannotCreateStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream) DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
}; };
class AccessDenied : public CannotCreateStream class AccessDenied : public CannotCreateStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream) DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
}; };
// EndOfStream can be used either as an error, or used just as a shortcut for manual // EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks. // feof checks.
// //
class EndOfStream : public BadStream class EndOfStream : public BadStream
{ {
public: public:
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream) DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
}; };
#ifdef __WXMSW__ #ifdef __WXMSW__
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Exception::WinApiError // Exception::WinApiError
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError class WinApiError : public RuntimeError
{ {
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError) DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(WinApiError) DEFINE_EXCEPTION_MESSAGES(WinApiError)
public: public:
int ErrorId; int ErrorId;
public: public:
WinApiError(); WinApiError();
wxString GetMsgFromWindows() const; wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
}; };
#endif #endif
} } // namespace Exception
using Exception::BaseException; using Exception::BaseException;
using Exception::ScopedExcept; using Exception::ScopedExcept;

View File

@ -33,88 +33,88 @@ template class SafeAlignedArray<u8, 16>;
// system deadlock. // system deadlock.
static const int MaxFormattedStringLength = 0x80000; static const int MaxFormattedStringLength = 0x80000;
static
#ifndef __linux__ #ifndef __linux__
__ri static __ri void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
#else
static void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
#endif #endif
void
format_that_ascii_mess(CharBufferType &buffer, uint writepos, const char *fmt, va_list argptr)
{ {
va_list args; va_list args;
while (true) { while (true)
int size = buffer.GetLength(); {
int size = buffer.GetLength();
va_copy(args, argptr); va_copy(args, argptr);
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args); int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
va_end(args); va_end(args);
// some implementations of vsnprintf() don't NUL terminate // some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so // the string if there is not enough space for it so
// always do it manually // always do it manually
buffer[size - 1] = '\0'; buffer[size - 1] = '\0';
if (size >= MaxFormattedStringLength) if (size >= MaxFormattedStringLength)
break; break;
// vsnprintf() may return either -1 (traditional Unix behavior) or the // vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the // total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98) // buffer were large enough (newer standards such as Unix98)
if (len < 0) if (len < 0)
len = size + (size / 4); len = size + (size / 4);
len += writepos; len += writepos;
if (len < size) if (len < size)
break; break;
buffer.Resize(len + 128); buffer.Resize(len + 128);
}; };
// performing an assertion or log of a truncated string is unsafe, so let's not; even // performing an assertion or log of a truncated string is unsafe, so let's not; even
// though it'd be kinda nice if we did. // though it'd be kinda nice if we did.
} }
// returns the length of the formatted string, in characters (wxChars). // returns the length of the formatted string, in characters (wxChars).
static
#ifndef __linux__ #ifndef __linux__
__ri static __ri uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
#else
static uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
#endif #endif
uint
format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr)
{ {
va_list args; va_list args;
while (true) { while (true)
int size = buffer.GetLength() / sizeof(wxChar); {
int size = buffer.GetLength() / sizeof(wxChar);
va_copy(args, argptr); va_copy(args, argptr);
int len = wxVsnprintf((wxChar *)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args); int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
va_end(args); va_end(args);
// some implementations of vsnprintf() don't NUL terminate // some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so // the string if there is not enough space for it so
// always do it manually // always do it manually
((wxChar *)buffer.GetPtr())[size - 1] = L'\0'; ((wxChar*)buffer.GetPtr())[size - 1] = L'\0';
if (size >= MaxFormattedStringLength) if (size >= MaxFormattedStringLength)
return size - 1; return size - 1;
// vsnprintf() may return either -1 (traditional Unix behavior) or the // vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the // total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98) // buffer were large enough (newer standards such as Unix98)
if (len < 0) if (len < 0)
len = size + (size / 4); len = size + (size / 4);
len += writepos; len += writepos;
if (len < size) if (len < size)
return len; return len;
buffer.Resize((len + 128) * sizeof(wxChar)); buffer.Resize((len + 128) * sizeof(wxChar));
}; };
// performing an assertion or log of a truncated string is unsafe, so let's not; even // performing an assertion or log of a truncated string is unsafe, so let's not; even
// though it'd be kinda nice if we did. // though it'd be kinda nice if we did.
pxAssume(false); pxAssume(false);
return 0; // unreachable. return 0; // unreachable.
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -127,124 +127,124 @@ static
// this class nicely in its current state. --air // this class nicely in its current state. --air
FastFormatUnicode::FastFormatUnicode() FastFormatUnicode::FastFormatUnicode()
: m_dest(2048) : m_dest(2048)
{ {
Clear(); Clear();
} }
void FastFormatUnicode::Clear() void FastFormatUnicode::Clear()
{ {
m_Length = 0; m_Length = 0;
((wxChar *)m_dest.GetPtr())[0] = 0; ((wxChar*)m_dest.GetPtr())[0] = 0;
} }
FastFormatUnicode &FastFormatUnicode::WriteV(const char *fmt, va_list argptr) FastFormatUnicode& FastFormatUnicode::WriteV(const char* fmt, va_list argptr)
{ {
wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr))); wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr)));
const uint inspos = m_Length; const uint inspos = m_Length;
const uint convLen = converted.Length(); const uint convLen = converted.Length();
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar)); m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
memcpy(&((wxChar *)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar)); memcpy(&((wxChar*)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
m_Length += convLen; m_Length += convLen;
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::WriteV(const wxChar *fmt, va_list argptr) FastFormatUnicode& FastFormatUnicode::WriteV(const wxChar* fmt, va_list argptr)
{ {
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr); m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::Write(const char *fmt, ...) FastFormatUnicode& FastFormatUnicode::Write(const char* fmt, ...)
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::Write(const wxChar *fmt, ...) FastFormatUnicode& FastFormatUnicode::Write(const wxChar* fmt, ...)
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::Write(const wxString fmt, ...) FastFormatUnicode& FastFormatUnicode::Write(const wxString fmt, ...)
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt.wx_str(), list); WriteV(fmt.wx_str(), list);
va_end(list); va_end(list);
return *this; return *this;
} }
bool FastFormatUnicode::IsEmpty() const bool FastFormatUnicode::IsEmpty() const
{ {
return ((wxChar &)m_dest[0]) == 0; return ((wxChar&)m_dest[0]) == 0;
} }
FastFormatUnicode &FastFormatUnicode::ToUpper() FastFormatUnicode& FastFormatUnicode::ToUpper()
{ {
wxChar *ch = (wxChar *)m_dest.GetPtr(); wxChar* ch = (wxChar*)m_dest.GetPtr();
for (uint i = 0; i < m_Length; ++i, ++ch) for (uint i = 0; i < m_Length; ++i, ++ch)
*ch = (wxChar)wxToupper(*ch); *ch = (wxChar)wxToupper(*ch);
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::ToLower() FastFormatUnicode& FastFormatUnicode::ToLower()
{ {
wxChar *ch = (wxChar *)m_dest.GetPtr(); wxChar* ch = (wxChar*)m_dest.GetPtr();
for (uint i = 0; i < m_Length; ++i, ++ch) for (uint i = 0; i < m_Length; ++i, ++ch)
*ch = (wxChar)wxTolower(*ch); *ch = (wxChar)wxTolower(*ch);
return *this; return *this;
} }
FastFormatUnicode &FastFormatUnicode::operator+=(const char *psz) FastFormatUnicode& FastFormatUnicode::operator+=(const char* psz)
{ {
Write(L"%s", WX_STR(fromUTF8(psz))); Write(L"%s", WX_STR(fromUTF8(psz)));
return *this; return *this;
} }
wxString &operator+=(wxString &str1, const FastFormatUnicode &str2) wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
{ {
str1.Append(str2.c_str(), str2.Length()); str1.Append(str2.c_str(), str2.Length());
return str1; return str1;
} }
wxString operator+(const wxString &str1, const FastFormatUnicode &str2) wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
{ {
wxString s = str1; wxString s = str1;
s += str2; s += str2;
return s; return s;
} }
wxString operator+(const wxChar *str1, const FastFormatUnicode &str2) wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
{ {
wxString s = str1; wxString s = str1;
s += str2; s += str2;
return s; return s;
} }
wxString operator+(const FastFormatUnicode &str1, const wxString &str2) wxString operator+(const FastFormatUnicode& str1, const wxString& str2)
{ {
wxString s = str1; wxString s = str1;
s += str2; s += str2;
return s; return s;
} }
wxString operator+(const FastFormatUnicode &str1, const wxChar *str2) wxString operator+(const FastFormatUnicode& str1, const wxChar* str2)
{ {
wxString s = str1; wxString s = str1;
s += str2; s += str2;
return s; return s;
} }
@ -252,38 +252,38 @@ wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
// FastFormatAscii (implementations) // FastFormatAscii (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
FastFormatAscii::FastFormatAscii() FastFormatAscii::FastFormatAscii()
: m_dest(2048) : m_dest(2048)
{ {
Clear(); Clear();
} }
void FastFormatAscii::Clear() void FastFormatAscii::Clear()
{ {
m_dest.GetPtr()[0] = 0; m_dest.GetPtr()[0] = 0;
} }
const wxString FastFormatAscii::GetString() const const wxString FastFormatAscii::GetString() const
{ {
return fromAscii(m_dest.GetPtr()); return fromAscii(m_dest.GetPtr());
} }
FastFormatAscii &FastFormatAscii::WriteV(const char *fmt, va_list argptr) FastFormatAscii& FastFormatAscii::WriteV(const char* fmt, va_list argptr)
{ {
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr); format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
return *this; return *this;
} }
FastFormatAscii &FastFormatAscii::Write(const char *fmt, ...) FastFormatAscii& FastFormatAscii::Write(const char* fmt, ...)
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return *this; return *this;
} }
bool FastFormatAscii::IsEmpty() const bool FastFormatAscii::IsEmpty() const
{ {
return m_dest[0] == 0; return m_dest[0] == 0;
} }

View File

@ -26,17 +26,15 @@
// Macro used for removing some of the redtape involved in defining bitfield/union helpers. // Macro used for removing some of the redtape involved in defining bitfield/union helpers.
// //
#define BITFIELD32() \ #define BITFIELD32() \
union \ union \
{ \ { \
u32 bitset; \ u32 bitset; \
struct \ struct \
{ {
#define BITFIELD_END \ #define BITFIELD_END \
} \ }; \
; \ };
} \
;
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
@ -52,20 +50,20 @@
class RecursionGuard class RecursionGuard
{ {
public: public:
int &Counter; int& Counter;
RecursionGuard(int &counter) RecursionGuard(int& counter)
: Counter(counter) : Counter(counter)
{ {
++Counter; ++Counter;
} }
virtual ~RecursionGuard() virtual ~RecursionGuard()
{ {
--Counter; --Counter;
} }
bool IsReentrant() const { return Counter > 1; } bool IsReentrant() const { return Counter > 1; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -74,30 +72,30 @@ public:
class IActionInvocation class IActionInvocation
{ {
public: public:
virtual ~IActionInvocation() = default; virtual ~IActionInvocation() = default;
virtual void InvokeAction() = 0; virtual void InvokeAction() = 0;
}; };
class ICloneable class ICloneable
{ {
public: public:
virtual ICloneable *Clone() const = 0; virtual ICloneable* Clone() const = 0;
}; };
class IDeletableObject class IDeletableObject
{ {
public: public:
virtual ~IDeletableObject() = default; virtual ~IDeletableObject() = default;
virtual void DeleteSelf() = 0; virtual void DeleteSelf() = 0;
virtual bool IsBeingDeleted() = 0; virtual bool IsBeingDeleted() = 0;
protected: protected:
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost, // This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
// but if the SysCore is being linked to another front end, you'll need to implement this // but if the SysCore is being linked to another front end, you'll need to implement this
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll // yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?). // need to implement one yourself (yay?).
virtual void DoDeletion() = 0; virtual void DoDeletion() = 0;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -126,26 +124,26 @@ protected:
class BaseDeletableObject : public virtual IDeletableObject class BaseDeletableObject : public virtual IDeletableObject
{ {
protected: protected:
std::atomic<bool> m_IsBeingDeleted; std::atomic<bool> m_IsBeingDeleted;
public: public:
BaseDeletableObject(); BaseDeletableObject();
virtual ~BaseDeletableObject(); virtual ~BaseDeletableObject();
void DeleteSelf(); void DeleteSelf();
bool IsBeingDeleted() { return !!m_IsBeingDeleted; } bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
// Returns FALSE if the object is already marked for deletion, or TRUE if the app // Returns FALSE if the object is already marked for deletion, or TRUE if the app
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise // should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
// the object could get deleted twice if two threads try to schedule it at the same time. // the object could get deleted twice if two threads try to schedule it at the same time.
bool MarkForDeletion(); bool MarkForDeletion();
protected: protected:
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost, // This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
// but if the SysCore is being linked to another front end, you'll need to implement this // but if the SysCore is being linked to another front end, you'll need to implement this
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll // yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?). // need to implement one yourself (yay?).
virtual void DoDeletion(); virtual void DoDeletion();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -154,76 +152,76 @@ protected:
class PageProtectionMode class PageProtectionMode
{ {
protected: protected:
bool m_read; bool m_read;
bool m_write; bool m_write;
bool m_exec; bool m_exec;
public: public:
PageProtectionMode() PageProtectionMode()
{ {
All(false); All(false);
} }
PageProtectionMode &Read(bool allow = true) PageProtectionMode& Read(bool allow = true)
{ {
m_read = allow; m_read = allow;
return *this; return *this;
} }
PageProtectionMode &Write(bool allow = true) PageProtectionMode& Write(bool allow = true)
{ {
m_write = allow; m_write = allow;
return *this; return *this;
} }
PageProtectionMode &Execute(bool allow = true) PageProtectionMode& Execute(bool allow = true)
{ {
m_exec = allow; m_exec = allow;
return *this; return *this;
} }
PageProtectionMode &All(bool allow = true) PageProtectionMode& All(bool allow = true)
{ {
m_read = m_write = m_exec = allow; m_read = m_write = m_exec = allow;
return *this; return *this;
} }
bool CanRead() const { return m_read; } bool CanRead() const { return m_read; }
bool CanWrite() const { return m_write; } bool CanWrite() const { return m_write; }
bool CanExecute() const { return m_exec && m_read; } bool CanExecute() const { return m_exec && m_read; }
bool IsNone() const { return !m_read && !m_write; } bool IsNone() const { return !m_read && !m_write; }
wxString ToString() const; wxString ToString() const;
}; };
static __fi PageProtectionMode PageAccess_None() static __fi PageProtectionMode PageAccess_None()
{ {
return PageProtectionMode(); return PageProtectionMode();
} }
static __fi PageProtectionMode PageAccess_ReadOnly() static __fi PageProtectionMode PageAccess_ReadOnly()
{ {
return PageProtectionMode().Read(); return PageProtectionMode().Read();
} }
static __fi PageProtectionMode PageAccess_WriteOnly() static __fi PageProtectionMode PageAccess_WriteOnly()
{ {
return PageProtectionMode().Write(); return PageProtectionMode().Write();
} }
static __fi PageProtectionMode PageAccess_ReadWrite() static __fi PageProtectionMode PageAccess_ReadWrite()
{ {
return PageAccess_ReadOnly().Write(); return PageAccess_ReadOnly().Write();
} }
static __fi PageProtectionMode PageAccess_ExecOnly() static __fi PageProtectionMode PageAccess_ExecOnly()
{ {
return PageAccess_ReadOnly().Execute(); return PageAccess_ReadOnly().Execute();
} }
static __fi PageProtectionMode PageAccess_Any() static __fi PageProtectionMode PageAccess_Any()
{ {
return PageProtectionMode().All(); return PageProtectionMode().All();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -233,35 +231,35 @@ static __fi PageProtectionMode PageAccess_Any()
// platform prior to wxWidgets .. it should prolly be removed -- air) // platform prior to wxWidgets .. it should prolly be removed -- air)
namespace HostSys namespace HostSys
{ {
void *MmapReserve(uptr base, size_t size); void* MmapReserve(uptr base, size_t size);
bool MmapCommit(uptr base, size_t size, const PageProtectionMode &mode); bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
void MmapReset(uptr base, size_t size); void MmapReset(uptr base, size_t size);
void *MmapReservePtr(void *base, size_t size); void* MmapReservePtr(void* base, size_t size);
bool MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode); bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
void MmapResetPtr(void *base, size_t size); void MmapResetPtr(void* base, size_t size);
// Maps a block of memory for use as a recompiled code buffer. // Maps a block of memory for use as a recompiled code buffer.
// Returns NULL on allocation failure. // Returns NULL on allocation failure.
extern void *Mmap(uptr base, size_t size); extern void* Mmap(uptr base, size_t size);
// Unmaps a block allocated by SysMmap // Unmaps a block allocated by SysMmap
extern void Munmap(uptr base, size_t size); extern void Munmap(uptr base, size_t size);
extern void MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode); extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
extern void Munmap(void *base, size_t size); extern void Munmap(void* base, size_t size);
template <uint size> template <uint size>
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode &mode) void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode& mode)
{ {
MemProtect(arr, size, mode); MemProtect(arr, size, mode);
} }
} } // namespace HostSys
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it. // Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
#define SafeSysMunmap(ptr, size) \ #define SafeSysMunmap(ptr, size) \
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL)) ((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
extern void InitCPUTicks(); extern void InitCPUTicks();
extern u64 GetTickFrequency(); extern u64 GetTickFrequency();

View File

@ -23,393 +23,404 @@ const wxRect wxDefaultRect(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDef
wxDirName g_fullBaseDirName = wxDirName(L""); wxDirName g_fullBaseDirName = wxDirName(L"");
void SetFullBaseDir(wxDirName appRoot) void SetFullBaseDir(wxDirName appRoot)
{ {
g_fullBaseDirName = appRoot; g_fullBaseDirName = appRoot;
} }
static int _calcEnumLength(const wxChar *const *enumArray) static int _calcEnumLength(const wxChar* const* enumArray)
{ {
int cnt = 0; int cnt = 0;
while (*enumArray != NULL) { while (*enumArray != NULL)
enumArray++; {
cnt++; enumArray++;
} cnt++;
}
return cnt; return cnt;
} }
ScopedIniGroup::ScopedIniGroup(IniInterface &mommy, const wxString &group) ScopedIniGroup::ScopedIniGroup(IniInterface& mommy, const wxString& group)
: m_mom(mommy) : m_mom(mommy)
{ {
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup."); pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
m_mom.SetPath(group); m_mom.SetPath(group);
} }
ScopedIniGroup::~ScopedIniGroup() ScopedIniGroup::~ScopedIniGroup()
{ {
m_mom.SetPath(L".."); m_mom.SetPath(L"..");
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// IniInterface (implementations) // IniInterface (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
IniInterface::IniInterface(wxConfigBase &config) IniInterface::IniInterface(wxConfigBase& config)
{ {
m_Config = &config; m_Config = &config;
} }
IniInterface::IniInterface(wxConfigBase *config) IniInterface::IniInterface(wxConfigBase* config)
{ {
m_Config = config; m_Config = config;
} }
IniInterface::IniInterface() IniInterface::IniInterface()
{ {
m_Config = wxConfigBase::Get(false); m_Config = wxConfigBase::Get(false);
} }
IniInterface::~IniInterface() IniInterface::~IniInterface()
{ {
Flush(); Flush();
} }
void IniInterface::SetPath(const wxString &path) void IniInterface::SetPath(const wxString& path)
{ {
if (m_Config) if (m_Config)
m_Config->SetPath(path); m_Config->SetPath(path);
} }
void IniInterface::Flush() void IniInterface::Flush()
{ {
if (m_Config) if (m_Config)
m_Config->Flush(); m_Config->Flush();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// IniLoader (implementations) // IniLoader (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
IniLoader::IniLoader(wxConfigBase &config) IniLoader::IniLoader(wxConfigBase& config)
: IniInterface(config) : IniInterface(config)
{ {
} }
IniLoader::IniLoader(wxConfigBase *config) IniLoader::IniLoader(wxConfigBase* config)
: IniInterface(config) : IniInterface(config)
{ {
} }
IniLoader::IniLoader() IniLoader::IniLoader()
: IniInterface() : IniInterface()
{ {
} }
void IniLoader::Entry(const wxString &var, wxString &value, const wxString defvalue) void IniLoader::Entry(const wxString& var, wxString& value, const wxString defvalue)
{ {
if (m_Config) if (m_Config)
m_Config->Read(var, &value, defvalue); m_Config->Read(var, &value, defvalue);
else else
value = defvalue; value = defvalue;
} }
void IniLoader::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative) void IniLoader::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
{ {
wxString dest; wxString dest;
if (m_Config) if (m_Config)
m_Config->Read(var, &dest, wxEmptyString); m_Config->Read(var, &dest, wxEmptyString);
if (dest.IsEmpty()) if (dest.IsEmpty())
value = defvalue; value = defvalue;
else { else
value = dest; {
if (isAllowRelative) value = dest;
value = g_fullBaseDirName + value; if (isAllowRelative)
value = g_fullBaseDirName + value;
if (value.IsAbsolute()) if (value.IsAbsolute())
value.Normalize(); value.Normalize();
} }
} }
void IniLoader::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative) void IniLoader::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
{ {
wxString dest(defvalue.GetFullPath()); wxString dest(defvalue.GetFullPath());
if (m_Config) if (m_Config)
m_Config->Read(var, &dest, defvalue.GetFullPath()); m_Config->Read(var, &dest, defvalue.GetFullPath());
value = dest; value = dest;
if (isAllowRelative) if (isAllowRelative)
value = g_fullBaseDirName + value; value = g_fullBaseDirName + value;
if (value.IsAbsolute()) if (value.IsAbsolute())
value.Normalize(); value.Normalize();
if (value.HasVolume()) if (value.HasVolume())
value.SetVolume(value.GetVolume().Upper()); value.SetVolume(value.GetVolume().Upper());
} }
void IniLoader::Entry(const wxString &var, int &value, const int defvalue) void IniLoader::Entry(const wxString& var, int& value, const int defvalue)
{ {
if (m_Config) if (m_Config)
m_Config->Read(var, &value, defvalue); m_Config->Read(var, &value, defvalue);
else else
value = defvalue; value = defvalue;
} }
void IniLoader::Entry(const wxString &var, uint &value, const uint defvalue) void IniLoader::Entry(const wxString& var, uint& value, const uint defvalue)
{ {
if (m_Config) if (m_Config)
m_Config->Read(var, (int *)&value, (int)defvalue); m_Config->Read(var, (int*)&value, (int)defvalue);
else else
value = defvalue; value = defvalue;
} }
void IniLoader::Entry(const wxString &var, bool &value, const bool defvalue) void IniLoader::Entry(const wxString& var, bool& value, const bool defvalue)
{ {
// TODO : Stricter value checking on enabled/disabled? // TODO : Stricter value checking on enabled/disabled?
wxString dest; wxString dest;
if(defvalue) if (defvalue)
dest = wxString("enabled"); dest = wxString("enabled");
else else
dest = wxString("disabled"); dest = wxString("disabled");
if (m_Config) if (m_Config)
m_Config->Read(var, &dest, dest); m_Config->Read(var, &dest, dest);
value = (dest == L"enabled") || (dest == L"1"); value = (dest == L"enabled") || (dest == L"1");
} }
bool IniLoader::EntryBitBool(const wxString &var, bool value, const bool defvalue) bool IniLoader::EntryBitBool(const wxString& var, bool value, const bool defvalue)
{ {
// Note: 'value' param is used by inisaver only. // Note: 'value' param is used by inisaver only.
bool result; bool result;
Entry(var, result, defvalue); Entry(var, result, defvalue);
return result; return result;
} }
int IniLoader::EntryBitfield(const wxString &var, int value, const int defvalue) int IniLoader::EntryBitfield(const wxString& var, int value, const int defvalue)
{ {
int result; int result;
Entry(var, result, defvalue); Entry(var, result, defvalue);
return result; return result;
} }
void IniLoader::Entry(const wxString &var, double& value, const double defvalue) void IniLoader::Entry(const wxString& var, double& value, const double defvalue)
{ {
auto readval = wxString::FromDouble(value); auto readval = wxString::FromDouble(value);
if (m_Config) if (m_Config)
m_Config->Read(var, &readval); m_Config->Read(var, &readval);
if (!readval.ToDouble(&value)) if (!readval.ToDouble(&value))
value = 0.0; value = 0.0;
} }
void IniLoader::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue) void IniLoader::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
{ {
if (!m_Config) { if (!m_Config)
value = defvalue; {
return; value = defvalue;
} return;
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue); }
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
} }
void IniLoader::Entry(const wxString &var, wxSize &value, const wxSize defvalue) void IniLoader::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
{ {
if (!m_Config) { if (!m_Config)
value = defvalue; {
return; value = defvalue;
} return;
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue); }
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
} }
void IniLoader::Entry(const wxString &var, wxRect &value, const wxRect defvalue) void IniLoader::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
{ {
if (!m_Config) { if (!m_Config)
value = defvalue; {
return; value = defvalue;
} return;
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue); }
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
} }
void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue) void IniLoader::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
{ {
// Confirm default value sanity... // Confirm default value sanity...
const int cnt = _calcEnumLength(enumArray); const int cnt = _calcEnumLength(enumArray);
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) { if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt))
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating."); {
defvalue = cnt - 1; Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
} defvalue = cnt - 1;
}
// Sanity confirmed, proceed with craziness! // Sanity confirmed, proceed with craziness!
if (!m_Config) { if (!m_Config)
value = defvalue; {
return; value = defvalue;
} return;
}
wxString retval; wxString retval;
m_Config->Read(var, &retval, enumArray[defvalue]); m_Config->Read(var, &retval, enumArray[defvalue]);
int i = 0; int i = 0;
while (enumArray[i] != NULL && (retval != enumArray[i])) while (enumArray[i] != NULL && (retval != enumArray[i]))
i++; i++;
if (enumArray[i] == NULL) { if (enumArray[i] == NULL)
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.", {
WX_STR(retval), WX_STR(var), enumArray[defvalue]); Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
value = defvalue; WX_STR(retval), WX_STR(var), enumArray[defvalue]);
} else value = defvalue;
value = i; }
else
value = i;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// IniSaver (implementations) // IniSaver (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
IniSaver::IniSaver(wxConfigBase &config) IniSaver::IniSaver(wxConfigBase& config)
: IniInterface(config) : IniInterface(config)
{ {
} }
IniSaver::IniSaver(wxConfigBase *config) IniSaver::IniSaver(wxConfigBase* config)
: IniInterface(config) : IniInterface(config)
{ {
} }
IniSaver::IniSaver() IniSaver::IniSaver()
: IniInterface() : IniInterface()
{ {
} }
void IniSaver::Entry(const wxString &var, wxString &value, const wxString defvalue) void IniSaver::Entry(const wxString& var, wxString& value, const wxString defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, value); m_Config->Write(var, value);
} }
void IniSaver::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative) void IniSaver::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
{ {
if (!m_Config) if (!m_Config)
return; return;
wxDirName res(value); wxDirName res(value);
if (res.IsAbsolute()) if (res.IsAbsolute())
res.Normalize(); res.Normalize();
if (isAllowRelative) if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString()); res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
/*if( value == defvalue ) /*if( value == defvalue )
m_Config->Write( var, wxString() ); m_Config->Write( var, wxString() );
else*/ else*/
m_Config->Write(var, res.ToString()); m_Config->Write(var, res.ToString());
} }
void IniSaver::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative) void IniSaver::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
{ {
if (!m_Config) if (!m_Config)
return; return;
wxFileName res(value); wxFileName res(value);
if (res.IsAbsolute()) if (res.IsAbsolute())
res.Normalize(); res.Normalize();
if (isAllowRelative) if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString()); res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
m_Config->Write(var, res.GetFullPath()); m_Config->Write(var, res.GetFullPath());
} }
void IniSaver::Entry(const wxString &var, int &value, const int defvalue) void IniSaver::Entry(const wxString& var, int& value, const int defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, value); m_Config->Write(var, value);
} }
void IniSaver::Entry(const wxString &var, uint &value, const uint defvalue) void IniSaver::Entry(const wxString& var, uint& value, const uint defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, (int)value); m_Config->Write(var, (int)value);
} }
void IniSaver::Entry(const wxString &var, bool &value, const bool defvalue) void IniSaver::Entry(const wxString& var, bool& value, const bool defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, value ? L"enabled" : L"disabled"); m_Config->Write(var, value ? L"enabled" : L"disabled");
} }
bool IniSaver::EntryBitBool(const wxString &var, bool value, const bool defvalue) bool IniSaver::EntryBitBool(const wxString& var, bool value, const bool defvalue)
{ {
if (m_Config) if (m_Config)
m_Config->Write(var, value ? L"enabled" : L"disabled"); m_Config->Write(var, value ? L"enabled" : L"disabled");
return value; return value;
} }
int IniSaver::EntryBitfield(const wxString &var, int value, const int defvalue) int IniSaver::EntryBitfield(const wxString& var, int value, const int defvalue)
{ {
if (m_Config) if (m_Config)
m_Config->Write(var, value); m_Config->Write(var, value);
return value; return value;
} }
void IniSaver::Entry(const wxString &var, double &value, const double defvalue) void IniSaver::Entry(const wxString& var, double& value, const double defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, wxString::FromDouble(value)); m_Config->Write(var, wxString::FromDouble(value));
} }
void IniSaver::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue) void IniSaver::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, ToString(value)); m_Config->Write(var, ToString(value));
} }
void IniSaver::Entry(const wxString &var, wxSize &value, const wxSize defvalue) void IniSaver::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, ToString(value)); m_Config->Write(var, ToString(value));
} }
void IniSaver::Entry(const wxString &var, wxRect &value, const wxRect defvalue) void IniSaver::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
{ {
if (!m_Config) if (!m_Config)
return; return;
m_Config->Write(var, ToString(value)); m_Config->Write(var, ToString(value));
} }
void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue) void IniSaver::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
{ {
const int cnt = _calcEnumLength(enumArray); const int cnt = _calcEnumLength(enumArray);
// Confirm default value sanity... // Confirm default value sanity...
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt)) { if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt))
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating."); {
defvalue = cnt - 1; Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
} defvalue = cnt - 1;
}
if (!m_Config) if (!m_Config)
return; return;
if (value >= cnt) { if (value >= cnt)
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var)); {
Console.Indent().Warning( Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
L"Illegal Value: %d\n" Console.Indent().Warning(
L"Using Default: %d (%s)\n", L"Illegal Value: %d\n"
value, defvalue, enumArray[defvalue]); L"Using Default: %d (%s)\n",
value, defvalue, enumArray[defvalue]);
// Cause a debug assertion, since this is a fully recoverable error. // Cause a debug assertion, since this is a fully recoverable error.
pxAssert(value < cnt); pxAssert(value < cnt);
value = defvalue; value = defvalue;
} }
m_Config->Write(var, enumArray[value]); m_Config->Write(var, enumArray[value]);
} }

View File

@ -31,58 +31,58 @@
class IniInterface class IniInterface
{ {
protected: protected:
wxConfigBase *m_Config; wxConfigBase* m_Config;
public: public:
virtual ~IniInterface(); virtual ~IniInterface();
explicit IniInterface(); explicit IniInterface();
explicit IniInterface(wxConfigBase &config); explicit IniInterface(wxConfigBase& config);
explicit IniInterface(wxConfigBase *config); explicit IniInterface(wxConfigBase* config);
void SetPath(const wxString &path); void SetPath(const wxString& path);
void Flush(); void Flush();
wxConfigBase &GetConfig() wxConfigBase& GetConfig()
{ {
pxAssert(m_Config); pxAssert(m_Config);
return *m_Config; return *m_Config;
} }
bool IsOk() const { return m_Config != NULL; } bool IsOk() const { return m_Config != NULL; }
virtual bool IsLoading() const = 0; virtual bool IsLoading() const = 0;
bool IsSaving() const { return !IsLoading(); } bool IsSaving() const { return !IsLoading(); }
virtual void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString()) = 0; virtual void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString()) = 0;
virtual void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0; virtual void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0;
virtual void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0; virtual void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0;
virtual void Entry(const wxString &var, int &value, const int defvalue = 0) = 0; virtual void Entry(const wxString& var, int& value, const int defvalue = 0) = 0;
virtual void Entry(const wxString &var, uint &value, const uint defvalue = 0) = 0; virtual void Entry(const wxString& var, uint& value, const uint defvalue = 0) = 0;
virtual void Entry(const wxString &var, bool &value, const bool defvalue = false) = 0; virtual void Entry(const wxString& var, bool& value, const bool defvalue = false) = 0;
// This special form of Entry is provided for bitfields, which cannot be passed by reference. // This special form of Entry is provided for bitfields, which cannot be passed by reference.
virtual bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false) = 0; virtual bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false) = 0;
virtual int EntryBitfield(const wxString &var, int value, const int defvalue = 0) = 0; virtual int EntryBitfield(const wxString& var, int value, const int defvalue = 0) = 0;
virtual void Entry(const wxString &var, double& value, const double defvalue = 0.0) = 0; virtual void Entry(const wxString& var, double& value, const double defvalue = 0.0) = 0;
virtual void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition) = 0; virtual void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition) = 0;
virtual void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize) = 0; virtual void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize) = 0;
virtual void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect) = 0; virtual void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect) = 0;
template <typename T> template <typename T>
void EnumEntry(const wxString &var, T &value, const wxChar *const *enumArray = NULL, const T defvalue = (T)0) void EnumEntry(const wxString& var, T& value, const wxChar* const* enumArray = NULL, const T defvalue = (T)0)
{ {
int tstore = (int)value; int tstore = (int)value;
auto defaultvalue = enum_cast(defvalue); auto defaultvalue = enum_cast(defvalue);
if (enumArray == NULL) if (enumArray == NULL)
Entry(var, tstore, defaultvalue); Entry(var, tstore, defaultvalue);
else else
_EnumEntry(var, tstore, enumArray, defaultvalue); _EnumEntry(var, tstore, enumArray, defaultvalue);
value = (T)tstore; value = (T)tstore;
} }
protected: protected:
virtual void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue) = 0; virtual void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue) = 0;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -91,11 +91,11 @@ protected:
class ScopedIniGroup class ScopedIniGroup
{ {
protected: protected:
IniInterface &m_mom; IniInterface& m_mom;
public: public:
ScopedIniGroup(IniInterface &mommy, const wxString &group); ScopedIniGroup(IniInterface& mommy, const wxString& group);
virtual ~ScopedIniGroup(); virtual ~ScopedIniGroup();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -109,31 +109,31 @@ public:
class IniLoader : public IniInterface class IniLoader : public IniInterface
{ {
public: public:
virtual ~IniLoader() = default; virtual ~IniLoader() = default;
explicit IniLoader(); explicit IniLoader();
explicit IniLoader(wxConfigBase &config); explicit IniLoader(wxConfigBase& config);
explicit IniLoader(wxConfigBase *config); explicit IniLoader(wxConfigBase* config);
bool IsLoading() const { return true; } bool IsLoading() const { return true; }
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxEmptyString); void Entry(const wxString& var, wxString& value, const wxString defvalue = wxEmptyString);
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false); void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false); void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
void Entry(const wxString &var, int &value, const int defvalue = 0); void Entry(const wxString& var, int& value, const int defvalue = 0);
void Entry(const wxString &var, uint &value, const uint defvalue = 0); void Entry(const wxString& var, uint& value, const uint defvalue = 0);
void Entry(const wxString &var, bool &value, const bool defvalue = false); void Entry(const wxString& var, bool& value, const bool defvalue = false);
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false); bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
int EntryBitfield(const wxString &var, int value, const int defvalue = 0); int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
void Entry(const wxString &var, double& value, const double defvalue = 0.0) override; void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition); void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize); void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect); void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
protected: protected:
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue); void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -147,31 +147,31 @@ protected:
class IniSaver : public IniInterface class IniSaver : public IniInterface
{ {
public: public:
virtual ~IniSaver() = default; virtual ~IniSaver() = default;
explicit IniSaver(); explicit IniSaver();
explicit IniSaver(wxConfigBase &config); explicit IniSaver(wxConfigBase& config);
explicit IniSaver(wxConfigBase *config); explicit IniSaver(wxConfigBase* config);
bool IsLoading() const { return false; } bool IsLoading() const { return false; }
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString()); void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString());
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false); void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false); void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
void Entry(const wxString &var, int &value, const int defvalue = 0); void Entry(const wxString& var, int& value, const int defvalue = 0);
void Entry(const wxString &var, uint &value, const uint defvalue = 0); void Entry(const wxString& var, uint& value, const uint defvalue = 0);
void Entry(const wxString &var, bool &value, const bool defvalue = false); void Entry(const wxString& var, bool& value, const bool defvalue = false);
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false); bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
int EntryBitfield(const wxString &var, int value, const int defvalue = 0); int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
void Entry(const wxString &var, double &value, const double defvalue = 0.0) override; void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition); void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize); void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect); void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
protected: protected:
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue); void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -33,195 +33,198 @@ extern void SignalExit(int sig);
static const uptr m_pagemask = getpagesize() - 1; static const uptr m_pagemask = getpagesize() - 1;
// Linux implementation of SIGSEGV handler. Bind it using sigaction(). // Linux implementation of SIGSEGV handler. Bind it using sigaction().
static void SysPageFaultSignalFilter(int signal, siginfo_t *siginfo, void *) static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void*)
{ {
// [TODO] : Add a thread ID filter to the Linux Signal handler here. // [TODO] : Add a thread ID filter to the Linux Signal handler here.
// Rationale: On windows, the __try/__except model allows per-thread specific behavior // Rationale: On windows, the __try/__except model allows per-thread specific behavior
// for page fault handling. On linux, there is a single signal handler for the whole // for page fault handling. On linux, there is a single signal handler for the whole
// process, but the handler is executed by the thread that caused the exception. // process, but the handler is executed by the thread that caused the exception.
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done // Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
// from the context of the current thread and stackframe. So long as the thread is not // from the context of the current thread and stackframe. So long as the thread is not
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should // the main/ui thread, use of the px assertion system should be safe. Use of stdio should
// be safe even on the main thread. // be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous // (in other words, stdio limitations only really apply to process-level asynchronous
// signals) // signals)
// Note: Use of stdio functions isn't safe here. Avoid console logs, // Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful. // assertions, file logs, or just about anything else useful.
// Note: This signal can be accessed by the EE or MTVU thread // Note: This signal can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information // Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better... // so for now we lock this exception code unless someone can fix this better...
Threading::ScopedLock lock(PageFault_Mutex); Threading::ScopedLock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask)); Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
// resumes execution right where we left off (re-executes instruction that // resumes execution right where we left off (re-executes instruction that
// caused the SIGSEGV). // caused the SIGSEGV).
if (Source_PageFault->WasHandled()) if (Source_PageFault->WasHandled())
return; return;
if (!wxThread::IsMain()) { if (!wxThread::IsMain())
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr)); {
} pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
}
// Bad mojo! Completely invalid address. // Bad mojo! Completely invalid address.
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL. // Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
pxTrap(); pxTrap();
if (!IsDebugBuild) if (!IsDebugBuild)
raise(SIGKILL); raise(SIGKILL);
} }
void _platform_InstallSignalHandler() void _platform_InstallSignalHandler()
{ {
Console.WriteLn("Installing POSIX SIGSEGV handler..."); Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa; struct sigaction sa;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO; sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter; sa.sa_sigaction = SysPageFaultSignalFilter;
#ifdef __APPLE__ #ifdef __APPLE__
// MacOS uses SIGBUS for memory permission violations // MacOS uses SIGBUS for memory permission violations
sigaction(SIGBUS, &sa, NULL); sigaction(SIGBUS, &sa, NULL);
#else #else
sigaction(SIGSEGV, &sa, NULL); sigaction(SIGSEGV, &sa, NULL);
#endif #endif
} }
static __ri void PageSizeAssertionTest(size_t size) static __ri void PageSizeAssertionTest(size_t size)
{ {
pxAssertMsg((__pagesize == getpagesize()), pxsFmt( pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t" "Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)", L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
getpagesize(), getpagesize(), __pagesize, __pagesize)); getpagesize(), getpagesize(), __pagesize, __pagesize));
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt( pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
L"Memory block size must be a multiple of the target platform's page size.\n" L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)", L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
__pagesize, __pagesize, size, size)); __pagesize, __pagesize, size, size));
} }
// returns FALSE if the mprotect call fails with an ENOMEM. // returns FALSE if the mprotect call fails with an ENOMEM.
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object // Raises assertions on other types of POSIX errors (since those typically reflect invalid object
// or memory states). // or memory states).
static bool _memprotect(void *baseaddr, size_t size, const PageProtectionMode &mode) static bool _memprotect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{ {
PageSizeAssertionTest(size); PageSizeAssertionTest(size);
uint lnxmode = 0; uint lnxmode = 0;
if (mode.CanWrite()) if (mode.CanWrite())
lnxmode |= PROT_WRITE; lnxmode |= PROT_WRITE;
if (mode.CanRead()) if (mode.CanRead())
lnxmode |= PROT_READ; lnxmode |= PROT_READ;
if (mode.CanExecute()) if (mode.CanExecute())
lnxmode |= PROT_EXEC | PROT_READ; lnxmode |= PROT_EXEC | PROT_READ;
const int result = mprotect(baseaddr, size, lnxmode); const int result = mprotect(baseaddr, size, lnxmode);
if (result == 0) if (result == 0)
return true; return true;
switch (errno) { switch (errno)
case EINVAL: {
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)", case EINVAL:
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString()))); pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
break; baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break;
case EACCES: case EACCES:
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)", pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString()))); baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break; break;
case ENOMEM: case ENOMEM:
// caller handles assertion or exception, or whatever. // caller handles assertion or exception, or whatever.
break; break;
} }
return false; return false;
} }
void *HostSys::MmapReservePtr(void *base, size_t size) void* HostSys::MmapReservePtr(void* base, size_t size)
{ {
PageSizeAssertionTest(size); PageSizeAssertionTest(size);
// On linux a reserve-without-commit is performed by using mmap on a read-only // On linux a reserve-without-commit is performed by using mmap on a read-only
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping // or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
// is completely inaccessible, the OS will simply reserve it and will not put it // is completely inaccessible, the OS will simply reserve it and will not put it
// against the commit table. // against the commit table.
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
} }
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode) bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
{ {
// In linux, reserved memory is automatically committed when its permissions are // In linux, reserved memory is automatically committed when its permissions are
// changed to something other than PROT_NONE. If the user is committing memory // changed to something other than PROT_NONE. If the user is committing memory
// as PROT_NONE, then just ignore this call (memory will be committed automatically // as PROT_NONE, then just ignore this call (memory will be committed automatically
// later when the user changes permissions to something useful via calls to MemProtect). // later when the user changes permissions to something useful via calls to MemProtect).
if (mode.IsNone()) if (mode.IsNone())
return false; return false;
if (_memprotect(base, size, mode)) if (_memprotect(base, size, mode))
return true; return true;
if (!pxDoOutOfMemory) if (!pxDoOutOfMemory)
return false; return false;
pxDoOutOfMemory(size); pxDoOutOfMemory(size);
return _memprotect(base, size, mode); return _memprotect(base, size, mode);
} }
void HostSys::MmapResetPtr(void *base, size_t size) void HostSys::MmapResetPtr(void* base, size_t size)
{ {
PageSizeAssertionTest(size); PageSizeAssertionTest(size);
void *result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); void* result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
pxAssertRel((uptr)result == (uptr)base, pxsFmt( pxAssertRel((uptr)result == (uptr)base, pxsFmt(
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.", "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
base, (uptr)base + size)); base, (uptr)base + size));
} }
void *HostSys::MmapReserve(uptr base, size_t size) void* HostSys::MmapReserve(uptr base, size_t size)
{ {
return MmapReservePtr((void *)base, size); return MmapReservePtr((void*)base, size);
} }
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode) bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
{ {
return MmapCommitPtr((void *)base, size, mode); return MmapCommitPtr((void*)base, size, mode);
} }
void HostSys::MmapReset(uptr base, size_t size) void HostSys::MmapReset(uptr base, size_t size)
{ {
MmapResetPtr((void *)base, size); MmapResetPtr((void*)base, size);
} }
void *HostSys::Mmap(uptr base, size_t size) void* HostSys::Mmap(uptr base, size_t size)
{ {
PageSizeAssertionTest(size); PageSizeAssertionTest(size);
// MAP_ANONYMOUS - means we have no associated file handle (or device). // MAP_ANONYMOUS - means we have no associated file handle (or device).
return mmap((void *)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
} }
void HostSys::Munmap(uptr base, size_t size) void HostSys::Munmap(uptr base, size_t size)
{ {
if (!base) if (!base)
return; return;
munmap((void *)base, size); munmap((void*)base, size);
} }
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode) void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{ {
if (!_memprotect(baseaddr, size, mode)) { if (!_memprotect(baseaddr, size, mode))
throw Exception::OutOfMemory(L"MemProtect") {
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", throw Exception::OutOfMemory(L"MemProtect")
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString()))); .SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
} baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
}
} }
#endif #endif

View File

@ -39,21 +39,21 @@
__forceinline void Threading::Sleep(int ms) __forceinline void Threading::Sleep(int ms)
{ {
usleep(1000 * ms); usleep(1000 * ms);
} }
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption. // improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait() __forceinline void Threading::SpinWait()
{ {
// If this doesn't compile you can just comment it out (it only serves as a // If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required). // performance hint and isn't required).
__asm__("pause"); __asm__("pause");
} }
__forceinline void Threading::EnableHiresScheduler() __forceinline void Threading::EnableHiresScheduler()
{ {
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful) // Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
} }
__forceinline void Threading::DisableHiresScheduler() __forceinline void Threading::DisableHiresScheduler()
@ -63,69 +63,72 @@ __forceinline void Threading::DisableHiresScheduler()
// Unit of time of GetThreadCpuTime/GetCpuTime // Unit of time of GetThreadCpuTime/GetCpuTime
u64 Threading::GetThreadTicksPerSecond() u64 Threading::GetThreadTicksPerSecond()
{ {
return 1000000; return 1000000;
} }
// Helper function to get either either the current cpu usage // Helper function to get either either the current cpu usage
// in called thread or in id thread // in called thread or in id thread
static u64 get_thread_time(uptr id = 0) static u64 get_thread_time(uptr id = 0)
{ {
clockid_t cid; clockid_t cid;
if (id) { if (id)
int err = pthread_getcpuclockid((pthread_t)id, &cid); {
if (err) int err = pthread_getcpuclockid((pthread_t)id, &cid);
return 0; if (err)
} else { return 0;
cid = CLOCK_THREAD_CPUTIME_ID; }
} else
{
cid = CLOCK_THREAD_CPUTIME_ID;
}
struct timespec ts; struct timespec ts;
int err = clock_gettime(cid, &ts); int err = clock_gettime(cid, &ts);
if (err) if (err)
return 0; return 0;
return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3; return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3;
} }
// Returns the current timestamp (not relative to a real world clock) // Returns the current timestamp (not relative to a real world clock)
u64 Threading::GetThreadCpuTime() u64 Threading::GetThreadCpuTime()
{ {
return get_thread_time(); return get_thread_time();
} }
u64 Threading::pxThread::GetCpuTime() const u64 Threading::pxThread::GetCpuTime() const
{ {
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or // Get the cpu time for the thread belonging to this object. Use m_native_id and/or
// m_native_handle to implement it. Return value should be a measure of total time the // m_native_handle to implement it. Return value should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(), // thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort). // which typically would be an OS-provided scalar or some sort).
if (!m_native_id) if (!m_native_id)
return 0; return 0;
return get_thread_time(m_native_id); return get_thread_time(m_native_id);
} }
void Threading::pxThread::_platform_specific_OnStartInThread() void Threading::pxThread::_platform_specific_OnStartInThread()
{ {
// Obtain linux-specific thread IDs or Handles here, which can be used to query // Obtain linux-specific thread IDs or Handles here, which can be used to query
// kernel scheduler performance information. // kernel scheduler performance information.
m_native_id = (uptr)pthread_self(); m_native_id = (uptr)pthread_self();
} }
void Threading::pxThread::_platform_specific_OnCleanupInThread() void Threading::pxThread::_platform_specific_OnCleanupInThread()
{ {
// Cleanup handles here, which were opened above. // Cleanup handles here, which were opened above.
} }
void Threading::SetNameOfCurrentThread(const char *name) void Threading::SetNameOfCurrentThread(const char* name)
{ {
#if defined(__linux__) #if defined(__linux__)
// Extract of manpage: "The name can be up to 16 bytes long, and should be // Extract of manpage: "The name can be up to 16 bytes long, and should be
// null-terminated if it contains fewer bytes." // null-terminated if it contains fewer bytes."
prctl(PR_SET_NAME, name, 0, 0, 0); prctl(PR_SET_NAME, name, 0, 0, 0);
#elif defined(__unix__) #elif defined(__unix__)
pthread_set_name_np(pthread_self(), name); pthread_set_name_np(pthread_self(), name);
#endif #endif
} }

View File

@ -22,20 +22,20 @@
// On GCC >= 4.7, this is equivalent to __builtin_clrsb(n); // On GCC >= 4.7, this is equivalent to __builtin_clrsb(n);
inline u32 count_leading_sign_bits(s32 n) inline u32 count_leading_sign_bits(s32 n)
{ {
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero. // If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
if (n < 0) if (n < 0)
n = ~n; n = ~n;
// If BSR is used directly, it would have an undefined value for 0. // If BSR is used directly, it would have an undefined value for 0.
if (n == 0) if (n == 0)
return 32; return 32;
// Perform our count leading zero. // Perform our count leading zero.
#ifdef _MSC_VER #ifdef _MSC_VER
unsigned long ret; unsigned long ret;
_BitScanReverse(&ret, n); _BitScanReverse(&ret, n);
return 31 - (u32)ret; return 31 - (u32)ret;
#else #else
return __builtin_clz(n); return __builtin_clz(n);
#endif #endif
} }

View File

@ -22,7 +22,7 @@
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and // For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
// other implementations. So for this combination only, prefer memcmp_mmx // other implementations. So for this combination only, prefer memcmp_mmx
#if defined(_MSC_VER) && !defined(_M_X86_64) #if defined(_MSC_VER) && !defined(_M_X86_64)
extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize); extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize);
#else #else
#define memcmp_mmx memcmp #define memcmp_mmx memcmp
#endif #endif
@ -31,14 +31,14 @@ extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize);
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically // Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
// for you! // for you!
template <typename T> template <typename T>
static __fi void memzero(T &object) static __fi void memzero(T& object)
{ {
memset(&object, 0, sizeof(T)); memset(&object, 0, sizeof(T));
} }
// This method clears an object with the given 8 bit value. // This method clears an object with the given 8 bit value.
template <u8 data, typename T> template <u8 data, typename T>
static __fi void memset8(T &object) static __fi void memset8(T& object)
{ {
memset(&object, data, sizeof(T)); memset(&object, data, sizeof(T));
} }

View File

@ -18,74 +18,78 @@
#include <xmmintrin.h> #include <xmmintrin.h>
template <u8 data> template <u8 data>
__noinline void memset_sse_a(void *dest, const size_t size) __noinline void memset_sse_a(void* dest, const size_t size)
{ {
const uint MZFqwc = size / 16; const uint MZFqwc = size / 16;
pxAssert((size & 0xf) == 0); pxAssert((size & 0xf) == 0);
__m128 srcreg; __m128 srcreg;
if (data != 0) { if (data != 0)
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data}; {
srcreg = _mm_loadh_pi(_mm_load_ps((float *)loadval), (__m64 *)loadval); static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
} else srcreg = _mm_loadh_pi(_mm_load_ps((float*)loadval), (__m64*)loadval);
srcreg = _mm_setzero_ps(); }
else
srcreg = _mm_setzero_ps();
float(*destxmm)[4] = (float(*)[4])dest; float(*destxmm)[4] = (float(*)[4])dest;
switch (MZFqwc & 0x07) { switch (MZFqwc & 0x07)
case 0x07: {
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg); case 0x07:
// Fall through _mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
case 0x06: // Fall through
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg); case 0x06:
// Fall through _mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
case 0x05: // Fall through
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg); case 0x05:
// Fall through _mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
case 0x04: // Fall through
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg); case 0x04:
// Fall through _mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
case 0x03: // Fall through
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg); case 0x03:
// Fall through _mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
case 0x02: // Fall through
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg); case 0x02:
// Fall through _mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
case 0x01: // Fall through
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg); case 0x01:
// Fall through _mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
} // Fall through
}
destxmm += (MZFqwc & 0x07); destxmm += (MZFqwc & 0x07);
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8) { for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8)
_mm_store_ps(&destxmm[0][0], srcreg); {
_mm_store_ps(&destxmm[1][0], srcreg); _mm_store_ps(&destxmm[0][0], srcreg);
_mm_store_ps(&destxmm[2][0], srcreg); _mm_store_ps(&destxmm[1][0], srcreg);
_mm_store_ps(&destxmm[3][0], srcreg); _mm_store_ps(&destxmm[2][0], srcreg);
_mm_store_ps(&destxmm[4][0], srcreg); _mm_store_ps(&destxmm[3][0], srcreg);
_mm_store_ps(&destxmm[5][0], srcreg); _mm_store_ps(&destxmm[4][0], srcreg);
_mm_store_ps(&destxmm[6][0], srcreg); _mm_store_ps(&destxmm[5][0], srcreg);
_mm_store_ps(&destxmm[7][0], srcreg); _mm_store_ps(&destxmm[6][0], srcreg);
} _mm_store_ps(&destxmm[7][0], srcreg);
}
}; };
static __fi void memzero_sse_a(void *dest, const size_t size) static __fi void memzero_sse_a(void* dest, const size_t size)
{ {
memset_sse_a<0>(dest, size); memset_sse_a<0>(dest, size);
} }
template <u8 data, typename T> template <u8 data, typename T>
__noinline void memset_sse_a(T &dest) __noinline void memset_sse_a(T& dest)
{ {
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset"); static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
memset_sse_a<data>(&dest, sizeof(dest)); memset_sse_a<data>(&dest, sizeof(dest));
} }
template <typename T> template <typename T>
void memzero_sse_a(T &dest) void memzero_sse_a(T& dest)
{ {
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset"); static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
memset_sse_a<0>(&dest, sizeof(dest)); memset_sse_a<0>(&dest, sizeof(dest));
} }

View File

@ -20,9 +20,9 @@
namespace Threading namespace Threading
{ {
static std::atomic<int> _attr_refcount(0); static std::atomic<int> _attr_refcount(0);
static pthread_mutexattr_t _attr_recursive; static pthread_mutexattr_t _attr_recursive;
} } // namespace Threading
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Mutex Implementations // Mutex Implementations
@ -52,90 +52,94 @@ static pthread_mutexattr_t _attr_recursive;
// This is an implementation that emulates pthread_mutex_timedlock() via // This is an implementation that emulates pthread_mutex_timedlock() via
// pthread_mutex_trylock(). // pthread_mutex_trylock().
static int xpthread_mutex_timedlock( static int xpthread_mutex_timedlock(
pthread_mutex_t *mutex, pthread_mutex_t* mutex,
const struct timespec *abs_timeout) const struct timespec* abs_timeout)
{ {
int err = 0; int err = 0;
while ((err = pthread_mutex_trylock(mutex)) == EBUSY) { while ((err = pthread_mutex_trylock(mutex)) == EBUSY)
// check if the timeout has expired, gettimeofday() is implemented {
// efficiently (in userspace) on OSX // check if the timeout has expired, gettimeofday() is implemented
struct timeval now; // efficiently (in userspace) on OSX
gettimeofday(&now, NULL); struct timeval now;
if (now.tv_sec > abs_timeout->tv_sec gettimeofday(&now, NULL);
|| (now.tv_sec == abs_timeout->tv_sec if (now.tv_sec > abs_timeout->tv_sec || (now.tv_sec == abs_timeout->tv_sec && (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec))
&& (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec)) { {
return ETIMEDOUT; return ETIMEDOUT;
} }
// acquiring lock failed, sleep some // acquiring lock failed, sleep some
struct timespec ts; struct timespec ts;
ts.tv_sec = 0; ts.tv_sec = 0;
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS; ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
while (nanosleep(&ts, &ts) == -1); while (nanosleep(&ts, &ts) == -1)
} ;
}
return err; return err;
} }
#endif #endif
Threading::Mutex::Mutex() Threading::Mutex::Mutex()
{ {
pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutex, NULL);
} }
static wxTimeSpan def_detach_timeout(0, 0, 6, 0); static wxTimeSpan def_detach_timeout(0, 0, 6, 0);
void Threading::Mutex::Detach() void Threading::Mutex::Detach()
{ {
if (EBUSY != pthread_mutex_destroy(&m_mutex)) if (EBUSY != pthread_mutex_destroy(&m_mutex))
return; return;
if (IsRecursive()) { if (IsRecursive())
// Sanity check: Recursive locks could be held by our own thread, which would {
// be considered an assertion failure, but can also be handled gracefully. // Sanity check: Recursive locks could be held by our own thread, which would
// (note: if the mutex is locked recursively more than twice then this assert won't // be considered an assertion failure, but can also be handled gracefully.
// detect it) // (note: if the mutex is locked recursively more than twice then this assert won't
// detect it)
Release(); Release();
Release(); // in case of double recursion. Release(); // in case of double recursion.
int result = pthread_mutex_destroy(&m_mutex); int result = pthread_mutex_destroy(&m_mutex);
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!).")) if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
return; return;
} }
if (Wait(def_detach_timeout)) if (Wait(def_detach_timeout))
pthread_mutex_destroy(&m_mutex); pthread_mutex_destroy(&m_mutex);
else else
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock."); Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
} }
Threading::Mutex::~Mutex() Threading::Mutex::~Mutex()
{ {
try { try
Mutex::Detach(); {
} Mutex::Detach();
DESTRUCTOR_CATCHALL; }
DESTRUCTOR_CATCHALL;
} }
Threading::MutexRecursive::MutexRecursive() Threading::MutexRecursive::MutexRecursive()
: Mutex(false) : Mutex(false)
{ {
if (++_attr_refcount == 1) { if (++_attr_refcount == 1)
if (0 != pthread_mutexattr_init(&_attr_recursive)) {
throw Exception::OutOfMemory(L"Recursive mutexing attributes"); if (0 != pthread_mutexattr_init(&_attr_recursive))
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
} }
if (pthread_mutex_init(&m_mutex, &_attr_recursive)) if (pthread_mutex_init(&m_mutex, &_attr_recursive))
Console.Error("(Thread Log) Failed to initialize mutex."); Console.Error("(Thread Log) Failed to initialize mutex.");
} }
Threading::MutexRecursive::~MutexRecursive() Threading::MutexRecursive::~MutexRecursive()
{ {
if (--_attr_refcount == 0) if (--_attr_refcount == 0)
pthread_mutexattr_destroy(&_attr_recursive); pthread_mutexattr_destroy(&_attr_recursive);
} }
// This is a bit of a hackish function, which is technically unsafe, but can be useful for allowing // This is a bit of a hackish function, which is technically unsafe, but can be useful for allowing
@ -144,8 +148,8 @@ Threading::MutexRecursive::~MutexRecursive()
// the deeper meanings of the universe for eternity. // the deeper meanings of the universe for eternity.
void Threading::Mutex::Recreate() void Threading::Mutex::Recreate()
{ {
Detach(); Detach();
pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutex, NULL);
} }
// Returns: // Returns:
@ -153,11 +157,12 @@ void Threading::Mutex::Recreate()
// unlocked. // unlocked.
bool Threading::Mutex::RecreateIfLocked() bool Threading::Mutex::RecreateIfLocked()
{ {
if (!Wait(def_detach_timeout)) { if (!Wait(def_detach_timeout))
Recreate(); {
return true; Recreate();
} return true;
return false; }
return false;
} }
@ -167,25 +172,25 @@ bool Threading::Mutex::RecreateIfLocked()
// other than the main thread. // other than the main thread.
void Threading::Mutex::AcquireWithoutYield() void Threading::Mutex::AcquireWithoutYield()
{ {
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead."); pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
} }
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan &timeout) bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan& timeout)
{ {
wxDateTime megafail(wxDateTime::UNow() + timeout); wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000}; const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0; return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
} }
void Threading::Mutex::Release() void Threading::Mutex::Release()
{ {
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
} }
bool Threading::Mutex::TryAcquire() bool Threading::Mutex::TryAcquire()
{ {
return EBUSY != pthread_mutex_trylock(&m_mutex); return EBUSY != pthread_mutex_trylock(&m_mutex);
} }
// This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events // This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events
@ -194,45 +199,56 @@ bool Threading::Mutex::TryAcquire()
void Threading::Mutex::Acquire() void Threading::Mutex::Acquire()
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
pthread_mutex_lock(&m_mutex); {
} else if (_WaitGui_RecursionGuard(L"Mutex::Acquire")) { pthread_mutex_lock(&m_mutex);
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
pthread_mutex_lock(&m_mutex); else if (_WaitGui_RecursionGuard(L"Mutex::Acquire"))
} else { {
//ScopedBusyCursor hourglass( Cursor_KindaBusy ); ScopedBusyCursor hourglass(Cursor_ReallyBusy);
while (!AcquireWithoutYield(def_yieldgui_interval)) pthread_mutex_lock(&m_mutex);
YieldToMain(); }
} else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!AcquireWithoutYield(def_yieldgui_interval))
YieldToMain();
}
#else #else
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
#endif #endif
} }
bool Threading::Mutex::Acquire(const wxTimeSpan &timeout) bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
return AcquireWithoutYield(timeout); {
} else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire")) { return AcquireWithoutYield(timeout);
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
return AcquireWithoutYield(timeout); else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire"))
} else { {
//ScopedBusyCursor hourglass( Cursor_KindaBusy ); ScopedBusyCursor hourglass(Cursor_ReallyBusy);
wxTimeSpan countdown((timeout)); return AcquireWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do { do
if (AcquireWithoutYield(def_yieldgui_interval)) {
break; if (AcquireWithoutYield(def_yieldgui_interval))
YieldToMain(); break;
countdown -= def_yieldgui_interval; YieldToMain();
} while (countdown.GetMilliseconds() > 0); countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0; return countdown.GetMilliseconds() > 0;
} }
#else #else
return AcquireWithoutYield(); return AcquireWithoutYield();
#endif #endif
} }
@ -245,14 +261,14 @@ bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
// //
void Threading::Mutex::Wait() void Threading::Mutex::Wait()
{ {
Acquire(); Acquire();
Release(); Release();
} }
void Threading::Mutex::WaitWithoutYield() void Threading::Mutex::WaitWithoutYield()
{ {
AcquireWithoutYield(); AcquireWithoutYield();
Release(); Release();
} }
// Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked. // Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked.
@ -262,22 +278,24 @@ void Threading::Mutex::WaitWithoutYield()
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out // true if the mutex was freed and is in an unlocked state; or false if the wait timed out
// and the mutex is still locked by another thread. // and the mutex is still locked by another thread.
// //
bool Threading::Mutex::Wait(const wxTimeSpan &timeout) bool Threading::Mutex::Wait(const wxTimeSpan& timeout)
{ {
if (Acquire(timeout)) { if (Acquire(timeout))
Release(); {
return true; Release();
} return true;
return false; }
return false;
} }
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout) bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
{ {
if (AcquireWithoutYield(timeout)) { if (AcquireWithoutYield(timeout))
Release(); {
return true; Release();
} return true;
return false; }
return false;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -286,72 +304,72 @@ bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
Threading::ScopedLock::~ScopedLock() Threading::ScopedLock::~ScopedLock()
{ {
if (m_IsLocked && m_lock) if (m_IsLocked && m_lock)
m_lock->Release(); m_lock->Release();
} }
Threading::ScopedLock::ScopedLock(const Mutex *locker) Threading::ScopedLock::ScopedLock(const Mutex* locker)
{ {
m_IsLocked = false; m_IsLocked = false;
AssignAndLock(locker); AssignAndLock(locker);
} }
Threading::ScopedLock::ScopedLock(const Mutex &locker) Threading::ScopedLock::ScopedLock(const Mutex& locker)
{ {
m_IsLocked = false; m_IsLocked = false;
AssignAndLock(locker); AssignAndLock(locker);
} }
void Threading::ScopedLock::AssignAndLock(const Mutex &locker) void Threading::ScopedLock::AssignAndLock(const Mutex& locker)
{ {
AssignAndLock(&locker); AssignAndLock(&locker);
} }
void Threading::ScopedLock::AssignAndLock(const Mutex *locker) void Threading::ScopedLock::AssignAndLock(const Mutex* locker)
{ {
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo. pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
m_lock = const_cast<Mutex *>(locker); m_lock = const_cast<Mutex*>(locker);
if (!m_lock) if (!m_lock)
return; return;
m_IsLocked = true; m_IsLocked = true;
m_lock->Acquire(); m_lock->Acquire();
} }
void Threading::ScopedLock::Assign(const Mutex &locker) void Threading::ScopedLock::Assign(const Mutex& locker)
{ {
m_lock = const_cast<Mutex *>(&locker); m_lock = const_cast<Mutex*>(&locker);
} }
void Threading::ScopedLock::Assign(const Mutex *locker) void Threading::ScopedLock::Assign(const Mutex* locker)
{ {
m_lock = const_cast<Mutex *>(locker); m_lock = const_cast<Mutex*>(locker);
} }
// Provides manual unlocking of a scoped lock prior to object destruction. // Provides manual unlocking of a scoped lock prior to object destruction.
void Threading::ScopedLock::Release() void Threading::ScopedLock::Release()
{ {
if (!m_IsLocked) if (!m_IsLocked)
return; return;
m_IsLocked = false; m_IsLocked = false;
if (m_lock) if (m_lock)
m_lock->Release(); m_lock->Release();
} }
// provides manual locking of a scoped lock, to re-lock after a manual unlocking. // provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedLock::Acquire() void Threading::ScopedLock::Acquire()
{ {
if (m_IsLocked || !m_lock) if (m_IsLocked || !m_lock)
return; return;
m_lock->Acquire(); m_lock->Acquire();
m_IsLocked = true; m_IsLocked = true;
} }
Threading::ScopedLock::ScopedLock(const Mutex &locker, bool isTryLock) Threading::ScopedLock::ScopedLock(const Mutex& locker, bool isTryLock)
{ {
m_lock = const_cast<Mutex *>(&locker); m_lock = const_cast<Mutex*>(&locker);
if (!m_lock) if (!m_lock)
return; return;
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false; m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
} }

View File

@ -30,12 +30,12 @@
struct PageFaultInfo struct PageFaultInfo
{ {
uptr addr; uptr addr;
PageFaultInfo(uptr address) PageFaultInfo(uptr address)
{ {
addr = address; addr = address;
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -44,22 +44,22 @@ struct PageFaultInfo
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo> class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
{ {
public: public:
typedef PageFaultInfo EvtParams; typedef PageFaultInfo EvtParams;
public: public:
virtual ~IEventListener_PageFault() = default; virtual ~IEventListener_PageFault() = default;
virtual void DispatchEvent(const PageFaultInfo &evtinfo, bool &handled) virtual void DispatchEvent(const PageFaultInfo& evtinfo, bool& handled)
{ {
OnPageFaultEvent(evtinfo, handled); OnPageFaultEvent(evtinfo, handled);
} }
virtual void DispatchEvent(const PageFaultInfo &evtinfo) virtual void DispatchEvent(const PageFaultInfo& evtinfo)
{ {
pxFailRel("Don't call me, damnit. Use DispatchException instead."); pxFailRel("Don't call me, damnit. Use DispatchException instead.");
} }
virtual void OnPageFaultEvent(const PageFaultInfo &evtinfo, bool &handled) {} virtual void OnPageFaultEvent(const PageFaultInfo& evtinfo, bool& handled) {}
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -68,34 +68,34 @@ public:
class EventListener_PageFault : public IEventListener_PageFault class EventListener_PageFault : public IEventListener_PageFault
{ {
public: public:
EventListener_PageFault(); EventListener_PageFault();
virtual ~EventListener_PageFault(); virtual ~EventListener_PageFault();
}; };
template <typename TypeToDispatchTo> template <typename TypeToDispatchTo>
class EventListenerHelper_PageFault : public EventListener_PageFault class EventListenerHelper_PageFault : public EventListener_PageFault
{ {
public: public:
TypeToDispatchTo *Owner; TypeToDispatchTo* Owner;
public: public:
EventListenerHelper_PageFault(TypeToDispatchTo &dispatchTo) EventListenerHelper_PageFault(TypeToDispatchTo& dispatchTo)
{ {
Owner = &dispatchTo; Owner = &dispatchTo;
} }
EventListenerHelper_PageFault(TypeToDispatchTo *dispatchTo) EventListenerHelper_PageFault(TypeToDispatchTo* dispatchTo)
{ {
Owner = dispatchTo; Owner = dispatchTo;
} }
virtual ~EventListenerHelper_PageFault() = default; virtual ~EventListenerHelper_PageFault() = default;
protected: protected:
virtual void OnPageFaultEvent(const PageFaultInfo &info, bool &handled) virtual void OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
{ {
Owner->OnPageFaultEvent(info, handled); Owner->OnPageFaultEvent(info, handled);
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -104,23 +104,23 @@ protected:
class SrcType_PageFault : public EventSource<IEventListener_PageFault> class SrcType_PageFault : public EventSource<IEventListener_PageFault>
{ {
protected: protected:
typedef EventSource<IEventListener_PageFault> _parent; typedef EventSource<IEventListener_PageFault> _parent;
protected: protected:
bool m_handled; bool m_handled;
public: public:
SrcType_PageFault() SrcType_PageFault()
: m_handled(false) : m_handled(false)
{ {
} }
virtual ~SrcType_PageFault() = default; virtual ~SrcType_PageFault() = default;
bool WasHandled() const { return m_handled; } bool WasHandled() const { return m_handled; }
virtual void Dispatch(const PageFaultInfo &params); virtual void Dispatch(const PageFaultInfo& params);
protected: protected:
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt); virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt);
}; };
@ -130,40 +130,41 @@ protected:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class VirtualMemoryManager class VirtualMemoryManager
{ {
DeclareNoncopyableObject(VirtualMemoryManager); DeclareNoncopyableObject(VirtualMemoryManager);
wxString m_name; wxString m_name;
uptr m_baseptr; uptr m_baseptr;
// An array to track page usage (to trigger asserts if things try to overlap) // An array to track page usage (to trigger asserts if things try to overlap)
std::atomic<bool> *m_pageuse; std::atomic<bool>* m_pageuse;
// reserved memory (in pages) // reserved memory (in pages)
u32 m_pages_reserved; u32 m_pages_reserved;
public: public:
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it, // If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
// calls to IsOk() will return false and Alloc() will always return null pointers // calls to IsOk() will return false and Alloc() will always return null pointers
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base` // strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false); VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
~VirtualMemoryManager(); ~VirtualMemoryManager();
void *GetBase() const { return (void *)m_baseptr; } void* GetBase() const { return (void*)m_baseptr; }
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area // Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
// offsetLocation must be page-aligned // offsetLocation must be page-aligned
void *Alloc(uptr offsetLocation, size_t size) const; void* Alloc(uptr offsetLocation, size_t size) const;
void *AllocAtAddress(void *address, size_t size) const { void* AllocAtAddress(void* address, size_t size) const
return Alloc(size, (uptr)address - m_baseptr); {
} return Alloc(size, (uptr)address - m_baseptr);
}
void Free(void *address, size_t size) const; void Free(void* address, size_t size) const;
// Was this VirtualMemoryManager successfully able to get its memory mapping? // Was this VirtualMemoryManager successfully able to get its memory mapping?
// (If not, calls to Alloc will return null pointers) // (If not, calls to Alloc will return null pointers)
bool IsOk() const { return m_baseptr != 0; } bool IsOk() const { return m_baseptr != 0; }
}; };
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr; typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
@ -173,13 +174,14 @@ typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class VirtualMemoryBumpAllocator class VirtualMemoryBumpAllocator
{ {
const VirtualMemoryManagerPtr m_allocator; const VirtualMemoryManagerPtr m_allocator;
std::atomic<uptr> m_baseptr{0}; std::atomic<uptr> m_baseptr{0};
const uptr m_endptr = 0; const uptr m_endptr = 0;
public: public:
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation); VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
void *Alloc(size_t size); void* Alloc(size_t size);
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; } const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -187,108 +189,108 @@ public:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class VirtualMemoryReserve class VirtualMemoryReserve
{ {
DeclareNoncopyableObject(VirtualMemoryReserve); DeclareNoncopyableObject(VirtualMemoryReserve);
protected: protected:
wxString m_name; wxString m_name;
// Where the memory came from (so we can return it) // Where the memory came from (so we can return it)
VirtualMemoryManagerPtr m_allocator; VirtualMemoryManagerPtr m_allocator;
// Default size of the reserve, in bytes. Can be specified when the object is constructed. // Default size of the reserve, in bytes. Can be specified when the object is constructed.
// Is used as the reserve size when Reserve() is called, unless an override is specified // Is used as the reserve size when Reserve() is called, unless an override is specified
// in the Reserve parameters. // in the Reserve parameters.
size_t m_defsize; size_t m_defsize;
void *m_baseptr; void* m_baseptr;
// reserved memory (in pages). // reserved memory (in pages).
uptr m_pages_reserved; uptr m_pages_reserved;
// Records the number of pages committed to memory. // Records the number of pages committed to memory.
// (metric for analysis of buffer usage) // (metric for analysis of buffer usage)
uptr m_pages_commited; uptr m_pages_commited;
// Protection mode to be applied to committed blocks. // Protection mode to be applied to committed blocks.
PageProtectionMode m_prot_mode; PageProtectionMode m_prot_mode;
// Controls write access to the entire reserve. When true (the default), the reserve // Controls write access to the entire reserve. When true (the default), the reserve
// operates normally. When set to false, all committed blocks are re-protected with // operates normally. When set to false, all committed blocks are re-protected with
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF // write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
// as well. // as well.
bool m_allow_writes; bool m_allow_writes;
// Allows the implementation to decide how much memory it needs to allocate if someone requests the given size // Allows the implementation to decide how much memory it needs to allocate if someone requests the given size
// Should translate requests of size 0 to m_defsize // Should translate requests of size 0 to m_defsize
virtual size_t GetSize(size_t requestedSize); virtual size_t GetSize(size_t requestedSize);
public: public:
VirtualMemoryReserve(const wxString &name, size_t size = 0); VirtualMemoryReserve(const wxString& name, size_t size = 0);
virtual ~VirtualMemoryReserve() virtual ~VirtualMemoryReserve()
{ {
Release(); Release();
} }
// Initialize with the given piece of memory // Initialize with the given piece of memory
// Note: The memory is already allocated, the allocator is for future use to free the region // Note: The memory is already allocated, the allocator is for future use to free the region
// It may be null in which case there is no way to free the memory in a way it will be usable again // It may be null in which case there is no way to free the memory in a way it will be usable again
virtual void *Assign(VirtualMemoryManagerPtr allocator, void *baseptr, size_t size); virtual void* Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size);
void *Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0) void* Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
{ {
size = GetSize(size); size = GetSize(size);
void *allocation = allocator->Alloc(baseOffset, size); void* allocation = allocator->Alloc(baseOffset, size);
return Assign(std::move(allocator), allocation, size); return Assign(std::move(allocator), allocation, size);
} }
void *Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0) void* Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
{ {
size = GetSize(size); size = GetSize(size);
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size); return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
} }
virtual void Reset(); virtual void Reset();
virtual void Release(); virtual void Release();
virtual bool TryResize(uint newsize); virtual bool TryResize(uint newsize);
virtual bool Commit(); virtual bool Commit();
virtual void ForbidModification(); virtual void ForbidModification();
virtual void AllowModification(); virtual void AllowModification();
bool IsOk() const { return m_baseptr != NULL; } bool IsOk() const { return m_baseptr != NULL; }
const wxString& GetName() const { return m_name; } const wxString& GetName() const { return m_name; }
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; } uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
uptr GetReserveSizeInPages() const { return m_pages_reserved; } uptr GetReserveSizeInPages() const { return m_pages_reserved; }
uint GetCommittedPageCount() const { return m_pages_commited; } uint GetCommittedPageCount() const { return m_pages_commited; }
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; } uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
u8 *GetPtr() { return (u8 *)m_baseptr; } u8* GetPtr() { return (u8*)m_baseptr; }
const u8 *GetPtr() const { return (u8 *)m_baseptr; } const u8* GetPtr() const { return (u8*)m_baseptr; }
u8 *GetPtrEnd() { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); } u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
const u8 *GetPtrEnd() const { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); } const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
VirtualMemoryReserve &SetPageAccessOnCommit(const PageProtectionMode &mode); VirtualMemoryReserve& SetPageAccessOnCommit(const PageProtectionMode& mode);
operator void *() { return m_baseptr; } operator void*() { return m_baseptr; }
operator const void *() const { return m_baseptr; } operator const void*() const { return m_baseptr; }
operator u8 *() { return (u8 *)m_baseptr; } operator u8*() { return (u8*)m_baseptr; }
operator const u8 *() const { return (u8 *)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; }
u8 &operator[](uint idx) u8& operator[](uint idx)
{ {
pxAssert(idx < (m_pages_reserved * __pagesize)); pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8 *)m_baseptr + idx); return *((u8*)m_baseptr + idx);
} }
const u8 &operator[](uint idx) const const u8& operator[](uint idx) const
{ {
pxAssert(idx < (m_pages_reserved * __pagesize)); pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8 *)m_baseptr + idx); return *((u8*)m_baseptr + idx);
} }
protected: protected:
virtual void ReprotectCommittedBlocks(const PageProtectionMode &newmode); virtual void ReprotectCommittedBlocks(const PageProtectionMode& newmode);
}; };
#ifdef __POSIX__ #ifdef __POSIX__
@ -299,11 +301,11 @@ protected:
#elif defined(_WIN32) #elif defined(_WIN32)
struct _EXCEPTION_POINTERS; struct _EXCEPTION_POINTERS;
extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS *eps); extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
#define PCSX2_PAGEFAULT_PROTECT __try #define PCSX2_PAGEFAULT_PROTECT __try
#define PCSX2_PAGEFAULT_EXCEPT \ #define PCSX2_PAGEFAULT_EXCEPT \
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {} __except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
#else #else
#error PCSX2 - Unsupported operating system platform. #error PCSX2 - Unsupported operating system platform.
@ -313,5 +315,5 @@ extern void pxInstallSignalHandler();
extern void _platform_InstallSignalHandler(); extern void _platform_InstallSignalHandler();
#include "Threading.h" #include "Threading.h"
extern SrcType_PageFault *Source_PageFault; extern SrcType_PageFault* Source_PageFault;
extern Threading::Mutex PageFault_Mutex; extern Threading::Mutex PageFault_Mutex;

View File

@ -26,180 +26,184 @@
class wxDirName : protected wxFileName class wxDirName : protected wxFileName
{ {
public: public:
explicit wxDirName(const wxFileName &src) explicit wxDirName(const wxFileName& src)
{ {
Assign(src.GetPath(), wxEmptyString); Assign(src.GetPath(), wxEmptyString);
} }
wxDirName() wxDirName()
: wxFileName() : wxFileName()
{ {
} }
wxDirName(const wxDirName &src) wxDirName(const wxDirName& src)
: wxFileName(src) : wxFileName(src)
{ {
} }
explicit wxDirName(const char *src) { Assign(fromUTF8(src)); } explicit wxDirName(const char* src) { Assign(fromUTF8(src)); }
explicit wxDirName(const wxString &src) { Assign(src); } explicit wxDirName(const wxString& src) { Assign(src); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void Assign(const wxString &volume, const wxString &path) void Assign(const wxString& volume, const wxString& path)
{ {
wxFileName::Assign(volume, path, wxEmptyString); wxFileName::Assign(volume, path, wxEmptyString);
} }
void Assign(const wxString &path) void Assign(const wxString& path)
{ {
wxFileName::Assign(path, wxEmptyString); wxFileName::Assign(path, wxEmptyString);
} }
void Assign(const wxDirName &path) void Assign(const wxDirName& path)
{ {
wxFileName::Assign(path); wxFileName::Assign(path);
} }
void Clear() { wxFileName::Clear(); } void Clear() { wxFileName::Clear(); }
wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); } wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); }
wxCharBuffer ToAscii() const { return GetPath().ToAscii(); } wxCharBuffer ToAscii() const { return GetPath().ToAscii(); }
wxString ToString() const { return GetPath(); } wxString ToString() const { return GetPath(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool IsWritable() const { return IsDirWritable(); } bool IsWritable() const { return IsDirWritable(); }
bool IsReadable() const { return IsDirReadable(); } bool IsReadable() const { return IsDirReadable(); }
bool Exists() const { return DirExists(); } bool Exists() const { return DirExists(); }
bool FileExists() const { return wxFileName::FileExists(); } bool FileExists() const { return wxFileName::FileExists(); }
bool IsOk() const { return wxFileName::IsOk(); } bool IsOk() const { return wxFileName::IsOk(); }
bool IsRelative() const { return wxFileName::IsRelative(); } bool IsRelative() const { return wxFileName::IsRelative(); }
bool IsAbsolute() const { return wxFileName::IsAbsolute(); } bool IsAbsolute() const { return wxFileName::IsAbsolute(); }
bool SameAs(const wxDirName &filepath) const bool SameAs(const wxDirName& filepath) const
{ {
return wxFileName::SameAs(filepath); return wxFileName::SameAs(filepath);
} }
//Returns true if the file is somewhere inside this directory (and both file and directory are not relative). //Returns true if the file is somewhere inside this directory (and both file and directory are not relative).
bool IsContains(const wxFileName &file) const bool IsContains(const wxFileName& file) const
{ {
if (this->IsRelative() || file.IsRelative()) if (this->IsRelative() || file.IsRelative())
return false; return false;
wxFileName f(file); wxFileName f(file);
while (1) { while (1)
if (this->SameAs(wxDirName(f.GetPath()))) {
return true; if (this->SameAs(wxDirName(f.GetPath())))
return true;
if (f.GetDirCount() == 0) if (f.GetDirCount() == 0)
return false; return false;
f.RemoveLastDir(); f.RemoveLastDir();
} }
return false; return false;
} }
bool IsContains(const wxDirName &dir) const bool IsContains(const wxDirName& dir) const
{ {
return IsContains((wxFileName)dir); return IsContains((wxFileName)dir);
} }
//Auto relative works as follows: //Auto relative works as follows:
// 1. if either base or subject are relative, return subject (should never be used with relative paths). // 1. if either base or subject are relative, return subject (should never be used with relative paths).
// 2. else if subject is somewhere inside base folder, then result is subject relative to base. // 2. else if subject is somewhere inside base folder, then result is subject relative to base.
// 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter. // 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter.
// 4. else, result is absolute path of subject. // 4. else, result is absolute path of subject.
// //
// returns ok if both this and base are absolute paths. // returns ok if both this and base are absolute paths.
static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString &pathbase) static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString& pathbase)
{ {
wxFileName subject(_subject); wxFileName subject(_subject);
wxDirName base(pathbase); wxDirName base(pathbase);
if (base.IsRelative() || subject.IsRelative()) if (base.IsRelative() || subject.IsRelative())
return subject.GetFullPath(); return subject.GetFullPath();
wxString bv(base.GetVolume()); wxString bv(base.GetVolume());
bv.MakeUpper(); bv.MakeUpper();
wxString sv(subject.GetVolume()); wxString sv(subject.GetVolume());
sv.MakeUpper(); sv.MakeUpper();
if (base.IsContains(subject)) { if (base.IsContains(subject))
subject.MakeRelativeTo(base.GetFullPath()); {
} else if (base.HasVolume() && subject.HasVolume() && bv == sv) { subject.MakeRelativeTo(base.GetFullPath());
wxString unusedVolume; }
wxString pathSansVolume; else if (base.HasVolume() && subject.HasVolume() && bv == sv)
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume); {
subject = pathSansVolume; wxString unusedVolume;
} wxString pathSansVolume;
//implicit else: this stays fully absolute subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
subject = pathSansVolume;
}
//implicit else: this stays fully absolute
return subject.GetFullPath(); return subject.GetFullPath();
} }
static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString &pathbase) static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString& pathbase)
{ {
return MakeAutoRelativeTo(wxFileName(subject), pathbase); return MakeAutoRelativeTo(wxFileName(subject), pathbase);
} }
// Returns the number of sub folders in this directory path // Returns the number of sub folders in this directory path
size_t GetCount() const { return GetDirCount(); } size_t GetCount() const { return GetDirCount(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
wxFileName Combine(const wxFileName &right) const; wxFileName Combine(const wxFileName& right) const;
wxDirName Combine(const wxDirName &right) const; wxDirName Combine(const wxDirName& right) const;
// removes the lastmost directory from the path // removes the lastmost directory from the path
void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); } void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); }
wxDirName &Normalize(int flags = wxPATH_NORM_ALL, const wxString &cwd = wxEmptyString); wxDirName& Normalize(int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString);
wxDirName &MakeRelativeTo(const wxString &pathBase = wxEmptyString); wxDirName& MakeRelativeTo(const wxString& pathBase = wxEmptyString);
wxDirName &MakeAbsolute(const wxString &cwd = wxEmptyString); wxDirName& MakeAbsolute(const wxString& cwd = wxEmptyString);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void AssignCwd(const wxString &volume = wxEmptyString) { wxFileName::AssignCwd(volume); } void AssignCwd(const wxString& volume = wxEmptyString) { wxFileName::AssignCwd(volume); }
bool SetCwd() { return wxFileName::SetCwd(); } bool SetCwd() { return wxFileName::SetCwd(); }
// wxWidgets is missing the const qualifier for this one! Shame! // wxWidgets is missing the const qualifier for this one! Shame!
void Rmdir(); void Rmdir();
bool Mkdir(); bool Mkdir();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
wxDirName &operator=(const wxDirName &dirname) wxDirName& operator=(const wxDirName& dirname)
{ {
Assign(dirname); Assign(dirname);
return *this; return *this;
} }
wxDirName &operator=(const wxString &dirname) wxDirName& operator=(const wxString& dirname)
{ {
Assign(dirname); Assign(dirname);
return *this; return *this;
} }
wxDirName &operator=(const char *dirname) wxDirName& operator=(const char* dirname)
{ {
Assign(fromUTF8(dirname)); Assign(fromUTF8(dirname));
return *this; return *this;
} }
wxFileName operator+(const wxFileName &right) const { return Combine(right); } wxFileName operator+(const wxFileName& right) const { return Combine(right); }
wxDirName operator+(const wxDirName &right) const { return Combine(right); } wxDirName operator+(const wxDirName& right) const { return Combine(right); }
wxFileName operator+(const wxString &right) const { return Combine(wxFileName(right)); } wxFileName operator+(const wxString& right) const { return Combine(wxFileName(right)); }
wxFileName operator+(const char *right) const { return Combine(wxFileName(fromUTF8(right))); } wxFileName operator+(const char* right) const { return Combine(wxFileName(fromUTF8(right))); }
bool operator==(const wxDirName &filename) const { return SameAs(filename); } bool operator==(const wxDirName& filename) const { return SameAs(filename); }
bool operator!=(const wxDirName &filename) const { return !SameAs(filename); } bool operator!=(const wxDirName& filename) const { return !SameAs(filename); }
bool operator==(const wxFileName &filename) const { return SameAs(wxDirName(filename)); } bool operator==(const wxFileName& filename) const { return SameAs(wxDirName(filename)); }
bool operator!=(const wxFileName &filename) const { return !SameAs(wxDirName(filename)); } bool operator!=(const wxFileName& filename) const { return !SameAs(wxDirName(filename)); }
// compare with a filename string interpreted as a native file name // compare with a filename string interpreted as a native file name
bool operator==(const wxString &filename) const { return SameAs(wxDirName(filename)); } bool operator==(const wxString& filename) const { return SameAs(wxDirName(filename)); }
bool operator!=(const wxString &filename) const { return !SameAs(wxDirName(filename)); } bool operator!=(const wxString& filename) const { return !SameAs(wxDirName(filename)); }
const wxFileName &GetFilename() const { return *this; } const wxFileName& GetFilename() const { return *this; }
wxFileName &GetFilename() { return *this; } wxFileName& GetFilename() { return *this; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -211,20 +215,20 @@ public:
// //
namespace Path namespace Path
{ {
extern bool IsRelative(const wxString &path); extern bool IsRelative(const wxString& path);
extern s64 GetFileSize(const wxString &path); extern s64 GetFileSize(const wxString& path);
extern wxString Normalize(const wxString &srcpath); extern wxString Normalize(const wxString& srcpath);
extern wxString Normalize(const wxDirName &srcpath); extern wxString Normalize(const wxDirName& srcpath);
extern wxString MakeAbsolute(const wxString &srcpath); extern wxString MakeAbsolute(const wxString& srcpath);
extern wxString Combine(const wxString &srcPath, const wxString &srcFile); extern wxString Combine(const wxString& srcPath, const wxString& srcFile);
extern wxString Combine(const wxDirName &srcPath, const wxFileName &srcFile); extern wxString Combine(const wxDirName& srcPath, const wxFileName& srcFile);
extern wxString Combine(const wxString &srcPath, const wxDirName &srcFile); extern wxString Combine(const wxString& srcPath, const wxDirName& srcFile);
extern wxString ReplaceExtension(const wxString &src, const wxString &ext); extern wxString ReplaceExtension(const wxString& src, const wxString& ext);
extern wxString ReplaceFilename(const wxString &src, const wxString &newfilename); extern wxString ReplaceFilename(const wxString& src, const wxString& newfilename);
extern wxString GetFilename(const wxString &src); extern wxString GetFilename(const wxString& src);
extern wxString GetDirectory(const wxString &src); extern wxString GetDirectory(const wxString& src);
extern wxString GetFilenameWithoutExt(const wxString &src); extern wxString GetFilenameWithoutExt(const wxString& src);
extern wxString GetRootDirectory(const wxString &src); extern wxString GetRootDirectory(const wxString& src);
} } // namespace Path

View File

@ -22,60 +22,60 @@
// wxDirName (implementations) // wxDirName (implementations)
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
wxFileName wxDirName::Combine(const wxFileName &right) const wxFileName wxDirName::Combine(const wxFileName& right) const
{ {
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation."); pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
if (right.IsAbsolute()) if (right.IsAbsolute())
return right; return right;
// Append any directory parts from right, and then set the filename. // Append any directory parts from right, and then set the filename.
// Except we can't do that because our m_members are private (argh!) and there is no API // Except we can't do that because our m_members are private (argh!) and there is no API
// for getting each component of the path. So instead let's use Normalize: // for getting each component of the path. So instead let's use Normalize:
wxFileName result(right); wxFileName result(right);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath()); result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
return result; return result;
} }
wxDirName wxDirName::Combine(const wxDirName &right) const wxDirName wxDirName::Combine(const wxDirName& right) const
{ {
pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation."); pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation.");
wxDirName result(right); wxDirName result(right);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath()); result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
return result; return result;
} }
wxDirName &wxDirName::Normalize(int flags, const wxString &cwd) wxDirName& wxDirName::Normalize(int flags, const wxString& cwd)
{ {
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization."); pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::Normalize(flags, cwd)) if (!wxFileName::Normalize(flags, cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed."); throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
return *this; return *this;
} }
wxDirName &wxDirName::MakeRelativeTo(const wxString &pathBase) wxDirName& wxDirName::MakeRelativeTo(const wxString& pathBase)
{ {
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization."); pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::MakeRelativeTo(pathBase)) if (!wxFileName::MakeRelativeTo(pathBase))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed."); throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
return *this; return *this;
} }
wxDirName &wxDirName::MakeAbsolute(const wxString &cwd) wxDirName& wxDirName::MakeAbsolute(const wxString& cwd)
{ {
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization."); pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::MakeAbsolute(cwd)) if (!wxFileName::MakeAbsolute(cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed."); throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
return *this; return *this;
} }
void wxDirName::Rmdir() void wxDirName::Rmdir()
{ {
if (!Exists()) if (!Exists())
return; return;
wxFileName::Rmdir(); wxFileName::Rmdir();
// TODO : Throw exception if operation failed? Do we care? // TODO : Throw exception if operation failed? Do we care?
} }
bool wxDirName::Mkdir() bool wxDirName::Mkdir()
@ -87,9 +87,9 @@ bool wxDirName::Mkdir()
#define wxS_DIR_DEFAULT 0777 #define wxS_DIR_DEFAULT 0777
#endif #endif
if (Exists()) if (Exists())
return true; return true;
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
} }
@ -98,111 +98,111 @@ bool wxDirName::Mkdir()
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
bool Path::IsRelative(const wxString &path) bool Path::IsRelative(const wxString& path)
{ {
return wxDirName(path).IsRelative(); return wxDirName(path).IsRelative();
} }
// Returns -1 if the file does not exist. // Returns -1 if the file does not exist.
s64 Path::GetFileSize(const wxString &path) s64 Path::GetFileSize(const wxString& path)
{ {
if (!wxFile::Exists(path.c_str())) if (!wxFile::Exists(path.c_str()))
return -1; return -1;
return (s64)wxFileName::GetSize(path).GetValue(); return (s64)wxFileName::GetSize(path).GetValue();
} }
wxString Path::Normalize(const wxString &src) wxString Path::Normalize(const wxString& src)
{ {
wxFileName normalize(src); wxFileName normalize(src);
normalize.Normalize(); normalize.Normalize();
return normalize.GetFullPath(); return normalize.GetFullPath();
} }
wxString Path::Normalize(const wxDirName &src) wxString Path::Normalize(const wxDirName& src)
{ {
return wxDirName(src).Normalize().ToString(); return wxDirName(src).Normalize().ToString();
} }
wxString Path::MakeAbsolute(const wxString &src) wxString Path::MakeAbsolute(const wxString& src)
{ {
wxFileName absolute(src); wxFileName absolute(src);
absolute.MakeAbsolute(); absolute.MakeAbsolute();
return absolute.GetFullPath(); return absolute.GetFullPath();
} }
// Concatenates two pathnames together, inserting delimiters (backslash on win32) // Concatenates two pathnames together, inserting delimiters (backslash on win32)
// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length. // as needed! Assumes the 'dest' is allocated to at least g_MaxPath length.
// //
wxString Path::Combine(const wxString &srcPath, const wxString &srcFile) wxString Path::Combine(const wxString& srcPath, const wxString& srcFile)
{ {
return (wxDirName(srcPath) + srcFile).GetFullPath(); return (wxDirName(srcPath) + srcFile).GetFullPath();
} }
wxString Path::Combine(const wxDirName &srcPath, const wxFileName &srcFile) wxString Path::Combine(const wxDirName& srcPath, const wxFileName& srcFile)
{ {
return (srcPath + srcFile).GetFullPath(); return (srcPath + srcFile).GetFullPath();
} }
wxString Path::Combine(const wxString &srcPath, const wxDirName &srcFile) wxString Path::Combine(const wxString& srcPath, const wxDirName& srcFile)
{ {
return (wxDirName(srcPath) + srcFile).ToString(); return (wxDirName(srcPath) + srcFile).ToString();
} }
// Replaces the extension of the file with the one given. // Replaces the extension of the file with the one given.
// This function works for path names as well as file names. // This function works for path names as well as file names.
wxString Path::ReplaceExtension(const wxString &src, const wxString &ext) wxString Path::ReplaceExtension(const wxString& src, const wxString& ext)
{ {
wxFileName jojo(src); wxFileName jojo(src);
jojo.SetExt(ext); jojo.SetExt(ext);
return jojo.GetFullPath(); return jojo.GetFullPath();
} }
wxString Path::ReplaceFilename(const wxString &src, const wxString &newfilename) wxString Path::ReplaceFilename(const wxString& src, const wxString& newfilename)
{ {
wxFileName jojo(src); wxFileName jojo(src);
jojo.SetFullName(newfilename); jojo.SetFullName(newfilename);
return jojo.GetFullPath(); return jojo.GetFullPath();
} }
wxString Path::GetFilename(const wxString &src) wxString Path::GetFilename(const wxString& src)
{ {
return wxFileName(src).GetFullName(); return wxFileName(src).GetFullName();
} }
wxString Path::GetFilenameWithoutExt(const wxString &src) wxString Path::GetFilenameWithoutExt(const wxString& src)
{ {
return wxFileName(src).GetName(); return wxFileName(src).GetName();
} }
wxString Path::GetDirectory(const wxString &src) wxString Path::GetDirectory(const wxString& src)
{ {
return wxFileName(src).GetPath(); return wxFileName(src).GetPath();
} }
// returns the base/root directory of the given path. // returns the base/root directory of the given path.
// Example /this/that/something.txt -> dest == "/" // Example /this/that/something.txt -> dest == "/"
wxString Path::GetRootDirectory(const wxString &src) wxString Path::GetRootDirectory(const wxString& src)
{ {
size_t pos = src.find_first_of(wxFileName::GetPathSeparators()); size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
if (pos == wxString::npos) if (pos == wxString::npos)
return wxString(); return wxString();
else else
return wxString(src.begin(), src.begin() + pos); return wxString(src.begin(), src.begin() + pos);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Launches the specified file according to its mime type // Launches the specified file according to its mime type
// //
void pxLaunch(const wxString &filename) void pxLaunch(const wxString& filename)
{ {
wxLaunchDefaultBrowser(filename); wxLaunchDefaultBrowser(filename);
} }
void pxLaunch(const char *filename) void pxLaunch(const char* filename)
{ {
pxLaunch(fromUTF8(filename)); pxLaunch(fromUTF8(filename));
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -211,12 +211,12 @@ void pxLaunch(const char *filename)
// bypasses wxWidgets internal filename checking, which can end up launching things // bypasses wxWidgets internal filename checking, which can end up launching things
// through browser more often than desired. // through browser more often than desired.
// //
void pxExplore(const wxString &path) void pxExplore(const wxString& path)
{ {
wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path); wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path);
} }
void pxExplore(const char *path) void pxExplore(const char* path)
{ {
pxExplore(fromUTF8(path)); pxExplore(fromUTF8(path));
} }

View File

@ -60,116 +60,116 @@ typedef unsigned int uint;
#ifdef __cplusplus #ifdef __cplusplus
union u128 union u128
{ {
struct struct
{ {
u64 lo; u64 lo;
u64 hi; u64 hi;
}; };
u64 _u64[2]; u64 _u64[2];
u32 _u32[4]; u32 _u32[4];
u16 _u16[8]; u16 _u16[8];
u8 _u8[16]; u8 _u8[16];
// Explicit conversion from u64. Zero-extends the source through 128 bits. // Explicit conversion from u64. Zero-extends the source through 128 bits.
static u128 From64(u64 src) static u128 From64(u64 src)
{ {
u128 retval; u128 retval;
retval.lo = src; retval.lo = src;
retval.hi = 0; retval.hi = 0;
return retval; return retval;
} }
// Explicit conversion from u32. Zero-extends the source through 128 bits. // Explicit conversion from u32. Zero-extends the source through 128 bits.
static u128 From32(u32 src) static u128 From32(u32 src)
{ {
u128 retval; u128 retval;
retval._u32[0] = src; retval._u32[0] = src;
retval._u32[1] = 0; retval._u32[1] = 0;
retval.hi = 0; retval.hi = 0;
return retval; return retval;
} }
operator u32() const { return _u32[0]; } operator u32() const { return _u32[0]; }
operator u16() const { return _u16[0]; } operator u16() const { return _u16[0]; }
operator u8() const { return _u8[0]; } operator u8() const { return _u8[0]; }
bool operator==(const u128 &right) const bool operator==(const u128& right) const
{ {
return (lo == right.lo) && (hi == right.hi); return (lo == right.lo) && (hi == right.hi);
} }
bool operator!=(const u128 &right) const bool operator!=(const u128& right) const
{ {
return (lo != right.lo) || (hi != right.hi); return (lo != right.lo) || (hi != right.hi);
} }
// In order for the following ToString() and WriteTo methods to be available, you must // In order for the following ToString() and WriteTo methods to be available, you must
// be linking to both wxWidgets and the pxWidgets extension library. If you are not // be linking to both wxWidgets and the pxWidgets extension library. If you are not
// using them, then you will need to provide your own implementations of these methods. // using them, then you will need to provide your own implementations of these methods.
wxString ToString() const; wxString ToString() const;
wxString ToString64() const; wxString ToString64() const;
wxString ToString8() const; wxString ToString8() const;
void WriteTo(FastFormatAscii &dest) const; void WriteTo(FastFormatAscii& dest) const;
void WriteTo8(FastFormatAscii &dest) const; void WriteTo8(FastFormatAscii& dest) const;
void WriteTo64(FastFormatAscii &dest) const; void WriteTo64(FastFormatAscii& dest) const;
}; };
struct s128 struct s128
{ {
s64 lo; s64 lo;
s64 hi; s64 hi;
// explicit conversion from s64, with sign extension. // explicit conversion from s64, with sign extension.
static s128 From64(s64 src) static s128 From64(s64 src)
{ {
s128 retval = {src, (src < 0) ? -1 : 0}; s128 retval = {src, (src < 0) ? -1 : 0};
return retval; return retval;
} }
// explicit conversion from s32, with sign extension. // explicit conversion from s32, with sign extension.
static s128 From64(s32 src) static s128 From64(s32 src)
{ {
s128 retval = {src, (src < 0) ? -1 : 0}; s128 retval = {src, (src < 0) ? -1 : 0};
return retval; return retval;
} }
operator u32() const { return (s32)lo; } operator u32() const { return (s32)lo; }
operator u16() const { return (s16)lo; } operator u16() const { return (s16)lo; }
operator u8() const { return (s8)lo; } operator u8() const { return (s8)lo; }
bool operator==(const s128 &right) const bool operator==(const s128& right) const
{ {
return (lo == right.lo) && (hi == right.hi); return (lo == right.lo) && (hi == right.hi);
} }
bool operator!=(const s128 &right) const bool operator!=(const s128& right) const
{ {
return (lo != right.lo) || (hi != right.hi); return (lo != right.lo) || (hi != right.hi);
} }
}; };
#else #else
typedef union _u128_t typedef union _u128_t
{ {
struct struct
{ {
u64 lo; u64 lo;
u64 hi; u64 hi;
}; };
u64 _u64[2]; u64 _u64[2];
u32 _u32[4]; u32 _u32[4];
u16 _u16[8]; u16 _u16[8];
u8 _u8[16]; u8 _u8[16];
} u128; } u128;
typedef union _s128_t typedef union _s128_t
{ {
u64 lo; u64 lo;
s64 hi; s64 hi;
} s128; } s128;
#endif #endif

View File

@ -33,174 +33,175 @@
namespace Perf namespace Perf
{ {
// Warning object aren't thread safe // Warning object aren't thread safe
InfoVector any(""); InfoVector any("");
InfoVector ee("EE"); InfoVector ee("EE");
InfoVector iop("IOP"); InfoVector iop("IOP");
InfoVector vu("VU"); InfoVector vu("VU");
InfoVector vif("VIF"); InfoVector vif("VIF");
// Perf is only supported on linux // Perf is only supported on linux
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE)) #if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Implementation of the Info object // Implementation of the Info object
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Info::Info(uptr x86, u32 size, const char *symbol) Info::Info(uptr x86, u32 size, const char* symbol)
: m_x86(x86) : m_x86(x86)
, m_size(size) , m_size(size)
, m_dynamic(false) , m_dynamic(false)
{ {
strncpy(m_symbol, symbol, sizeof(m_symbol)); strncpy(m_symbol, symbol, sizeof(m_symbol));
} }
Info::Info(uptr x86, u32 size, const char *symbol, u32 pc) Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
: m_x86(x86) : m_x86(x86)
, m_size(size) , m_size(size)
, m_dynamic(true) , m_dynamic(true)
{ {
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc); snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
} }
void Info::Print(FILE *fp) void Info::Print(FILE* fp)
{ {
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol); fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Implementation of the InfoVector object // Implementation of the InfoVector object
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
InfoVector::InfoVector(const char *prefix) InfoVector::InfoVector(const char* prefix)
{ {
strncpy(m_prefix, prefix, sizeof(m_prefix)); strncpy(m_prefix, prefix, sizeof(m_prefix));
#ifdef ENABLE_VTUNE #ifdef ENABLE_VTUNE
m_vtune_id = iJIT_GetNewMethodID(); m_vtune_id = iJIT_GetNewMethodID();
#else #else
m_vtune_id = 0; m_vtune_id = 0;
#endif #endif
} }
void InfoVector::print(FILE *fp) void InfoVector::print(FILE* fp)
{ {
for (auto &&it : m_v) for (auto&& it : m_v)
it.Print(fp); it.Print(fp);
} }
void InfoVector::map(uptr x86, u32 size, const char *symbol) void InfoVector::map(uptr x86, u32 size, const char* symbol)
{ {
// This function is typically used for dispatcher and recompiler. // This function is typically used for dispatcher and recompiler.
// Dispatchers are on a page and must always be kept. // Dispatchers are on a page and must always be kept.
// Recompilers are much bigger (TODO check VIF) and are only // Recompilers are much bigger (TODO check VIF) and are only
// useful when MERGE_BLOCK_RESULT is defined // useful when MERGE_BLOCK_RESULT is defined
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT) #if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
u32 max_code_size = 16 * _1kb; u32 max_code_size = 16 * _1kb;
#else #else
u32 max_code_size = _1gb; u32 max_code_size = _1gb;
#endif #endif
if (size < max_code_size) { if (size < max_code_size)
m_v.emplace_back(x86, size, symbol); {
m_v.emplace_back(x86, size, symbol);
#ifdef ENABLE_VTUNE #ifdef ENABLE_VTUNE
std::string name = std::string(symbol); std::string name = std::string(symbol);
iJIT_Method_Load ml; iJIT_Method_Load ml;
memset(&ml, 0, sizeof(ml)); memset(&ml, 0, sizeof(ml));
ml.method_id = iJIT_GetNewMethodID(); ml.method_id = iJIT_GetNewMethodID();
ml.method_name = (char *)name.c_str(); ml.method_name = (char*)name.c_str();
ml.method_load_address = (void *)x86; ml.method_load_address = (void*)x86;
ml.method_size = size; ml.method_size = size;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml); iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u); //fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
#endif #endif
} }
} }
void InfoVector::map(uptr x86, u32 size, u32 pc) void InfoVector::map(uptr x86, u32 size, u32 pc)
{ {
#ifndef MERGE_BLOCK_RESULT #ifndef MERGE_BLOCK_RESULT
m_v.emplace_back(x86, size, m_prefix, pc); m_v.emplace_back(x86, size, m_prefix, pc);
#endif #endif
#ifdef ENABLE_VTUNE #ifdef ENABLE_VTUNE
iJIT_Method_Load_V2 ml; iJIT_Method_Load_V2 ml;
memset(&ml, 0, sizeof(ml)); memset(&ml, 0, sizeof(ml));
#ifdef MERGE_BLOCK_RESULT #ifdef MERGE_BLOCK_RESULT
ml.method_id = m_vtune_id; ml.method_id = m_vtune_id;
ml.method_name = m_prefix; ml.method_name = m_prefix;
#else #else
std::string name = std::string(m_prefix) + "_" + std::to_string(pc); std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
ml.method_id = iJIT_GetNewMethodID(); ml.method_id = iJIT_GetNewMethodID();
ml.method_name = (char *)name.c_str(); ml.method_name = (char*)name.c_str();
#endif #endif
ml.method_load_address = (void *)x86; ml.method_load_address = (void*)x86;
ml.method_size = size; ml.method_size = size;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml); iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size); //fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
#endif #endif
} }
void InfoVector::reset() void InfoVector::reset()
{ {
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; }); auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
m_v.erase(dynamic, m_v.end()); m_v.erase(dynamic, m_v.end());
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Global function // Global function
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void dump() void dump()
{ {
char file[256]; char file[256];
snprintf(file, 250, "/tmp/perf-%d.map", getpid()); snprintf(file, 250, "/tmp/perf-%d.map", getpid());
FILE *fp = fopen(file, "w"); FILE* fp = fopen(file, "w");
any.print(fp); any.print(fp);
ee.print(fp); ee.print(fp);
iop.print(fp); iop.print(fp);
vu.print(fp); vu.print(fp);
if (fp) if (fp)
fclose(fp); fclose(fp);
} }
void dump_and_reset() void dump_and_reset()
{ {
dump(); dump();
any.reset(); any.reset();
ee.reset(); ee.reset();
iop.reset(); iop.reset();
vu.reset(); vu.reset();
} }
#else #else
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Dummy implementation // Dummy implementation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
InfoVector::InfoVector(const char *prefix) InfoVector::InfoVector(const char* prefix)
: m_vtune_id(0) : m_vtune_id(0)
{ {
} }
void InfoVector::map(uptr x86, u32 size, const char *symbol) {} void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
void InfoVector::map(uptr x86, u32 size, u32 pc) {} void InfoVector::map(uptr x86, u32 size, u32 pc) {}
void InfoVector::reset() {} void InfoVector::reset() {}
void dump() {} void dump() {}
void dump_and_reset() {} void dump_and_reset() {}
#endif #endif
} } // namespace Perf

View File

@ -22,41 +22,41 @@
namespace Perf namespace Perf
{ {
struct Info struct Info
{ {
uptr m_x86; uptr m_x86;
u32 m_size; u32 m_size;
char m_symbol[20]; char m_symbol[20];
// The idea is to keep static zones that are set only // The idea is to keep static zones that are set only
// once. // once.
bool m_dynamic; bool m_dynamic;
Info(uptr x86, u32 size, const char *symbol); Info(uptr x86, u32 size, const char* symbol);
Info(uptr x86, u32 size, const char *symbol, u32 pc); Info(uptr x86, u32 size, const char* symbol, u32 pc);
void Print(FILE *fp); void Print(FILE* fp);
}; };
class InfoVector class InfoVector
{ {
std::vector<Info> m_v; std::vector<Info> m_v;
char m_prefix[20]; char m_prefix[20];
unsigned int m_vtune_id; unsigned int m_vtune_id;
public: public:
InfoVector(const char *prefix); InfoVector(const char* prefix);
void print(FILE *fp); void print(FILE* fp);
void map(uptr x86, u32 size, const char *symbol); void map(uptr x86, u32 size, const char* symbol);
void map(uptr x86, u32 size, u32 pc); void map(uptr x86, u32 size, u32 pc);
void reset(); void reset();
}; };
void dump(); void dump();
void dump_and_reset(); void dump_and_reset();
extern InfoVector any; extern InfoVector any;
extern InfoVector ee; extern InfoVector ee;
extern InfoVector iop; extern InfoVector iop;
extern InfoVector vu; extern InfoVector vu;
extern InfoVector vif; extern InfoVector vif;
} } // namespace Perf

View File

@ -22,188 +22,188 @@
namespace Threading namespace Threading
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ThreadDeleteEvent // ThreadDeleteEvent
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class EventListener_Thread : public IEventDispatcher<int> class EventListener_Thread : public IEventDispatcher<int>
{ {
public: public:
typedef int EvtParams; typedef int EvtParams;
protected: protected:
pxThread *m_thread; pxThread* m_thread;
public: public:
EventListener_Thread() EventListener_Thread()
{ {
m_thread = NULL; m_thread = NULL;
} }
virtual ~EventListener_Thread() = default; virtual ~EventListener_Thread() = default;
void SetThread(pxThread &thr) { m_thread = &thr; } void SetThread(pxThread& thr) { m_thread = &thr; }
void SetThread(pxThread *thr) { m_thread = thr; } void SetThread(pxThread* thr) { m_thread = thr; }
void DispatchEvent(const int &params) void DispatchEvent(const int& params)
{ {
OnThreadCleanup(); OnThreadCleanup();
} }
protected: protected:
// Invoked by the pxThread when the thread execution is ending. This is // Invoked by the pxThread when the thread execution is ending. This is
// typically more useful than a delete listener since the extended thread information // typically more useful than a delete listener since the extended thread information
// provided by virtualized functions/methods will be available. // provided by virtualized functions/methods will be available.
// Important! This event is executed *by the thread*, so care must be taken to ensure // Important! This event is executed *by the thread*, so care must be taken to ensure
// thread sync when necessary (posting messages to the main thread, etc). // thread sync when necessary (posting messages to the main thread, etc).
virtual void OnThreadCleanup() = 0; virtual void OnThreadCleanup() = 0;
}; };
/// Set the name of the current thread /// Set the name of the current thread
void SetNameOfCurrentThread(const char* name); void SetNameOfCurrentThread(const char* name);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxThread - Helper class for the basics of starting/managing persistent threads. // pxThread - Helper class for the basics of starting/managing persistent threads.
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// This class is meant to be a helper for the typical threading model of "start once and // This class is meant to be a helper for the typical threading model of "start once and
// reuse many times." This class incorporates a lot of extra overhead in stopping and // reuse many times." This class incorporates a lot of extra overhead in stopping and
// starting threads, but in turn provides most of the basic thread-safety and event-handling // starting threads, but in turn provides most of the basic thread-safety and event-handling
// functionality needed for a threaded operation. In practice this model is usually an // functionality needed for a threaded operation. In practice this model is usually an
// ideal one for efficiency since Operating Systems themselves typically subscribe to a // ideal one for efficiency since Operating Systems themselves typically subscribe to a
// design where sleeping, suspending, and resuming threads is very efficient, but starting // design where sleeping, suspending, and resuming threads is very efficient, but starting
// new threads has quite a bit of overhead. // new threads has quite a bit of overhead.
// //
// To use this as a base class for your threaded procedure, overload the following virtual // To use this as a base class for your threaded procedure, overload the following virtual
// methods: // methods:
// void OnStart(); // void OnStart();
// void ExecuteTaskInThread(); // void ExecuteTaskInThread();
// void OnCleanupInThread(); // void OnCleanupInThread();
// //
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use // Use the public methods Start() and Cancel() to start and shutdown the thread, and use
// m_sem_event internally to post/receive events for the thread (make a public accessor for // m_sem_event internally to post/receive events for the thread (make a public accessor for
// it in your derived class if your thread utilizes the post). // it in your derived class if your thread utilizes the post).
// //
// Notes: // Notes:
// * Constructing threads as static global vars isn't recommended since it can potentially // * Constructing threads as static global vars isn't recommended since it can potentially
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers // confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
// no dependency options for ensuring correct static var initializations). Use heap // no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead. // allocation to create thread objects instead.
// //
class pxThread class pxThread
{ {
DeclareNoncopyableObject(pxThread); DeclareNoncopyableObject(pxThread);
friend void pxYield(int ms); friend void pxYield(int ms);
protected: protected:
wxString m_name; // diagnostic name for our thread. wxString m_name; // diagnostic name for our thread.
pthread_t m_thread; pthread_t m_thread;
uptr m_native_id; // typically an id, but implementing platforms can do whatever. uptr m_native_id; // typically an id, but implementing platforms can do whatever.
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever. uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
Semaphore m_sem_event; // general wait event that's needed by most threads Semaphore m_sem_event; // general wait event that's needed by most threads
Semaphore m_sem_startup; // startup sync tool Semaphore m_sem_startup; // startup sync tool
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally. MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
Mutex m_mtx_ThreadName; Mutex m_mtx_ThreadName;
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc. std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
// exception handle, set non-NULL if the thread terminated with an exception // exception handle, set non-NULL if the thread terminated with an exception
// Use RethrowException() to re-throw the exception using its original exception type. // Use RethrowException() to re-throw the exception using its original exception type.
ScopedPtrMT<BaseException> m_except; ScopedPtrMT<BaseException> m_except;
EventSource<EventListener_Thread> m_evtsrc_OnDelete; EventSource<EventListener_Thread> m_evtsrc_OnDelete;
public: public:
virtual ~pxThread(); virtual ~pxThread();
pxThread(const wxString &name = L"pxThread"); pxThread(const wxString& name = L"pxThread");
pthread_t GetId() const { return m_thread; } pthread_t GetId() const { return m_thread; }
u64 GetCpuTime() const; u64 GetCpuTime() const;
virtual void Start(); virtual void Start();
virtual void Cancel(bool isBlocking = true); virtual void Cancel(bool isBlocking = true);
virtual bool Cancel(const wxTimeSpan &timeout); virtual bool Cancel(const wxTimeSpan& timeout);
virtual bool Detach(); virtual bool Detach();
virtual void Block(); virtual void Block();
virtual bool Block(const wxTimeSpan &timeout); virtual bool Block(const wxTimeSpan& timeout);
virtual void RethrowException() const; virtual void RethrowException() const;
void AddListener(EventListener_Thread &evt); void AddListener(EventListener_Thread& evt);
void AddListener(EventListener_Thread *evt) void AddListener(EventListener_Thread* evt)
{ {
if (evt == NULL) if (evt == NULL)
return; return;
AddListener(*evt); AddListener(*evt);
} }
void WaitOnSelf(Semaphore &mutex) const; void WaitOnSelf(Semaphore& mutex) const;
void WaitOnSelf(Mutex &mutex) const; void WaitOnSelf(Mutex& mutex) const;
bool WaitOnSelf(Semaphore &mutex, const wxTimeSpan &timeout) const; bool WaitOnSelf(Semaphore& mutex, const wxTimeSpan& timeout) const;
bool WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const; bool WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const;
bool IsRunning() const; bool IsRunning() const;
bool IsSelf() const; bool IsSelf() const;
bool HasPendingException() const { return !!m_except; } bool HasPendingException() const { return !!m_except; }
wxString GetName() const; wxString GetName() const;
void SetName(const wxString &newname); void SetName(const wxString& newname);
protected: protected:
// Extending classes should always implement your own OnStart(), which is called by // Extending classes should always implement your own OnStart(), which is called by
// Start() once necessary locks have been obtained. Do not override Start() directly // Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;) // unless you're really sure that's what you need to do. ;)
virtual void OnStart(); virtual void OnStart();
virtual void OnStartInThread(); virtual void OnStartInThread();
// This is called when the thread has been canceled or exits normally. The pxThread // This is called when the thread has been canceled or exits normally. The pxThread
// automatically binds it to the pthread cleanup routines as soon as the thread starts. // automatically binds it to the pthread cleanup routines as soon as the thread starts.
virtual void OnCleanupInThread(); virtual void OnCleanupInThread();
// Implemented by derived class to perform actual threaded task! // Implemented by derived class to perform actual threaded task!
virtual void ExecuteTaskInThread() = 0; virtual void ExecuteTaskInThread() = 0;
void TestCancel() const; void TestCancel() const;
// Yields this thread to other threads and checks for cancellation. A sleeping thread should // Yields this thread to other threads and checks for cancellation. A sleeping thread should
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep() // always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
// or better yet, disable cancellation of the thread completely with DisableCancellation(). // or better yet, disable cancellation of the thread completely with DisableCancellation().
// //
// Parameters: // Parameters:
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms // ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
// depending on operating system/platform). If ms is 0 or unspecified, then a single // depending on operating system/platform). If ms is 0 or unspecified, then a single
// timeslice is yielded to other contending threads. If no threads are contending for // timeslice is yielded to other contending threads. If no threads are contending for
// time when ms==0, then no yield is done, but cancellation is still tested. // time when ms==0, then no yield is done, but cancellation is still tested.
void Yield(int ms = 0) void Yield(int ms = 0)
{ {
pxAssert(IsSelf()); pxAssert(IsSelf());
Threading::Sleep(ms); Threading::Sleep(ms);
TestCancel(); TestCancel();
} }
void FrankenMutex(Mutex &mutex); void FrankenMutex(Mutex& mutex);
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const; bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const;
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const; bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Section of methods for internal use only. // Section of methods for internal use only.
void _platform_specific_OnStartInThread(); void _platform_specific_OnStartInThread();
void _platform_specific_OnCleanupInThread(); void _platform_specific_OnCleanupInThread();
bool _basecancel(); bool _basecancel();
void _selfRunningTest(const wxChar *name) const; void _selfRunningTest(const wxChar* name) const;
void _DoSetThreadName(const wxString &name); void _DoSetThreadName(const wxString& name);
void _DoSetThreadName(const char *name) { SetNameOfCurrentThread(name); } void _DoSetThreadName(const char* name) { SetNameOfCurrentThread(name); }
void _internal_execute(); void _internal_execute();
void _try_virtual_invoke(void (pxThread::*method)()); void _try_virtual_invoke(void (pxThread::*method)());
void _ThreadCleanup(); void _ThreadCleanup();
static void *_internal_callback(void *func); static void* _internal_callback(void* func);
static void internal_callback_helper(void *func); static void internal_callback_helper(void* func);
static void _pt_callback_cleanup(void *handle); static void _pt_callback_cleanup(void* handle);
}; };
} } // namespace Threading

View File

@ -20,37 +20,37 @@
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Threading::RwMutex::RwMutex() Threading::RwMutex::RwMutex()
{ {
pthread_rwlock_init(&m_rwlock, NULL); pthread_rwlock_init(&m_rwlock, NULL);
} }
Threading::RwMutex::~RwMutex() Threading::RwMutex::~RwMutex()
{ {
pthread_rwlock_destroy(&m_rwlock); pthread_rwlock_destroy(&m_rwlock);
} }
void Threading::RwMutex::AcquireRead() void Threading::RwMutex::AcquireRead()
{ {
pthread_rwlock_rdlock(&m_rwlock); pthread_rwlock_rdlock(&m_rwlock);
} }
void Threading::RwMutex::AcquireWrite() void Threading::RwMutex::AcquireWrite()
{ {
pthread_rwlock_wrlock(&m_rwlock); pthread_rwlock_wrlock(&m_rwlock);
} }
bool Threading::RwMutex::TryAcquireRead() bool Threading::RwMutex::TryAcquireRead()
{ {
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY; return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
} }
bool Threading::RwMutex::TryAcquireWrite() bool Threading::RwMutex::TryAcquireWrite()
{ {
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY; return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
} }
void Threading::RwMutex::Release() void Threading::RwMutex::Release()
{ {
pthread_rwlock_unlock(&m_rwlock); pthread_rwlock_unlock(&m_rwlock);
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -58,57 +58,57 @@ void Threading::RwMutex::Release()
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock() Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock()
{ {
if (m_IsLocked) if (m_IsLocked)
m_lock.Release(); m_lock.Release();
} }
// Provides manual unlocking of a scoped lock prior to object destruction. // Provides manual unlocking of a scoped lock prior to object destruction.
void Threading::BaseScopedReadWriteLock::Release() void Threading::BaseScopedReadWriteLock::Release()
{ {
if (!m_IsLocked) if (!m_IsLocked)
return; return;
m_IsLocked = false; m_IsLocked = false;
m_lock.Release(); m_lock.Release();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ScopedReadLock / ScopedWriteLock // ScopedReadLock / ScopedWriteLock
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
Threading::ScopedReadLock::ScopedReadLock(RwMutex &locker) Threading::ScopedReadLock::ScopedReadLock(RwMutex& locker)
: BaseScopedReadWriteLock(locker) : BaseScopedReadWriteLock(locker)
{ {
m_IsLocked = true; m_IsLocked = true;
m_lock.AcquireRead(); m_lock.AcquireRead();
} }
// provides manual locking of a scoped lock, to re-lock after a manual unlocking. // provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedReadLock::Acquire() void Threading::ScopedReadLock::Acquire()
{ {
if (m_IsLocked) if (m_IsLocked)
return; return;
m_lock.AcquireRead(); m_lock.AcquireRead();
m_IsLocked = true; m_IsLocked = true;
} }
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker) Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker)
: BaseScopedReadWriteLock(locker) : BaseScopedReadWriteLock(locker)
{ {
m_IsLocked = true; m_IsLocked = true;
m_lock.AcquireWrite(); m_lock.AcquireWrite();
} }
// provides manual locking of a scoped lock, to re-lock after a manual unlocking. // provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedWriteLock::Acquire() void Threading::ScopedWriteLock::Acquire()
{ {
if (m_IsLocked) if (m_IsLocked)
return; return;
m_lock.AcquireWrite(); m_lock.AcquireWrite();
m_IsLocked = true; m_IsLocked = true;
} }
// Special constructor used by ScopedTryLock // Special constructor used by ScopedTryLock
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker, bool isTryLock) Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker, bool isTryLock)
: BaseScopedReadWriteLock(locker) : BaseScopedReadWriteLock(locker)
{ {
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false; //m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
} }

View File

@ -19,72 +19,72 @@
namespace Threading namespace Threading
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// RwMutex // RwMutex
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class RwMutex class RwMutex
{ {
DeclareNoncopyableObject(RwMutex); DeclareNoncopyableObject(RwMutex);
protected: protected:
pthread_rwlock_t m_rwlock; pthread_rwlock_t m_rwlock;
public: public:
RwMutex(); RwMutex();
virtual ~RwMutex(); virtual ~RwMutex();
virtual void AcquireRead(); virtual void AcquireRead();
virtual void AcquireWrite(); virtual void AcquireWrite();
virtual bool TryAcquireRead(); virtual bool TryAcquireRead();
virtual bool TryAcquireWrite(); virtual bool TryAcquireWrite();
virtual void Release(); virtual void Release();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseScopedReadWriteLock // BaseScopedReadWriteLock
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class BaseScopedReadWriteLock class BaseScopedReadWriteLock
{ {
DeclareNoncopyableObject(BaseScopedReadWriteLock); DeclareNoncopyableObject(BaseScopedReadWriteLock);
protected: protected:
RwMutex &m_lock; RwMutex& m_lock;
bool m_IsLocked; bool m_IsLocked;
public: public:
BaseScopedReadWriteLock(RwMutex &locker) BaseScopedReadWriteLock(RwMutex& locker)
: m_lock(locker) : m_lock(locker)
{ {
} }
virtual ~BaseScopedReadWriteLock(); virtual ~BaseScopedReadWriteLock();
void Release(); void Release();
bool IsLocked() const { return m_IsLocked; } bool IsLocked() const { return m_IsLocked; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ScopedReadLock / ScopedWriteLock // ScopedReadLock / ScopedWriteLock
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class ScopedReadLock : public BaseScopedReadWriteLock class ScopedReadLock : public BaseScopedReadWriteLock
{ {
public: public:
ScopedReadLock(RwMutex &locker); ScopedReadLock(RwMutex& locker);
virtual ~ScopedReadLock() = default; virtual ~ScopedReadLock() = default;
void Acquire(); void Acquire();
}; };
class ScopedWriteLock : public BaseScopedReadWriteLock class ScopedWriteLock : public BaseScopedReadWriteLock
{ {
public: public:
ScopedWriteLock(RwMutex &locker); ScopedWriteLock(RwMutex& locker);
virtual ~ScopedWriteLock() = default; virtual ~ScopedWriteLock() = default;
void Acquire(); void Acquire();
protected: protected:
ScopedWriteLock(RwMutex &locker, bool isTryLock); ScopedWriteLock(RwMutex& locker, bool isTryLock);
}; };
} } // namespace Threading

View File

@ -26,7 +26,7 @@
// Microsoft Windows only macro, useful for freeing out COM objects: // Microsoft Windows only macro, useful for freeing out COM objects:
#define safe_release(ptr) \ #define safe_release(ptr) \
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL)) ((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SafeArray // SafeArray
@ -37,72 +37,72 @@
template <typename T> template <typename T>
class SafeArray class SafeArray
{ {
DeclareNoncopyableObject(SafeArray); DeclareNoncopyableObject(SafeArray);
public: public:
static const int DefaultChunkSize = 0x1000 * sizeof(T); static const int DefaultChunkSize = 0x1000 * sizeof(T);
public: public:
wxString Name; // user-assigned block name wxString Name; // user-assigned block name
int ChunkSize; int ChunkSize;
protected: protected:
T *m_ptr; T* m_ptr;
int m_size; // size of the allocation of memory int m_size; // size of the allocation of memory
protected: protected:
SafeArray(const wxChar *name, T *allocated_mem, int initSize); SafeArray(const wxChar* name, T* allocated_mem, int initSize);
virtual T *_virtual_realloc(int newsize); virtual T* _virtual_realloc(int newsize);
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug // A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
// builds only -- no bounds checking is done in release builds). // builds only -- no bounds checking is done in release builds).
T *_getPtr(uint i) const; T* _getPtr(uint i) const;
public: public:
virtual ~SafeArray(); virtual ~SafeArray();
explicit SafeArray(const wxChar *name = L"Unnamed"); explicit SafeArray(const wxChar* name = L"Unnamed");
explicit SafeArray(int initialSize, const wxChar *name = L"Unnamed"); explicit SafeArray(int initialSize, const wxChar* name = L"Unnamed");
void Dispose(); void Dispose();
void ExactAlloc(int newsize); void ExactAlloc(int newsize);
void MakeRoomFor(int newsize) void MakeRoomFor(int newsize)
{ {
if (newsize > m_size) if (newsize > m_size)
ExactAlloc(newsize); ExactAlloc(newsize);
} }
bool IsDisposed() const { return (m_ptr == NULL); } bool IsDisposed() const { return (m_ptr == NULL); }
// Returns the size of the memory allocation, as according to the array type. // Returns the size of the memory allocation, as according to the array type.
int GetLength() const { return m_size; } int GetLength() const { return m_size; }
// Returns the size of the memory allocation in bytes. // Returns the size of the memory allocation in bytes.
int GetSizeInBytes() const { return m_size * sizeof(T); } int GetSizeInBytes() const { return m_size * sizeof(T); }
// Extends the containment area of the array. Extensions are performed // Extends the containment area of the array. Extensions are performed
// in chunks. // in chunks.
void GrowBy(int items) void GrowBy(int items)
{ {
MakeRoomFor(m_size + ChunkSize + items + 1); MakeRoomFor(m_size + ChunkSize + items + 1);
} }
// Gets a pointer to the requested allocation index. // Gets a pointer to the requested allocation index.
// DevBuilds : Generates assertion if the index is invalid. // DevBuilds : Generates assertion if the index is invalid.
T *GetPtr(uint idx = 0) { return _getPtr(idx); } T* GetPtr(uint idx = 0) { return _getPtr(idx); }
const T *GetPtr(uint idx = 0) const { return _getPtr(idx); } const T* GetPtr(uint idx = 0) const { return _getPtr(idx); }
// Gets a pointer to the element directly after the last element in the array. // Gets a pointer to the element directly after the last element in the array.
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids* // This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
// the out-of-bounds assertion check that typically occurs when you do that. :) // the out-of-bounds assertion check that typically occurs when you do that. :)
T *GetPtrEnd() { return &m_ptr[m_size]; } T* GetPtrEnd() { return &m_ptr[m_size]; }
const T *GetPtrEnd() const { return &m_ptr[m_size]; } const T* GetPtrEnd() const { return &m_ptr[m_size]; }
// Gets an element of this memory allocation much as if it were an array. // Gets an element of this memory allocation much as if it were an array.
// DevBuilds : Generates assertion if the index is invalid. // DevBuilds : Generates assertion if the index is invalid.
T &operator[](int idx) { return *_getPtr((uint)idx); } T& operator[](int idx) { return *_getPtr((uint)idx); }
const T &operator[](int idx) const { return *_getPtr((uint)idx); } const T& operator[](int idx) const { return *_getPtr((uint)idx); }
virtual SafeArray<T> *Clone() const; virtual SafeArray<T>* Clone() const;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -118,73 +118,73 @@ public:
template <typename T> template <typename T>
class SafeList class SafeList
{ {
DeclareNoncopyableObject(SafeList); DeclareNoncopyableObject(SafeList);
public: public:
static const int DefaultChunkSize = 0x80 * sizeof(T); static const int DefaultChunkSize = 0x80 * sizeof(T);
public: public:
wxString Name; // user-assigned block name wxString Name; // user-assigned block name
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time. int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
protected: protected:
T *m_ptr; T* m_ptr;
int m_allocsize; // size of the allocation of memory int m_allocsize; // size of the allocation of memory
uint m_length; // length of the array (active items, not buffer allocation) uint m_length; // length of the array (active items, not buffer allocation)
protected: protected:
virtual T *_virtual_realloc(int newsize); virtual T* _virtual_realloc(int newsize);
void _MakeRoomFor_threshold(int newsize); void _MakeRoomFor_threshold(int newsize);
T *_getPtr(uint i) const; T* _getPtr(uint i) const;
public: public:
virtual ~SafeList(); virtual ~SafeList();
explicit SafeList(const wxChar *name = L"Unnamed"); explicit SafeList(const wxChar* name = L"Unnamed");
explicit SafeList(int initialSize, const wxChar *name = L"Unnamed"); explicit SafeList(int initialSize, const wxChar* name = L"Unnamed");
virtual SafeList<T> *Clone() const; virtual SafeList<T>* Clone() const;
void Remove(int index); void Remove(int index);
void MakeRoomFor(int blockSize); void MakeRoomFor(int blockSize);
T &New(); T& New();
int Add(const T &src); int Add(const T& src);
T &AddNew(const T &src); T& AddNew(const T& src);
// Returns the size of the list, as according to the array type. This includes // Returns the size of the list, as according to the array type. This includes
// mapped items only. The actual size of the allocation may differ. // mapped items only. The actual size of the allocation may differ.
int GetLength() const { return m_length; } int GetLength() const { return m_length; }
// Returns the size of the list, in bytes. This includes mapped items only. // Returns the size of the list, in bytes. This includes mapped items only.
// The actual size of the allocation may differ. // The actual size of the allocation may differ.
int GetSizeInBytes() const { return m_length * sizeof(T); } int GetSizeInBytes() const { return m_length * sizeof(T); }
void MatchLengthToAllocatedSize() void MatchLengthToAllocatedSize()
{ {
m_length = m_allocsize; m_length = m_allocsize;
} }
void GrowBy(int items) void GrowBy(int items)
{ {
MakeRoomFor(m_length + ChunkSize + items + 1); MakeRoomFor(m_length + ChunkSize + items + 1);
} }
// Sets the item length to zero. Does not free memory allocations. // Sets the item length to zero. Does not free memory allocations.
void Clear() void Clear()
{ {
m_length = 0; m_length = 0;
} }
// Gets an element of this memory allocation much as if it were an array. // Gets an element of this memory allocation much as if it were an array.
// DevBuilds : Generates assertion if the index is invalid. // DevBuilds : Generates assertion if the index is invalid.
T &operator[](int idx) { return *_getPtr((uint)idx); } T& operator[](int idx) { return *_getPtr((uint)idx); }
const T &operator[](int idx) const { return *_getPtr((uint)idx); } const T& operator[](int idx) const { return *_getPtr((uint)idx); }
T *GetPtr() { return m_ptr; } T* GetPtr() { return m_ptr; }
const T *GetPtr() const { return m_ptr; } const T* GetPtr() const { return m_ptr; }
T &GetLast() { return m_ptr[m_length - 1]; } T& GetLast() { return m_ptr[m_length - 1]; }
const T &GetLast() const { return m_ptr[m_length - 1]; } const T& GetLast() const { return m_ptr[m_length - 1]; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -197,21 +197,21 @@ public:
template <typename T, uint Alignment> template <typename T, uint Alignment>
class SafeAlignedArray : public SafeArray<T> class SafeAlignedArray : public SafeArray<T>
{ {
typedef SafeArray<T> _parent; typedef SafeArray<T> _parent;
protected: protected:
T *_virtual_realloc(int newsize); T* _virtual_realloc(int newsize);
public: public:
using _parent::operator[]; using _parent::operator[];
virtual ~SafeAlignedArray(); virtual ~SafeAlignedArray();
explicit SafeAlignedArray(const wxChar *name = L"Unnamed") explicit SafeAlignedArray(const wxChar* name = L"Unnamed")
: SafeArray<T>::SafeArray(name) : SafeArray<T>::SafeArray(name)
{ {
} }
explicit SafeAlignedArray(int initialSize, const wxChar *name = L"Unnamed"); explicit SafeAlignedArray(int initialSize, const wxChar* name = L"Unnamed");
virtual SafeAlignedArray<T, Alignment> *Clone() const; virtual SafeAlignedArray<T, Alignment>* Clone() const;
}; };

View File

@ -23,79 +23,80 @@
// Throws: // Throws:
// Exception::OutOfMemory if the allocated_mem pointer is NULL. // Exception::OutOfMemory if the allocated_mem pointer is NULL.
template <typename T> template <typename T>
SafeArray<T>::SafeArray(const wxChar *name, T *allocated_mem, int initSize) SafeArray<T>::SafeArray(const wxChar* name, T* allocated_mem, int initSize)
: Name(name) : Name(name)
{ {
ChunkSize = DefaultChunkSize; ChunkSize = DefaultChunkSize;
m_ptr = allocated_mem; m_ptr = allocated_mem;
m_size = initSize; m_size = initSize;
if (m_ptr == NULL) if (m_ptr == NULL)
throw Exception::OutOfMemory(name) throw Exception::OutOfMemory(name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize)); .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
} }
template <typename T> template <typename T>
T *SafeArray<T>::_virtual_realloc(int newsize) T* SafeArray<T>::_virtual_realloc(int newsize)
{ {
T *retval = (T *)((m_ptr == NULL) ? T* retval = (T*)((m_ptr == NULL) ?
malloc(newsize * sizeof(T)) : malloc(newsize * sizeof(T)) :
realloc(m_ptr, newsize * sizeof(T))); realloc(m_ptr, newsize * sizeof(T)));
if (IsDebugBuild && (retval != NULL)) { if (IsDebugBuild && (retval != NULL))
// Zero everything out to 0xbaadf00d, so that its obviously uncleared {
// to a debuggee // Zero everything out to 0xbaadf00d, so that its obviously uncleared
// to a debuggee
u32 *fill = (u32 *)&retval[m_size]; u32* fill = (u32*)&retval[m_size];
const u32 *end = (u32 *)((((uptr)&retval[newsize - 1]) - 3) & ~0x3); const u32* end = (u32*)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
for (; fill < end; ++fill) for (; fill < end; ++fill)
*fill = 0xbaadf00d; *fill = 0xbaadf00d;
} }
return retval; return retval;
} }
template <typename T> template <typename T>
SafeArray<T>::~SafeArray() SafeArray<T>::~SafeArray()
{ {
safe_free(m_ptr); safe_free(m_ptr);
} }
template <typename T> template <typename T>
SafeArray<T>::SafeArray(const wxChar *name) SafeArray<T>::SafeArray(const wxChar* name)
: Name(name) : Name(name)
{ {
ChunkSize = DefaultChunkSize; ChunkSize = DefaultChunkSize;
m_ptr = NULL; m_ptr = NULL;
m_size = 0; m_size = 0;
} }
template <typename T> template <typename T>
SafeArray<T>::SafeArray(int initialSize, const wxChar *name) SafeArray<T>::SafeArray(int initialSize, const wxChar* name)
: Name(name) : Name(name)
{ {
ChunkSize = DefaultChunkSize; ChunkSize = DefaultChunkSize;
m_ptr = (initialSize == 0) ? NULL : (T *)malloc(initialSize * sizeof(T)); m_ptr = (initialSize == 0) ? NULL : (T*)malloc(initialSize * sizeof(T));
m_size = initialSize; m_size = initialSize;
if ((initialSize != 0) && (m_ptr == NULL)) if ((initialSize != 0) && (m_ptr == NULL))
throw Exception::OutOfMemory(name) throw Exception::OutOfMemory(name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize)); .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
} }
// Clears the contents of the array to zero, and frees all memory allocations. // Clears the contents of the array to zero, and frees all memory allocations.
template <typename T> template <typename T>
void SafeArray<T>::Dispose() void SafeArray<T>::Dispose()
{ {
m_size = 0; m_size = 0;
safe_free(m_ptr); safe_free(m_ptr);
} }
template <typename T> template <typename T>
T *SafeArray<T>::_getPtr(uint i) const T* SafeArray<T>::_getPtr(uint i) const
{ {
IndexBoundsAssumeDev(WX_STR(Name), i, m_size); IndexBoundsAssumeDev(WX_STR(Name), i, m_size);
return &m_ptr[i]; return &m_ptr[i];
} }
// reallocates the array to the explicit size. Can be used to shrink or grow an // reallocates the array to the explicit size. Can be used to shrink or grow an
@ -103,23 +104,23 @@ T *SafeArray<T>::_getPtr(uint i) const
template <typename T> template <typename T>
void SafeArray<T>::ExactAlloc(int newsize) void SafeArray<T>::ExactAlloc(int newsize)
{ {
if (newsize == m_size) if (newsize == m_size)
return; return;
m_ptr = _virtual_realloc(newsize); m_ptr = _virtual_realloc(newsize);
if (m_ptr == NULL) if (m_ptr == NULL)
throw Exception::OutOfMemory(Name) throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize)); .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
m_size = newsize; m_size = newsize;
} }
template <typename T> template <typename T>
SafeArray<T> *SafeArray<T>::Clone() const SafeArray<T>* SafeArray<T>::Clone() const
{ {
SafeArray<T> *retval = new SafeArray<T>(m_size); SafeArray<T>* retval = new SafeArray<T>(m_size);
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size); memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
return retval; return retval;
} }
@ -128,11 +129,11 @@ SafeArray<T> *SafeArray<T>::Clone() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
template <typename T, uint Alignment> template <typename T, uint Alignment>
T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize) T* SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
{ {
return (T *)((this->m_ptr == NULL) ? return (T*)((this->m_ptr == NULL) ?
_aligned_malloc(newsize * sizeof(T), Alignment) : _aligned_malloc(newsize * sizeof(T), Alignment) :
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T))); pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
} }
// Appends "(align: xx)" to the name of the allocation in devel builds. // Appends "(align: xx)" to the name of the allocation in devel builds.
@ -141,25 +142,25 @@ T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
template <typename T, uint Alignment> template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment>::~SafeAlignedArray() SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
{ {
safe_aligned_free(this->m_ptr); safe_aligned_free(this->m_ptr);
// mptr is set to null, so the parent class's destructor won't re-free it. // mptr is set to null, so the parent class's destructor won't re-free it.
} }
template <typename T, uint Alignment> template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar *name) SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar* name)
: SafeArray<T>::SafeArray( : SafeArray<T>::SafeArray(
name, name,
(T *)_aligned_malloc(initialSize * sizeof(T), Alignment), (T*)_aligned_malloc(initialSize * sizeof(T), Alignment),
initialSize) initialSize)
{ {
} }
template <typename T, uint Alignment> template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const SafeAlignedArray<T, Alignment>* SafeAlignedArray<T, Alignment>::Clone() const
{ {
SafeAlignedArray<T, Alignment> *retval = new SafeAlignedArray<T, Alignment>(this->m_size); SafeAlignedArray<T, Alignment>* retval = new SafeAlignedArray<T, Alignment>(this->m_size);
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size); memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
return retval; return retval;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -167,50 +168,51 @@ SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
template <typename T> template <typename T>
T *SafeList<T>::_virtual_realloc(int newsize) T* SafeList<T>::_virtual_realloc(int newsize)
{ {
return (T *)realloc(m_ptr, newsize * sizeof(T)); return (T*)realloc(m_ptr, newsize * sizeof(T));
} }
template <typename T> template <typename T>
SafeList<T>::~SafeList() SafeList<T>::~SafeList()
{ {
safe_free(m_ptr); safe_free(m_ptr);
} }
template <typename T> template <typename T>
SafeList<T>::SafeList(const wxChar *name) SafeList<T>::SafeList(const wxChar* name)
: Name(name) : Name(name)
{ {
ChunkSize = DefaultChunkSize; ChunkSize = DefaultChunkSize;
m_ptr = NULL; m_ptr = NULL;
m_allocsize = 0; m_allocsize = 0;
m_length = 0; m_length = 0;
} }
template <typename T> template <typename T>
SafeList<T>::SafeList(int initialSize, const wxChar *name) SafeList<T>::SafeList(int initialSize, const wxChar* name)
: Name(name) : Name(name)
{ {
ChunkSize = DefaultChunkSize; ChunkSize = DefaultChunkSize;
m_allocsize = initialSize; m_allocsize = initialSize;
m_length = 0; m_length = 0;
m_ptr = (T *)malloc(initialSize * sizeof(T)); m_ptr = (T*)malloc(initialSize * sizeof(T));
if (m_ptr == NULL) if (m_ptr == NULL)
throw Exception::OutOfMemory(Name) throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length)); .SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
for (int i = 0; i < m_allocsize; ++i) { for (int i = 0; i < m_allocsize; ++i)
new (&m_ptr[i]) T(); {
} new (&m_ptr[i]) T();
}
} }
template <typename T> template <typename T>
T *SafeList<T>::_getPtr(uint i) const T* SafeList<T>::_getPtr(uint i) const
{ {
IndexBoundsAssumeDev(WX_STR(Name), i, m_length); IndexBoundsAssumeDev(WX_STR(Name), i, m_length);
return &m_ptr[i]; return &m_ptr[i];
} }
// Ensures that the allocation is large enough to fit data of the // Ensures that the allocation is large enough to fit data of the
@ -218,42 +220,44 @@ T *SafeList<T>::_getPtr(uint i) const
template <typename T> template <typename T>
void SafeList<T>::MakeRoomFor(int blockSize) void SafeList<T>::MakeRoomFor(int blockSize)
{ {
if (blockSize > m_allocsize) { if (blockSize > m_allocsize)
const int newalloc = blockSize + ChunkSize; {
m_ptr = _virtual_realloc(newalloc); const int newalloc = blockSize + ChunkSize;
if (m_ptr == NULL) m_ptr = _virtual_realloc(newalloc);
throw Exception::OutOfMemory(Name) if (m_ptr == NULL)
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize)); throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
for (; m_allocsize < newalloc; ++m_allocsize) { for (; m_allocsize < newalloc; ++m_allocsize)
new (&m_ptr[m_allocsize]) T(); {
} new (&m_ptr[m_allocsize]) T();
} }
}
} }
// Appends an item to the end of the list and returns a handle to it. // Appends an item to the end of the list and returns a handle to it.
template <typename T> template <typename T>
T &SafeList<T>::New() T& SafeList<T>::New()
{ {
_MakeRoomFor_threshold(m_length + 1); _MakeRoomFor_threshold(m_length + 1);
return m_ptr[m_length++]; return m_ptr[m_length++];
} }
template <typename T> template <typename T>
int SafeList<T>::Add(const T &src) int SafeList<T>::Add(const T& src)
{ {
_MakeRoomFor_threshold(m_length + 1); _MakeRoomFor_threshold(m_length + 1);
m_ptr[m_length] = src; m_ptr[m_length] = src;
return m_length++; return m_length++;
} }
// Same as Add, but returns the handle of the new object instead of it's array index. // Same as Add, but returns the handle of the new object instead of it's array index.
template <typename T> template <typename T>
T &SafeList<T>::AddNew(const T &src) T& SafeList<T>::AddNew(const T& src)
{ {
_MakeRoomFor_threshold(m_length + 1); _MakeRoomFor_threshold(m_length + 1);
m_ptr[m_length] = src; m_ptr[m_length] = src;
return m_ptr[m_length]; return m_ptr[m_length];
} }
// Performs a standard array-copy removal of the given item. All items past the // Performs a standard array-copy removal of the given item. All items past the
@ -262,23 +266,23 @@ T &SafeList<T>::AddNew(const T &src)
template <typename T> template <typename T>
void SafeList<T>::Remove(int index) void SafeList<T>::Remove(int index)
{ {
IndexBoundsAssumeDev(Name.c_str(), index, m_length); IndexBoundsAssumeDev(Name.c_str(), index, m_length);
int copylen = m_length - index; int copylen = m_length - index;
if (copylen > 0) if (copylen > 0)
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen); memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
} }
template <typename T> template <typename T>
SafeList<T> *SafeList<T>::Clone() const SafeList<T>* SafeList<T>::Clone() const
{ {
SafeList<T> *retval = new SafeList<T>(m_length); SafeList<T>* retval = new SafeList<T>(m_length);
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length); memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
return retval; return retval;
} }
template <typename T> template <typename T>
void SafeList<T>::_MakeRoomFor_threshold(int newsize) void SafeList<T>::_MakeRoomFor_threshold(int newsize)
{ {
MakeRoomFor(newsize + ChunkSize); MakeRoomFor(newsize + ChunkSize);
} }

View File

@ -28,34 +28,34 @@
// pointer to null after deallocation. // pointer to null after deallocation.
#define safe_delete(ptr) \ #define safe_delete(ptr) \
((void)(delete (ptr)), (ptr) = NULL) ((void)(delete (ptr)), (ptr) = NULL)
#define safe_delete_array(ptr) \ #define safe_delete_array(ptr) \
((void)(delete[](ptr)), (ptr) = NULL) ((void)(delete[](ptr)), (ptr) = NULL)
// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on // No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on
// just about every compiler and libc implementation of any recentness. // just about every compiler and libc implementation of any recentness.
#define safe_free(ptr) \ #define safe_free(ptr) \
((void)(free(ptr), !!0), (ptr) = NULL) ((void)(free(ptr), !!0), (ptr) = NULL)
//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL)) //((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
#define safe_fclose(ptr) \ #define safe_fclose(ptr) \
((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL)) ((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL))
// Implementation note: all known implementations of _aligned_free check the pointer for // Implementation note: all known implementations of _aligned_free check the pointer for
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to // NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
// do it here. // do it here.
#define safe_aligned_free(ptr) \ #define safe_aligned_free(ptr) \
((void)(_aligned_free(ptr), (ptr) = NULL)) ((void)(_aligned_free(ptr), (ptr) = NULL))
// aligned_malloc: Implement/declare linux equivalents here! // aligned_malloc: Implement/declare linux equivalents here!
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
extern void *__fastcall _aligned_malloc(size_t size, size_t align); extern void* __fastcall _aligned_malloc(size_t size, size_t align);
extern void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size); extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size);
extern void _aligned_free(void *pmem); extern void _aligned_free(void* pmem);
#else #else
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \ #define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
_aligned_realloc(handle, new_size, align) _aligned_realloc(handle, new_size, align)
#endif #endif
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -63,7 +63,7 @@ extern void _aligned_free(void *pmem);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
typedef void FnType_OutOfMemory(uptr blocksize); typedef void FnType_OutOfMemory(uptr blocksize);
typedef FnType_OutOfMemory *Fnptr_OutOfMemory; typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
// This method is meant to be assigned by applications that link against pxWex. It is called // This method is meant to be assigned by applications that link against pxWex. It is called
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be // (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
@ -93,74 +93,74 @@ template <typename T>
class BaseScopedAlloc class BaseScopedAlloc
{ {
protected: protected:
T *m_buffer; T* m_buffer;
uint m_size; uint m_size;
public: public:
BaseScopedAlloc() BaseScopedAlloc()
{ {
m_buffer = NULL; m_buffer = NULL;
m_size = 0; m_size = 0;
} }
virtual ~BaseScopedAlloc() virtual ~BaseScopedAlloc()
{ {
//pxAssert(m_buffer==NULL); //pxAssert(m_buffer==NULL);
} }
public: public:
size_t GetSize() const { return m_size; } size_t GetSize() const { return m_size; }
size_t GetLength() const { return m_size; } size_t GetLength() const { return m_size; }
// Allocates the object to the specified size. If an existing allocation is in // Allocates the object to the specified size. If an existing allocation is in
// place, it is freed and replaced with the new allocation, and all data is lost. // place, it is freed and replaced with the new allocation, and all data is lost.
// Parameter: // Parameter:
// newSize - size of the new allocation, in elements (not bytes!). If the specified // newSize - size of the new allocation, in elements (not bytes!). If the specified
// size is 0, the the allocation is freed, same as calling Free(). // size is 0, the the allocation is freed, same as calling Free().
virtual void Alloc(size_t newsize) = 0; virtual void Alloc(size_t newsize) = 0;
// Re-sizes the allocation to the requested size, without any data loss. // Re-sizes the allocation to the requested size, without any data loss.
// Parameter: // Parameter:
// newSize - size of the new allocation, in elements (not bytes!). If the specified // newSize - size of the new allocation, in elements (not bytes!). If the specified
// size is 0, the the allocation is freed, same as calling Free(). // size is 0, the the allocation is freed, same as calling Free().
virtual void Resize(size_t newsize) = 0; virtual void Resize(size_t newsize) = 0;
void Free() void Free()
{ {
Alloc(0); Alloc(0);
} }
// Makes enough room for the requested size. Existing data in the array is retained. // Makes enough room for the requested size. Existing data in the array is retained.
void MakeRoomFor(uint size) void MakeRoomFor(uint size)
{ {
if (size <= m_size) if (size <= m_size)
return; return;
Resize(size); Resize(size);
} }
T *GetPtr(uint idx = 0) const T* GetPtr(uint idx = 0) const
{ {
#if pxUSE_SECURE_MALLOC #if pxUSE_SECURE_MALLOC
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size); IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#endif #endif
return &m_buffer[idx]; return &m_buffer[idx];
} }
T &operator[](uint idx) T& operator[](uint idx)
{ {
#if pxUSE_SECURE_MALLOC #if pxUSE_SECURE_MALLOC
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size); IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#endif #endif
return m_buffer[idx]; return m_buffer[idx];
} }
const T &operator[](uint idx) const const T& operator[](uint idx) const
{ {
#if pxUSE_SECURE_MALLOC #if pxUSE_SECURE_MALLOC
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size); IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#endif #endif
return m_buffer[idx]; return m_buffer[idx];
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -175,42 +175,42 @@ public:
template <typename T> template <typename T>
class ScopedAlloc : public BaseScopedAlloc<T> class ScopedAlloc : public BaseScopedAlloc<T>
{ {
typedef BaseScopedAlloc<T> _parent; typedef BaseScopedAlloc<T> _parent;
public: public:
ScopedAlloc(size_t size = 0) ScopedAlloc(size_t size = 0)
: _parent() : _parent()
{ {
Alloc(size); Alloc(size);
} }
virtual ~ScopedAlloc() virtual ~ScopedAlloc()
{ {
safe_free(this->m_buffer); safe_free(this->m_buffer);
} }
virtual void Alloc(size_t newsize) virtual void Alloc(size_t newsize)
{ {
safe_free(this->m_buffer); safe_free(this->m_buffer);
this->m_size = newsize; this->m_size = newsize;
if (!this->m_size) if (!this->m_size)
return; return;
this->m_buffer = (T *)malloc(this->m_size * sizeof(T)); this->m_buffer = (T*)malloc(this->m_size * sizeof(T));
if (!this->m_buffer) if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc"); throw Exception::OutOfMemory(L"ScopedAlloc");
} }
virtual void Resize(size_t newsize) virtual void Resize(size_t newsize)
{ {
this->m_size = newsize; this->m_size = newsize;
this->m_buffer = (T *)realloc(this->m_buffer, this->m_size * sizeof(T)); this->m_buffer = (T*)realloc(this->m_buffer, this->m_size * sizeof(T));
if (!this->m_buffer) if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc::Resize"); throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
} }
using _parent::operator[]; using _parent::operator[];
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -225,40 +225,40 @@ public:
template <typename T, uint align> template <typename T, uint align>
class ScopedAlignedAlloc : public BaseScopedAlloc<T> class ScopedAlignedAlloc : public BaseScopedAlloc<T>
{ {
typedef BaseScopedAlloc<T> _parent; typedef BaseScopedAlloc<T> _parent;
public: public:
ScopedAlignedAlloc(size_t size = 0) ScopedAlignedAlloc(size_t size = 0)
: _parent() : _parent()
{ {
Alloc(size); Alloc(size);
} }
virtual ~ScopedAlignedAlloc() virtual ~ScopedAlignedAlloc()
{ {
safe_aligned_free(this->m_buffer); safe_aligned_free(this->m_buffer);
} }
virtual void Alloc(size_t newsize) virtual void Alloc(size_t newsize)
{ {
safe_aligned_free(this->m_buffer); safe_aligned_free(this->m_buffer);
this->m_size = newsize; this->m_size = newsize;
if (!this->m_size) if (!this->m_size)
return; return;
this->m_buffer = (T *)_aligned_malloc(this->m_size * sizeof(T), align); this->m_buffer = (T*)_aligned_malloc(this->m_size * sizeof(T), align);
if (!this->m_buffer) if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc"); throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
} }
virtual void Resize(size_t newsize) virtual void Resize(size_t newsize)
{ {
this->m_buffer = (T *)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T)); this->m_buffer = (T*)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T));
this->m_size = newsize; this->m_size = newsize;
if (!this->m_buffer) if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize"); throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
} }
using _parent::operator[]; using _parent::operator[];
}; };

View File

@ -25,91 +25,91 @@ using Threading::ScopedLock;
template <typename T> template <typename T>
class ScopedPtrMT class ScopedPtrMT
{ {
DeclareNoncopyableObject(ScopedPtrMT); DeclareNoncopyableObject(ScopedPtrMT);
protected: protected:
std::atomic<T *> m_ptr; std::atomic<T*> m_ptr;
Threading::Mutex m_mtx; Threading::Mutex m_mtx;
public: public:
typedef T element_type; typedef T element_type;
wxEXPLICIT ScopedPtrMT(T *ptr = nullptr) wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
{ {
m_ptr = ptr; m_ptr = ptr;
} }
~ScopedPtrMT() { _Delete_unlocked(); } ~ScopedPtrMT() { _Delete_unlocked(); }
ScopedPtrMT &Reassign(T *ptr = nullptr) ScopedPtrMT& Reassign(T* ptr = nullptr)
{ {
T *doh = m_ptr.exchange(ptr); T* doh = m_ptr.exchange(ptr);
if (ptr != doh) if (ptr != doh)
delete doh; delete doh;
return *this; return *this;
} }
ScopedPtrMT &Delete() noexcept ScopedPtrMT& Delete() noexcept
{ {
ScopedLock lock(m_mtx); ScopedLock lock(m_mtx);
_Delete_unlocked(); _Delete_unlocked();
} }
// Removes the pointer from scoped management, but does not delete! // Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method) // (ScopedPtr will be nullptr after this method)
T *DetachPtr() T* DetachPtr()
{ {
ScopedLock lock(m_mtx); ScopedLock lock(m_mtx);
return m_ptr.exchange(nullptr); return m_ptr.exchange(nullptr);
} }
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT // Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
// has no object in management. // has no object in management.
T *GetPtr() const T* GetPtr() const
{ {
return m_ptr; return m_ptr;
} }
void SwapPtr(ScopedPtrMT &other) void SwapPtr(ScopedPtrMT& other)
{ {
ScopedLock lock(m_mtx); ScopedLock lock(m_mtx);
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load())); m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
T *const tmp = other.m_ptr; T* const tmp = other.m_ptr;
other.m_ptr = m_ptr; other.m_ptr = m_ptr;
m_ptr = tmp; m_ptr = tmp;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ScopedPtrMT Operators // ScopedPtrMT Operators
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// I've decided to use the ATL's approach to pointer validity tests, opposed to // I've decided to use the ATL's approach to pointer validity tests, opposed to
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't // the wx/boost approach (which uses some bizarre member method pointer crap, and can't
// allow the T* implicit casting. // allow the T* implicit casting.
bool operator!() const noexcept bool operator!() const noexcept
{ {
return m_ptr.load() == nullptr; return m_ptr.load() == nullptr;
} }
// Equality // Equality
bool operator==(T *pT) const noexcept bool operator==(T* pT) const noexcept
{ {
return m_ptr == pT; return m_ptr == pT;
} }
// Inequality // Inequality
bool operator!=(T *pT) const noexcept bool operator!=(T* pT) const noexcept
{ {
return !operator==(pT); return !operator==(pT);
} }
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion // Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer. // of the managed pointer.
ScopedPtrMT &operator=(T *src) ScopedPtrMT& operator=(T* src)
{ {
return Reassign(src); return Reassign(src);
} }
#if 0 #if 0
operator T*() const operator T*() const
@ -133,8 +133,8 @@ public:
#endif #endif
protected: protected:
void _Delete_unlocked() noexcept void _Delete_unlocked() noexcept
{ {
delete m_ptr.exchange(nullptr); delete m_ptr.exchange(nullptr);
} }
}; };

View File

@ -26,49 +26,50 @@
Threading::Semaphore::Semaphore() Threading::Semaphore::Semaphore()
{ {
sem_init(&m_sema, false, 0); sem_init(&m_sema, false, 0);
} }
Threading::Semaphore::~Semaphore() Threading::Semaphore::~Semaphore()
{ {
sem_destroy(&m_sema); sem_destroy(&m_sema);
} }
void Threading::Semaphore::Reset() void Threading::Semaphore::Reset()
{ {
sem_destroy(&m_sema); sem_destroy(&m_sema);
sem_init(&m_sema, false, 0); sem_init(&m_sema, false, 0);
} }
void Threading::Semaphore::Post() void Threading::Semaphore::Post()
{ {
sem_post(&m_sema); sem_post(&m_sema);
} }
void Threading::Semaphore::Post(int multiple) void Threading::Semaphore::Post(int multiple)
{ {
#if defined(_MSC_VER) #if defined(_MSC_VER)
sem_post_multiple(&m_sema, multiple); sem_post_multiple(&m_sema, multiple);
#else #else
// Only w32pthreads has the post_multiple, but it's easy enough to fake: // Only w32pthreads has the post_multiple, but it's easy enough to fake:
while (multiple > 0) { while (multiple > 0)
multiple--; {
sem_post(&m_sema); multiple--;
} sem_post(&m_sema);
}
#endif #endif
} }
void Threading::Semaphore::WaitWithoutYield() void Threading::Semaphore::WaitWithoutYield()
{ {
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead."); pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
sem_wait(&m_sema); sem_wait(&m_sema);
} }
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout) bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
{ {
wxDateTime megafail(wxDateTime::UNow() + timeout); wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000}; const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return sem_timedwait(&m_sema, &fail) == 0; return sem_timedwait(&m_sema, &fail) == 0;
} }
@ -80,18 +81,23 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
void Threading::Semaphore::Wait() void Threading::Semaphore::Wait()
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
sem_wait(&m_sema); {
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) { sem_wait(&m_sema);
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
sem_wait(&m_sema); else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
} else { {
//ScopedBusyCursor hourglass( Cursor_KindaBusy ); ScopedBusyCursor hourglass(Cursor_ReallyBusy);
while (!WaitWithoutYield(def_yieldgui_interval)) sem_wait(&m_sema);
YieldToMain(); }
} else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!WaitWithoutYield(def_yieldgui_interval))
YieldToMain();
}
#else #else
sem_wait(&m_sema); sem_wait(&m_sema);
#endif #endif
} }
@ -104,29 +110,35 @@ void Threading::Semaphore::Wait()
// false if the wait timed out before the semaphore was signaled, or true if the signal was // false if the wait timed out before the semaphore was signaled, or true if the signal was
// reached prior to timeout. // reached prior to timeout.
// //
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout) bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
{ {
#if wxUSE_GUI #if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) { if (!wxThread::IsMain() || (wxTheApp == NULL))
return WaitWithoutYield(timeout); {
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) { return WaitWithoutYield(timeout);
ScopedBusyCursor hourglass(Cursor_ReallyBusy); }
return WaitWithoutYield(timeout); else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
} else { {
//ScopedBusyCursor hourglass( Cursor_KindaBusy ); ScopedBusyCursor hourglass(Cursor_ReallyBusy);
wxTimeSpan countdown((timeout)); return WaitWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do { do
if (WaitWithoutYield(def_yieldgui_interval)) {
break; if (WaitWithoutYield(def_yieldgui_interval))
YieldToMain(); break;
countdown -= def_yieldgui_interval; YieldToMain();
} while (countdown.GetMilliseconds() > 0); countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0; return countdown.GetMilliseconds() > 0;
} }
#else #else
return WaitWithoutYield(timeout); return WaitWithoutYield(timeout);
#endif #endif
} }
@ -140,26 +152,26 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
// to do a lot of no-cancel waits in a tight loop worker thread, for example. // to do a lot of no-cancel waits in a tight loop worker thread, for example.
void Threading::Semaphore::WaitNoCancel() void Threading::Semaphore::WaitNoCancel()
{ {
int oldstate; int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield(); //WaitWithoutYield();
Wait(); Wait();
pthread_setcancelstate(oldstate, NULL); pthread_setcancelstate(oldstate, NULL);
} }
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout) void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
{ {
int oldstate; int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield( timeout ); //WaitWithoutYield( timeout );
Wait(timeout); Wait(timeout);
pthread_setcancelstate(oldstate, NULL); pthread_setcancelstate(oldstate, NULL);
} }
int Threading::Semaphore::Count() int Threading::Semaphore::Count()
{ {
int retval; int retval;
sem_getvalue(&m_sema, &retval); sem_getvalue(&m_sema, &retval);
return retval; return retval;
} }
#endif #endif

View File

@ -17,59 +17,59 @@
#include "common/Pcsx2Defs.h" #include "common/Pcsx2Defs.h"
#include "common/StringHelpers.h" #include "common/StringHelpers.h"
__fi wxString fromUTF8(const char *src) __fi wxString fromUTF8(const char* src)
{ {
// IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of // IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of
// wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or // wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or
// destructor that attempts to do logging may crash the app (either during startup or during exit) unless // destructor that attempts to do logging may crash the app (either during startup or during exit) unless
// we use a LOCAL instance of wxMBConvUTF8(). --air // we use a LOCAL instance of wxMBConvUTF8(). --air
// Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class // Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class
// is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets // is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets
// uses the stupid globals in the first place!) --air // uses the stupid globals in the first place!) --air
return wxString(src, wxMBConvUTF8()); return wxString(src, wxMBConvUTF8());
} }
__fi wxString fromAscii(const char *src) __fi wxString fromAscii(const char* src)
{ {
return wxString::FromAscii(src); return wxString::FromAscii(src);
} }
wxString u128::ToString() const wxString u128::ToString() const
{ {
return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]); return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
} }
wxString u128::ToString64() const wxString u128::ToString64() const
{ {
return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]); return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
} }
wxString u128::ToString8() const wxString u128::ToString8() const
{ {
FastFormatUnicode result; FastFormatUnicode result;
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]); result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
for (uint i = 2; i < 16; i += 2) for (uint i = 2; i < 16; i += 2)
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]); result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
return result; return result;
} }
void u128::WriteTo(FastFormatAscii &dest) const void u128::WriteTo(FastFormatAscii& dest) const
{ {
dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]); dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
} }
void u128::WriteTo64(FastFormatAscii &dest) const void u128::WriteTo64(FastFormatAscii& dest) const
{ {
dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]); dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
} }
void u128::WriteTo8(FastFormatAscii &dest) const void u128::WriteTo8(FastFormatAscii& dest) const
{ {
dest.Write("0x%02X.%02X", _u8[0], _u8[1]); dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
for (uint i = 2; i < 16; i += 2) for (uint i = 2; i < 16; i += 2)
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]); dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
} }
// Splits a string into parts and adds the parts into the given SafeList. // Splits a string into parts and adds the parts into the given SafeList.
@ -78,11 +78,11 @@ void u128::WriteTo8(FastFormatAscii &dest) const
// //
// Note: wxWidgets 2.9 / 3.0 has a wxSplit function, but we're using 2.8 so I had to make // Note: wxWidgets 2.9 / 3.0 has a wxSplit function, but we're using 2.8 so I had to make
// my own. // my own.
void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode) void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode)
{ {
wxStringTokenizer parts(src, delims, mode); wxStringTokenizer parts(src, delims, mode);
while (parts.HasMoreTokens()) while (parts.HasMoreTokens())
dest.Add(parts.GetNextToken()); dest.Add(parts.GetNextToken());
} }
// Joins a list of strings into one larger string, using the given string concatenation // Joins a list of strings into one larger string, using the given string concatenation
@ -91,32 +91,34 @@ void SplitString(wxArrayString &dest, const wxString &src, const wxString &delim
// //
// Note: wxWidgets 2.9 / 3.0 has a wxJoin function, but we're using 2.8 so I had to make // Note: wxWidgets 2.9 / 3.0 has a wxJoin function, but we're using 2.8 so I had to make
// my own. // my own.
wxString JoinString(const wxArrayString &src, const wxString &separator) wxString JoinString(const wxArrayString& src, const wxString& separator)
{ {
wxString dest; wxString dest;
for (int i = 0, len = src.GetCount(); i < len; ++i) { for (int i = 0, len = src.GetCount(); i < len; ++i)
if (src[i].IsEmpty()) {
continue; if (src[i].IsEmpty())
if (!dest.IsEmpty()) continue;
dest += separator; if (!dest.IsEmpty())
dest += src[i]; dest += separator;
} dest += src[i];
return dest; }
return dest;
} }
wxString JoinString(const wxChar **src, const wxString &separator) wxString JoinString(const wxChar** src, const wxString& separator)
{ {
wxString dest; wxString dest;
while (*src != NULL) { while (*src != NULL)
if (*src[0] == 0) {
continue; if (*src[0] == 0)
continue;
if (!dest.IsEmpty()) if (!dest.IsEmpty())
dest += separator; dest += separator;
dest += *src; dest += *src;
++src; ++src;
} }
return dest; return dest;
} }
@ -127,12 +129,12 @@ wxString JoinString(const wxChar **src, const wxString &separator)
// This, so far, include types such as wxPoint, wxRect, and wxSize. // This, so far, include types such as wxPoint, wxRect, and wxSize.
// //
template <typename T> template <typename T>
T Parse(const wxString &src, const wxString &separators = L",") T Parse(const wxString& src, const wxString& separators = L",")
{ {
T retval; T retval;
if (!TryParse(retval, src, separators)) if (!TryParse(retval, src, separators))
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src); throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
return retval; return retval;
} }
@ -141,104 +143,104 @@ T Parse(const wxString &src, const wxString &separators = L",")
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Converts a wxPoint into a comma-delimited string! // Converts a wxPoint into a comma-delimited string!
wxString ToString(const wxPoint &src, const wxString &separator) wxString ToString(const wxPoint& src, const wxString& separator)
{ {
return wxString() << src.x << separator << src.y; return wxString() << src.x << separator << src.y;
} }
wxString ToString(const wxSize &src, const wxString &separator) wxString ToString(const wxSize& src, const wxString& separator)
{ {
return wxString() << src.GetWidth() << separator << src.GetHeight(); return wxString() << src.GetWidth() << separator << src.GetHeight();
} }
// Converts a wxRect into a comma-delimited string! // Converts a wxRect into a comma-delimited string!
// Example: 32,64,128,5 // Example: 32,64,128,5
wxString ToString(const wxRect &src, const wxString &separator) wxString ToString(const wxRect& src, const wxString& separator)
{ {
return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator); return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator);
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Parse helpers for wxString! // Parse helpers for wxString!
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
bool TryParse(wxPoint &dest, wxStringTokenizer &parts) bool TryParse(wxPoint& dest, wxStringTokenizer& parts)
{ {
long result[2]; long result[2];
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0])) if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
return false; return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1])) if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false; return false;
dest.x = result[0]; dest.x = result[0];
dest.y = result[1]; dest.y = result[1];
return true; return true;
} }
bool TryParse(wxSize &dest, wxStringTokenizer &parts) bool TryParse(wxSize& dest, wxStringTokenizer& parts)
{ {
long result[2]; long result[2];
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0])) if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
return false; return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1])) if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false; return false;
dest.SetWidth(result[0]); dest.SetWidth(result[0]);
dest.SetHeight(result[1]); dest.SetHeight(result[1]);
return true; return true;
} }
// Tries to parse the given string into a wxPoint value at 'dest.' If the parse fails, the // Tries to parse the given string into a wxPoint value at 'dest.' If the parse fails, the
// method aborts and returns false. // method aborts and returns false.
bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval, const wxString &separators) bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval, const wxString& separators)
{ {
dest = defval; dest = defval;
wxStringTokenizer parts(src, separators); wxStringTokenizer parts(src, separators);
return TryParse(dest, parts); return TryParse(dest, parts);
} }
bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval, const wxString &separators) bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval, const wxString& separators)
{ {
dest = defval; dest = defval;
wxStringTokenizer parts(src, separators); wxStringTokenizer parts(src, separators);
return TryParse(dest, parts); return TryParse(dest, parts);
} }
bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval, const wxString &separators) bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval, const wxString& separators)
{ {
dest = defval; dest = defval;
wxStringTokenizer parts(src, separators); wxStringTokenizer parts(src, separators);
wxPoint point; wxPoint point;
wxSize size; wxSize size;
if (!TryParse(point, parts)) if (!TryParse(point, parts))
return false; return false;
if (!TryParse(size, parts)) if (!TryParse(size, parts))
return false; return false;
dest = wxRect(point, size); dest = wxRect(point, size);
return true; return true;
} }
// returns TRUE if the parse is valid, or FALSE if it's a comment. // returns TRUE if the parse is valid, or FALSE if it's a comment.
bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest) bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest)
{ {
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";")) if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
return false; return false;
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false); ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
rdest = src.AfterFirst(L'=').Trim(true).Trim(false); rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
return true; return true;
} }
ParsedAssignmentString::ParsedAssignmentString(const wxString &src) ParsedAssignmentString::ParsedAssignmentString(const wxString& src)
{ {
IsComment = pxParseAssignmentString(src, lvalue, rvalue); IsComment = pxParseAssignmentString(src, lvalue, rvalue);
} }
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms, // Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
@ -249,37 +251,41 @@ ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
// from incoming data. Mac platforms may need an implementation of their own that converts // from incoming data. Mac platforms may need an implementation of their own that converts
// newlines to CRs...? // newlines to CRs...?
// //
void px_fputs(FILE *fp, const char *src) void px_fputs(FILE* fp, const char* src)
{ {
if (fp == NULL) if (fp == NULL)
return; return;
#ifdef _WIN32 #ifdef _WIN32
// Windows needs CR's partnered with all newlines, or else notepad.exe can't view // Windows needs CR's partnered with all newlines, or else notepad.exe can't view
// the stupid logfile. Best way is to write one char at a time.. >_< // the stupid logfile. Best way is to write one char at a time.. >_<
const char *curchar = src; const char* curchar = src;
bool prevcr = false; bool prevcr = false;
while (*curchar != 0) { while (*curchar != 0)
if (*curchar == '\r') { {
prevcr = true; if (*curchar == '\r')
} else { {
// Only write a CR/LF pair if the current LF is not prefixed nor prevcr = true;
// post-fixed by a CR. }
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r')) else
fputs("\r\n", fp); {
else // Only write a CR/LF pair if the current LF is not prefixed nor
fputc(*curchar, fp); // post-fixed by a CR.
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
fputs("\r\n", fp);
else
fputc(*curchar, fp);
prevcr = false; prevcr = false;
} }
++curchar; ++curchar;
} }
#else #else
// Linux is happy with plain old LFs. Not sure about Macs... does OSX still // Linux is happy with plain old LFs. Not sure about Macs... does OSX still
// go by the old school Mac style of using Crs only? // go by the old school Mac style of using Crs only?
fputs(src, fp); // fputs does not do automatic newlines, so it's ok! fputs(src, fp); // fputs does not do automatic newlines, so it's ok!
#endif #endif
} }

View File

@ -24,7 +24,7 @@
#define WX_STR(str) (str.wc_str()) #define WX_STR(str) (str.wc_str())
#else #else
// Stupid wx3.0 doesn't support c_str for vararg function // Stupid wx3.0 doesn't support c_str for vararg function
#define WX_STR(str) (static_cast<const char *>(str.c_str())) #define WX_STR(str) (static_cast<const char*>(str.c_str()))
#endif #endif
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -33,59 +33,59 @@
// Converts a string to UTF8 and provides an interface for getting its length. // Converts a string to UTF8 and provides an interface for getting its length.
class pxToUTF8 class pxToUTF8
{ {
DeclareNoncopyableObject(pxToUTF8); DeclareNoncopyableObject(pxToUTF8);
protected: protected:
wxCharBuffer m_result; wxCharBuffer m_result;
int m_length; int m_length;
public: public:
explicit pxToUTF8(const wxString &src) explicit pxToUTF8(const wxString& src)
: m_result(src.ToUTF8()) : m_result(src.ToUTF8())
{ {
m_length = -1; m_length = -1;
} }
size_t Length() size_t Length()
{ {
if (-1 == m_length) if (-1 == m_length)
m_length = strlen(m_result); m_length = strlen(m_result);
return m_length; return m_length;
} }
void Convert(const wxString &src) void Convert(const wxString& src)
{ {
m_result = src.ToUTF8(); m_result = src.ToUTF8();
m_length = -1; m_length = -1;
} }
const char *data() const { return m_result; } const char* data() const { return m_result; }
operator const char *() const operator const char*() const
{ {
return m_result.data(); return m_result.data();
} }
}; };
extern void px_fputs(FILE *fp, const char *src); extern void px_fputs(FILE* fp, const char* src);
// wxWidgets lacks one of its own... // wxWidgets lacks one of its own...
extern const wxRect wxDefaultRect; extern const wxRect wxDefaultRect;
extern void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL); extern void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL);
extern wxString JoinString(const wxArrayString &src, const wxString &separator); extern wxString JoinString(const wxArrayString& src, const wxString& separator);
extern wxString JoinString(const wxChar **src, const wxString &separator); extern wxString JoinString(const wxChar** src, const wxString& separator);
extern wxString ToString(const wxPoint &src, const wxString &separator = L","); extern wxString ToString(const wxPoint& src, const wxString& separator = L",");
extern wxString ToString(const wxSize &src, const wxString &separator = L","); extern wxString ToString(const wxSize& src, const wxString& separator = L",");
extern wxString ToString(const wxRect &src, const wxString &separator = L","); extern wxString ToString(const wxRect& src, const wxString& separator = L",");
extern bool TryParse(wxPoint &dest, const wxStringTokenizer &parts); extern bool TryParse(wxPoint& dest, const wxStringTokenizer& parts);
extern bool TryParse(wxSize &dest, const wxStringTokenizer &parts); extern bool TryParse(wxSize& dest, const wxStringTokenizer& parts);
extern bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval = wxDefaultPosition, const wxString &separators = L","); extern bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval = wxDefaultPosition, const wxString& separators = L",");
extern bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval = wxDefaultSize, const wxString &separators = L","); extern bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval = wxDefaultSize, const wxString& separators = L",");
extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = wxDefaultRect, const wxString &separators = L","); extern bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval = wxDefaultRect, const wxString& separators = L",");
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ParsedAssignmentString // ParsedAssignmentString
@ -103,11 +103,11 @@ extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = w
// //
struct ParsedAssignmentString struct ParsedAssignmentString
{ {
wxString lvalue; wxString lvalue;
wxString rvalue; wxString rvalue;
bool IsComment; bool IsComment;
ParsedAssignmentString(const wxString &src); ParsedAssignmentString(const wxString& src);
}; };
// ====================================================================================== // ======================================================================================
@ -139,40 +139,40 @@ typedef ScopedAlignedAlloc<char, 16> CharBufferType;
class FastFormatAscii class FastFormatAscii
{ {
protected: protected:
CharBufferType m_dest; CharBufferType m_dest;
public: public:
FastFormatAscii(); FastFormatAscii();
~FastFormatAscii() = default; ~FastFormatAscii() = default;
FastFormatAscii &Write(const char *fmt, ...); FastFormatAscii& Write(const char* fmt, ...);
FastFormatAscii &WriteV(const char *fmt, va_list argptr); FastFormatAscii& WriteV(const char* fmt, va_list argptr);
void Clear(); void Clear();
bool IsEmpty() const; bool IsEmpty() const;
const char *c_str() const { return m_dest.GetPtr(); } const char* c_str() const { return m_dest.GetPtr(); }
operator const char *() const { return m_dest.GetPtr(); } operator const char*() const { return m_dest.GetPtr(); }
const wxString GetString() const; const wxString GetString() const;
//operator wxString() const; //operator wxString() const;
FastFormatAscii &operator+=(const wxString &s) FastFormatAscii& operator+=(const wxString& s)
{ {
Write("%s", WX_STR(s)); Write("%s", WX_STR(s));
return *this; return *this;
} }
FastFormatAscii &operator+=(const wxChar *psz) FastFormatAscii& operator+=(const wxChar* psz)
{ {
Write("%ls", psz); Write("%ls", psz);
return *this; return *this;
} }
FastFormatAscii &operator+=(const char *psz) FastFormatAscii& operator+=(const char* psz)
{ {
Write("%s", psz); Write("%s", psz);
return *this; return *this;
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -181,54 +181,54 @@ public:
class FastFormatUnicode class FastFormatUnicode
{ {
protected: protected:
CharBufferType m_dest; CharBufferType m_dest;
uint m_Length; uint m_Length;
public: public:
FastFormatUnicode(); FastFormatUnicode();
~FastFormatUnicode() = default; ~FastFormatUnicode() = default;
FastFormatUnicode &Write(const char *fmt, ...); FastFormatUnicode& Write(const char* fmt, ...);
FastFormatUnicode &Write(const wxChar *fmt, ...); FastFormatUnicode& Write(const wxChar* fmt, ...);
FastFormatUnicode &Write(const wxString fmt, ...); FastFormatUnicode& Write(const wxString fmt, ...);
FastFormatUnicode &WriteV(const char *fmt, va_list argptr); FastFormatUnicode& WriteV(const char* fmt, va_list argptr);
FastFormatUnicode &WriteV(const wxChar *fmt, va_list argptr); FastFormatUnicode& WriteV(const wxChar* fmt, va_list argptr);
void Clear(); void Clear();
bool IsEmpty() const; bool IsEmpty() const;
uint Length() const { return m_Length; } uint Length() const { return m_Length; }
FastFormatUnicode &ToUpper(); FastFormatUnicode& ToUpper();
FastFormatUnicode &ToLower(); FastFormatUnicode& ToLower();
const wxChar *c_str() const { return (const wxChar *)m_dest.GetPtr(); } const wxChar* c_str() const { return (const wxChar*)m_dest.GetPtr(); }
operator const wxChar *() const { return (const wxChar *)m_dest.GetPtr(); } operator const wxChar*() const { return (const wxChar*)m_dest.GetPtr(); }
operator wxString() const { return (const wxChar *)m_dest.GetPtr(); } operator wxString() const { return (const wxChar*)m_dest.GetPtr(); }
FastFormatUnicode &operator+=(const wxString &s) FastFormatUnicode& operator+=(const wxString& s)
{ {
Write(L"%s", WX_STR(s)); Write(L"%s", WX_STR(s));
return *this; return *this;
} }
FastFormatUnicode &operator+=(const wxChar *psz) FastFormatUnicode& operator+=(const wxChar* psz)
{ {
Write(L"%s", psz); Write(L"%s", psz);
return *this; return *this;
} }
FastFormatUnicode &operator+=(const char *psz); FastFormatUnicode& operator+=(const char* psz);
}; };
extern bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest); extern bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest);
#define pxsFmt FastFormatUnicode().Write #define pxsFmt FastFormatUnicode().Write
#define pxsFmtV FastFormatUnicode().WriteV #define pxsFmtV FastFormatUnicode().WriteV
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str() #define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
extern wxString &operator+=(wxString &str1, const FastFormatUnicode &str2); extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
extern wxString operator+(const wxString &str1, const FastFormatUnicode &str2); extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
extern wxString operator+(const wxChar *str1, const FastFormatUnicode &str2); extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);
extern wxString operator+(const FastFormatUnicode &str1, const wxString &str2); extern wxString operator+(const FastFormatUnicode& str1, const wxString& str2);
extern wxString operator+(const FastFormatUnicode &str1, const wxChar *str2); extern wxString operator+(const FastFormatUnicode& str1, const wxChar* str2);

View File

@ -33,12 +33,12 @@ const wxTimeSpan Threading::def_yieldgui_interval(0, 0, 0, 100);
ConsoleLogSource_Threading::ConsoleLogSource_Threading() ConsoleLogSource_Threading::ConsoleLogSource_Threading()
{ {
static const TraceLogDescriptor myDesc = static const TraceLogDescriptor myDesc =
{ {
L"p&xThread", L"pxThread", L"p&xThread", L"pxThread",
pxLt("Threading activity: start, detach, sync, deletion, etc.")}; pxLt("Threading activity: start, detach, sync, deletion, etc.")};
m_Descriptor = &myDesc; m_Descriptor = &myDesc;
} }
ConsoleLogSource_Threading pxConLog_Thread; ConsoleLogSource_Threading pxConLog_Thread;
@ -47,18 +47,18 @@ ConsoleLogSource_Threading pxConLog_Thread;
class StaticMutex : public Mutex class StaticMutex : public Mutex
{ {
protected: protected:
bool &m_DeletedFlag; bool& m_DeletedFlag;
public: public:
StaticMutex(bool &deletedFlag) StaticMutex(bool& deletedFlag)
: m_DeletedFlag(deletedFlag) : m_DeletedFlag(deletedFlag)
{ {
} }
virtual ~StaticMutex() virtual ~StaticMutex()
{ {
m_DeletedFlag = true; m_DeletedFlag = true;
} }
}; };
static pthread_key_t curthread_key = 0; static pthread_key_t curthread_key = 0;
@ -67,111 +67,115 @@ static s32 total_key_count = 0;
static bool tkl_destructed = false; static bool tkl_destructed = false;
static StaticMutex total_key_lock(tkl_destructed); static StaticMutex total_key_lock(tkl_destructed);
static void make_curthread_key(const pxThread *thr) static void make_curthread_key(const pxThread* thr)
{ {
pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key."); pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key.");
ScopedLock lock(total_key_lock); ScopedLock lock(total_key_lock);
if (total_key_count++ != 0) if (total_key_count++ != 0)
return; return;
if (0 != pthread_key_create(&curthread_key, NULL)) { if (0 != pthread_key_create(&curthread_key, NULL))
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)"); {
curthread_key = 0; pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
} curthread_key = 0;
}
} }
static void unmake_curthread_key() static void unmake_curthread_key()
{ {
ScopedLock lock; ScopedLock lock;
if (!tkl_destructed) if (!tkl_destructed)
lock.AssignAndLock(total_key_lock); lock.AssignAndLock(total_key_lock);
if (--total_key_count > 0) if (--total_key_count > 0)
return; return;
if (curthread_key) if (curthread_key)
pthread_key_delete(curthread_key); pthread_key_delete(curthread_key);
curthread_key = 0; curthread_key = 0;
} }
void Threading::pxTestCancel() void Threading::pxTestCancel()
{ {
pthread_testcancel(); pthread_testcancel();
} }
// Returns a handle to the current persistent thread. If the current thread does not belong // Returns a handle to the current persistent thread. If the current thread does not belong
// to the pxThread table, NULL is returned. Since the main/ui thread is not created // to the pxThread table, NULL is returned. Since the main/ui thread is not created
// through pxThread it will also return NULL. Callers can use wxThread::IsMain() to // through pxThread it will also return NULL. Callers can use wxThread::IsMain() to
// test if the NULL thread is the main thread. // test if the NULL thread is the main thread.
pxThread *Threading::pxGetCurrentThread() pxThread* Threading::pxGetCurrentThread()
{ {
return !curthread_key ? NULL : (pxThread *)pthread_getspecific(curthread_key); return !curthread_key ? NULL : (pxThread*)pthread_getspecific(curthread_key);
} }
// returns the name of the current thread, or "Unknown" if the thread is neither a pxThread // returns the name of the current thread, or "Unknown" if the thread is neither a pxThread
// nor the Main/UI thread. // nor the Main/UI thread.
wxString Threading::pxGetCurrentThreadName() wxString Threading::pxGetCurrentThreadName()
{ {
if (pxThread *thr = pxGetCurrentThread()) { if (pxThread* thr = pxGetCurrentThread())
return thr->GetName(); {
} else if (wxThread::IsMain()) { return thr->GetName();
return L"Main/UI"; }
} else if (wxThread::IsMain())
{
return L"Main/UI";
}
return L"Unknown"; return L"Unknown";
} }
void Threading::pxYield(int ms) void Threading::pxYield(int ms)
{ {
if (pxThread *thr = pxGetCurrentThread()) if (pxThread* thr = pxGetCurrentThread())
thr->Yield(ms); thr->Yield(ms);
else else
Sleep(ms); Sleep(ms);
} }
// (intended for internal use only) // (intended for internal use only)
// Returns true if the Wait is recursive, or false if the Wait is safe and should be // Returns true if the Wait is recursive, or false if the Wait is safe and should be
// handled via normal yielding methods. // handled via normal yielding methods.
bool Threading::_WaitGui_RecursionGuard(const wxChar *name) bool Threading::_WaitGui_RecursionGuard(const wxChar* name)
{ {
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
// In order to avoid deadlock we need to make sure we cut some time to handle messages. // In order to avoid deadlock we need to make sure we cut some time to handle messages.
// But this can result in recursive yield calls, which would crash the app. Protect // But this can result in recursive yield calls, which would crash the app. Protect
// against them here and, if recursion is detected, perform a standard blocking wait. // against them here and, if recursion is detected, perform a standard blocking wait.
static int __Guard = 0; static int __Guard = 0;
RecursionGuard guard(__Guard); RecursionGuard guard(__Guard);
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false; //if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
if (!guard.IsReentrant()) if (!guard.IsReentrant())
return false; return false;
pxThreadLog.Write(pxGetCurrentThreadName(), pxThreadLog.Write(pxGetCurrentThreadName(),
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name)); pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
return true; return true;
} }
__fi void Threading::Timeslice() __fi void Threading::Timeslice()
{ {
sched_yield(); sched_yield();
} }
void Threading::pxThread::_pt_callback_cleanup(void *handle) void Threading::pxThread::_pt_callback_cleanup(void* handle)
{ {
((pxThread *)handle)->_ThreadCleanup(); ((pxThread*)handle)->_ThreadCleanup();
} }
Threading::pxThread::pxThread(const wxString &name) Threading::pxThread::pxThread(const wxString& name)
: m_name(name) : m_name(name)
, m_thread() , m_thread()
, m_native_id(0) , m_native_id(0)
, m_native_handle(0) , m_native_handle(0)
, m_detached(true) // start out with m_thread in detached/invalid state , m_detached(true) // start out with m_thread in detached/invalid state
, m_running(false) , m_running(false)
{ {
} }
@ -184,50 +188,53 @@ Threading::pxThread::pxThread(const wxString &name)
// like marrying your sister, and then cheating on her with your daughter. // like marrying your sister, and then cheating on her with your daughter.
Threading::pxThread::~pxThread() Threading::pxThread::~pxThread()
{ {
try { try
pxThreadLog.Write(GetName(), L"Executing default destructor!"); {
pxThreadLog.Write(GetName(), L"Executing default destructor!");
if (m_running) { if (m_running)
pxThreadLog.Write(GetName(), L"Waiting for running thread to end..."); {
m_mtx_InThread.Wait(); pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
pxThreadLog.Write(GetName(), L"Thread ended gracefully."); m_mtx_InThread.Wait();
} pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
Threading::Sleep(1); }
Detach(); Threading::Sleep(1);
} Detach();
DESTRUCTOR_CATCHALL }
DESTRUCTOR_CATCHALL
} }
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const
{ {
if (IsSelf()) if (IsSelf())
return true; return true;
if (IsDevBuild) if (IsDevBuild)
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName()))); pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
return false; return false;
} }
bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const
{ {
if (!IsSelf()) if (!IsSelf())
return true; return true;
if (IsDevBuild) if (IsDevBuild)
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName()))); pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
return false; return false;
} }
void Threading::pxThread::FrankenMutex(Mutex &mutex) void Threading::pxThread::FrankenMutex(Mutex& mutex)
{ {
if (mutex.RecreateIfLocked()) { if (mutex.RecreateIfLocked())
// Our lock is bupkis, which means the previous thread probably deadlocked. {
// Let's create a new mutex lock to replace it. // Our lock is bupkis, which means the previous thread probably deadlocked.
// Let's create a new mutex lock to replace it.
pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!"); pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!");
} }
} }
// Main entry point for starting or e-starting a persistent thread. This function performs necessary // Main entry point for starting or e-starting a persistent thread. This function performs necessary
@ -238,53 +245,56 @@ void Threading::pxThread::FrankenMutex(Mutex &mutex)
// This function should not be called from the owner thread. // This function should not be called from the owner thread.
void Threading::pxThread::Start() void Threading::pxThread::Start()
{ {
// Prevents sudden parallel startup, and or parallel startup + cancel: // Prevents sudden parallel startup, and or parallel startup + cancel:
ScopedLock startlock(m_mtx_start); ScopedLock startlock(m_mtx_start);
if (m_running) { if (m_running)
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning..."); {
return; pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
} return;
}
Detach(); // clean up previous thread handle, if one exists. Detach(); // clean up previous thread handle, if one exists.
OnStart(); OnStart();
m_except = NULL; m_except = NULL;
pxThreadLog.Write(GetName(), L"Calling pthread_create..."); pxThreadLog.Write(GetName(), L"Calling pthread_create...");
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0) if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno))); throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
#ifdef ASAN_WORKAROUND #ifdef ASAN_WORKAROUND
// Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982 // Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982
// //
// In our case, the semaphore was posted (counter is 1) but thread is still // In our case, the semaphore was posted (counter is 1) but thread is still
// waiting... So waits 100ms and checks the counter value manually // waiting... So waits 100ms and checks the counter value manually
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100))) { if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100)))
if (m_sem_startup.Count() == 0) {
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore."); if (m_sem_startup.Count() == 0)
} throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
}
#else #else
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0))) { if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0)))
RethrowException(); {
RethrowException();
// And if the thread threw nothing of its own: // And if the thread threw nothing of its own:
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore."); throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
} }
#endif #endif
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the // Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
// sense that it stalls the calling thread completely until the new thread is created // sense that it stalls the calling thread completely until the new thread is created
// (which may not always be desirable). But too bad. In order to safely use 'running' locks // (which may not always be desirable). But too bad. In order to safely use 'running' locks
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't // and detachment management, this *has* to be done. By rule, starting new threads shouldn't
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks. // be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel // (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
// overhead in starting threads). // overhead in starting threads).
// (this could also be done using operating system specific calls, since any threaded OS has // (this could also be done using operating system specific calls, since any threaded OS has
// functions that allow us to see if a thread is running or not, and to block against it even if // functions that allow us to see if a thread is running or not, and to block against it even if
// it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But // it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im- // pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
// possible to safely block against a running thread) // possible to safely block against a running thread)
} }
// Returns: TRUE if the detachment was performed, or FALSE if the thread was // Returns: TRUE if the detachment was performed, or FALSE if the thread was
@ -292,26 +302,27 @@ void Threading::pxThread::Start()
// This function should not be called from the owner thread. // This function should not be called from the owner thread.
bool Threading::pxThread::Detach() bool Threading::pxThread::Detach()
{ {
AffinityAssert_DisallowFromSelf(pxDiagSpot); AffinityAssert_DisallowFromSelf(pxDiagSpot);
if (m_detached.exchange(true)) if (m_detached.exchange(true))
return false; return false;
pthread_detach(m_thread); pthread_detach(m_thread);
return true; return true;
} }
bool Threading::pxThread::_basecancel() bool Threading::pxThread::_basecancel()
{ {
if (!m_running) if (!m_running)
return false; return false;
if (m_detached) { if (m_detached)
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread."); {
return false; pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
} return false;
}
pthread_cancel(m_thread); pthread_cancel(m_thread);
return true; return true;
} }
// Remarks: // Remarks:
@ -330,34 +341,35 @@ bool Threading::pxThread::_basecancel()
// //
void Threading::pxThread::Cancel(bool isBlocking) void Threading::pxThread::Cancel(bool isBlocking)
{ {
AffinityAssert_DisallowFromSelf(pxDiagSpot); AffinityAssert_DisallowFromSelf(pxDiagSpot);
// Prevent simultaneous startup and cancel, necessary to avoid // Prevent simultaneous startup and cancel, necessary to avoid
ScopedLock startlock(m_mtx_start); ScopedLock startlock(m_mtx_start);
if (!_basecancel()) if (!_basecancel())
return; return;
if (isBlocking) { if (isBlocking)
WaitOnSelf(m_mtx_InThread); {
Detach(); WaitOnSelf(m_mtx_InThread);
} Detach();
}
} }
bool Threading::pxThread::Cancel(const wxTimeSpan &timespan) bool Threading::pxThread::Cancel(const wxTimeSpan& timespan)
{ {
AffinityAssert_DisallowFromSelf(pxDiagSpot); AffinityAssert_DisallowFromSelf(pxDiagSpot);
// Prevent simultaneous startup and cancel: // Prevent simultaneous startup and cancel:
ScopedLock startlock(m_mtx_start); ScopedLock startlock(m_mtx_start);
if (!_basecancel()) if (!_basecancel())
return true; return true;
if (!WaitOnSelf(m_mtx_InThread, timespan)) if (!WaitOnSelf(m_mtx_InThread, timespan))
return false; return false;
Detach(); Detach();
return true; return true;
} }
@ -373,32 +385,32 @@ bool Threading::pxThread::Cancel(const wxTimeSpan &timespan)
// //
void Threading::pxThread::Block() void Threading::pxThread::Block()
{ {
AffinityAssert_DisallowFromSelf(pxDiagSpot); AffinityAssert_DisallowFromSelf(pxDiagSpot);
WaitOnSelf(m_mtx_InThread); WaitOnSelf(m_mtx_InThread);
} }
bool Threading::pxThread::Block(const wxTimeSpan &timeout) bool Threading::pxThread::Block(const wxTimeSpan& timeout)
{ {
AffinityAssert_DisallowFromSelf(pxDiagSpot); AffinityAssert_DisallowFromSelf(pxDiagSpot);
return WaitOnSelf(m_mtx_InThread, timeout); return WaitOnSelf(m_mtx_InThread, timeout);
} }
bool Threading::pxThread::IsSelf() const bool Threading::pxThread::IsSelf() const
{ {
// Detached threads may have their pthread handles recycled as newer threads, causing // Detached threads may have their pthread handles recycled as newer threads, causing
// false IsSelf reports. // false IsSelf reports.
return !m_detached && (pthread_self() == m_thread); return !m_detached && (pthread_self() == m_thread);
} }
bool Threading::pxThread::IsRunning() const bool Threading::pxThread::IsRunning() const
{ {
return m_running; return m_running;
} }
void Threading::pxThread::AddListener(EventListener_Thread &evt) void Threading::pxThread::AddListener(EventListener_Thread& evt)
{ {
evt.SetThread(this); evt.SetThread(this);
m_evtsrc_OnDelete.Add(evt); m_evtsrc_OnDelete.Add(evt);
} }
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method, // Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
@ -406,49 +418,51 @@ void Threading::pxThread::AddListener(EventListener_Thread &evt)
// the thread will have allowed itself to terminate properly. // the thread will have allowed itself to terminate properly.
void Threading::pxThread::RethrowException() const void Threading::pxThread::RethrowException() const
{ {
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the // Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
// pointer might still be invalid after detachment, so might as well just detach and check // pointer might still be invalid after detachment, so might as well just detach and check
// after. // after.
ScopedExcept ptr(const_cast<pxThread *>(this)->m_except.DetachPtr()); ScopedExcept ptr(const_cast<pxThread*>(this)->m_except.DetachPtr());
if (ptr) if (ptr)
ptr->Rethrow(); ptr->Rethrow();
} }
static bool m_BlockDeletions = false; static bool m_BlockDeletions = false;
bool Threading::AllowDeletions() bool Threading::AllowDeletions()
{ {
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
return !m_BlockDeletions; return !m_BlockDeletions;
} }
void Threading::YieldToMain() void Threading::YieldToMain()
{ {
m_BlockDeletions = true; m_BlockDeletions = true;
wxTheApp->Yield(true); wxTheApp->Yield(true);
m_BlockDeletions = false; m_BlockDeletions = false;
} }
void Threading::pxThread::_selfRunningTest(const wxChar *name) const void Threading::pxThread::_selfRunningTest(const wxChar* name) const
{ {
if (HasPendingException()) { if (HasPendingException())
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name)); {
RethrowException(); pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
} RethrowException();
}
if (!m_running) { if (!m_running)
throw Exception::CancelEvent(pxsFmt( {
L"Blocking thread %s was terminated while another thread was waiting on a %s.", throw Exception::CancelEvent(pxsFmt(
WX_STR(GetName()), name)); L"Blocking thread %s was terminated while another thread was waiting on a %s.",
} WX_STR(GetName()), name));
}
// Thread is still alive and kicking (for now) -- yield to other messages and hope // Thread is still alive and kicking (for now) -- yield to other messages and hope
// that impending chaos does not ensue. [it shouldn't since we block pxThread // that impending chaos does not ensue. [it shouldn't since we block pxThread
// objects from being deleted until outside the scope of a mutex/semaphore wait). // objects from being deleted until outside the scope of a mutex/semaphore wait).
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf")) if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
Threading::YieldToMain(); Threading::YieldToMain();
} }
// This helper function is a deadlock-safe method of waiting on a semaphore in a pxThread. If the // This helper function is a deadlock-safe method of waiting on a semaphore in a pxThread. If the
@ -462,16 +476,17 @@ void Threading::pxThread::_selfRunningTest(const wxChar *name) const
// This function will rethrow exceptions raised by the persistent thread, if it throws an error // This function will rethrow exceptions raised by the persistent thread, if it throws an error
// while the calling thread is blocking (which also means the persistent thread has terminated). // while the calling thread is blocking (which also means the persistent thread has terminated).
// //
void Threading::pxThread::WaitOnSelf(Semaphore &sem) const void Threading::pxThread::WaitOnSelf(Semaphore& sem) const
{ {
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot)) if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return; return;
while (true) { while (true)
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333))) {
return; if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
_selfRunningTest(L"semaphore"); return;
} _selfRunningTest(L"semaphore");
}
} }
// This helper function is a deadlock-safe method of waiting on a mutex in a pxThread. // This helper function is a deadlock-safe method of waiting on a mutex in a pxThread.
@ -487,52 +502,55 @@ void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
// error while the calling thread is blocking (which also means the persistent thread has // error while the calling thread is blocking (which also means the persistent thread has
// terminated). // terminated).
// //
void Threading::pxThread::WaitOnSelf(Mutex &mutex) const void Threading::pxThread::WaitOnSelf(Mutex& mutex) const
{ {
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot)) if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return; return;
while (true) { while (true)
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333))) {
return; if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
_selfRunningTest(L"mutex"); return;
} _selfRunningTest(L"mutex");
}
} }
static const wxTimeSpan SelfWaitInterval(0, 0, 0, 333); static const wxTimeSpan SelfWaitInterval(0, 0, 0, 333);
bool Threading::pxThread::WaitOnSelf(Semaphore &sem, const wxTimeSpan &timeout) const bool Threading::pxThread::WaitOnSelf(Semaphore& sem, const wxTimeSpan& timeout) const
{ {
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot)) if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return true; return true;
wxTimeSpan runningout(timeout); wxTimeSpan runningout(timeout);
while (runningout.GetMilliseconds() > 0) { while (runningout.GetMilliseconds() > 0)
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout); {
if (sem.WaitWithoutYield(interval)) const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
return true; if (sem.WaitWithoutYield(interval))
_selfRunningTest(L"semaphore"); return true;
runningout -= interval; _selfRunningTest(L"semaphore");
} runningout -= interval;
return false; }
return false;
} }
bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const bool Threading::pxThread::WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const
{ {
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot)) if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return true; return true;
wxTimeSpan runningout(timeout); wxTimeSpan runningout(timeout);
while (runningout.GetMilliseconds() > 0) { while (runningout.GetMilliseconds() > 0)
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout); {
if (mutex.WaitWithoutYield(interval)) const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
return true; if (mutex.WaitWithoutYield(interval))
_selfRunningTest(L"mutex"); return true;
runningout -= interval; _selfRunningTest(L"mutex");
} runningout -= interval;
return false; }
return false;
} }
// Inserts a thread cancellation point. If the thread has received a cancel request, this // Inserts a thread cancellation point. If the thread has received a cancel request, this
@ -541,36 +559,39 @@ bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) co
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup). // and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
void Threading::pxThread::TestCancel() const void Threading::pxThread::TestCancel() const
{ {
AffinityAssert_AllowFromSelf(pxDiagSpot); AffinityAssert_AllowFromSelf(pxDiagSpot);
pthread_testcancel(); pthread_testcancel();
} }
// Executes the virtual member method // Executes the virtual member method
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)()) void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
{ {
try { try
(this->*method)(); {
} (this->*method)();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Neat repackaging for STL Runtime errors... // Neat repackaging for STL Runtime errors...
// //
catch (std::runtime_error &ex) { catch (std::runtime_error& ex)
m_except = new Exception::RuntimeError(ex, WX_STR(GetName())); {
} m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
catch (Exception::RuntimeError &ex) { catch (Exception::RuntimeError& ex)
BaseException *woot = ex.Clone(); {
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName())); BaseException* woot = ex.Clone();
m_except = woot; woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
} m_except = woot;
}
#ifndef PCSX2_DEVBUILD #ifndef PCSX2_DEVBUILD
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Bleh... don't bother with std::exception. runtime_error should catch anything // Bleh... don't bother with std::exception. runtime_error should catch anything
// useful coming out of the core STL libraries anyway, and these are best handled by // useful coming out of the core STL libraries anyway, and these are best handled by
// the MSVC debugger (or by silent random annoying fail on debug-less linux). // the MSVC debugger (or by silent random annoying fail on debug-less linux).
/*catch( std::logic_error& ex ) /*catch( std::logic_error& ex )
{ {
throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s", throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s",
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) ) WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
@ -582,14 +603,15 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) ) WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
); );
}*/ }*/
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// BaseException -- same deal as LogicErrors. // BaseException -- same deal as LogicErrors.
// //
catch (BaseException &ex) { catch (BaseException& ex)
BaseException *woot = ex.Clone(); {
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName())); BaseException* woot = ex.Clone();
m_except = woot; woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
} m_except = woot;
}
#endif #endif
} }
@ -597,25 +619,25 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
// OnCleanupInThread() to extend cleanup functionality. // OnCleanupInThread() to extend cleanup functionality.
void Threading::pxThread::_ThreadCleanup() void Threading::pxThread::_ThreadCleanup()
{ {
AffinityAssert_AllowFromSelf(pxDiagSpot); AffinityAssert_AllowFromSelf(pxDiagSpot);
_try_virtual_invoke(&pxThread::OnCleanupInThread); _try_virtual_invoke(&pxThread::OnCleanupInThread);
m_mtx_InThread.Release(); m_mtx_InThread.Release();
// Must set m_running LAST, as thread destructors depend on this value (it is used // Must set m_running LAST, as thread destructors depend on this value (it is used
// to avoid destruction of the thread until all internal data use has stopped. // to avoid destruction of the thread until all internal data use has stopped.
m_running = false; m_running = false;
} }
wxString Threading::pxThread::GetName() const wxString Threading::pxThread::GetName() const
{ {
ScopedLock lock(m_mtx_ThreadName); ScopedLock lock(m_mtx_ThreadName);
return m_name; return m_name;
} }
void Threading::pxThread::SetName(const wxString &newname) void Threading::pxThread::SetName(const wxString& newname)
{ {
ScopedLock lock(m_mtx_ThreadName); ScopedLock lock(m_mtx_ThreadName);
m_name = newname; m_name = newname;
} }
// This override is called by PeristentThread when the thread is first created, prior to // This override is called by PeristentThread when the thread is first created, prior to
@ -627,82 +649,82 @@ void Threading::pxThread::SetName(const wxString &newname)
// //
void Threading::pxThread::OnStartInThread() void Threading::pxThread::OnStartInThread()
{ {
m_detached = false; m_detached = false;
m_running = true; m_running = true;
_platform_specific_OnStartInThread(); _platform_specific_OnStartInThread();
} }
void Threading::pxThread::_internal_execute() void Threading::pxThread::_internal_execute()
{ {
m_mtx_InThread.Acquire(); m_mtx_InThread.Acquire();
_DoSetThreadName(GetName()); _DoSetThreadName(GetName());
make_curthread_key(this); make_curthread_key(this);
if (curthread_key) if (curthread_key)
pthread_setspecific(curthread_key, this); pthread_setspecific(curthread_key, this);
OnStartInThread(); OnStartInThread();
m_sem_startup.Post(); m_sem_startup.Post();
_try_virtual_invoke(&pxThread::ExecuteTaskInThread); _try_virtual_invoke(&pxThread::ExecuteTaskInThread);
} }
// Called by Start, prior to actual starting of the thread, and after any previous // Called by Start, prior to actual starting of the thread, and after any previous
// running thread has been canceled or detached. // running thread has been canceled or detached.
void Threading::pxThread::OnStart() void Threading::pxThread::OnStart()
{ {
m_native_handle = 0; m_native_handle = 0;
m_native_id = 0; m_native_id = 0;
FrankenMutex(m_mtx_InThread); FrankenMutex(m_mtx_InThread);
m_sem_event.Reset(); m_sem_event.Reset();
m_sem_startup.Reset(); m_sem_startup.Reset();
} }
// Extending classes that override this method should always call it last from their // Extending classes that override this method should always call it last from their
// personal implementations. // personal implementations.
void Threading::pxThread::OnCleanupInThread() void Threading::pxThread::OnCleanupInThread()
{ {
if (curthread_key) if (curthread_key)
pthread_setspecific(curthread_key, NULL); pthread_setspecific(curthread_key, NULL);
unmake_curthread_key(); unmake_curthread_key();
_platform_specific_OnCleanupInThread(); _platform_specific_OnCleanupInThread();
m_native_handle = 0; m_native_handle = 0;
m_native_id = 0; m_native_id = 0;
m_evtsrc_OnDelete.Dispatch(0); m_evtsrc_OnDelete.Dispatch(0);
} }
// passed into pthread_create, and is used to dispatch the thread's object oriented // passed into pthread_create, and is used to dispatch the thread's object oriented
// callback function // callback function
void *Threading::pxThread::_internal_callback(void *itsme) void* Threading::pxThread::_internal_callback(void* itsme)
{ {
if (!pxAssertDev(itsme != NULL, wxNullChar)) if (!pxAssertDev(itsme != NULL, wxNullChar))
return NULL; return NULL;
internal_callback_helper(itsme); internal_callback_helper(itsme);
return nullptr; return nullptr;
} }
// __try is used in pthread_cleanup_push when CLEANUP_SEH is used as the cleanup model. // __try is used in pthread_cleanup_push when CLEANUP_SEH is used as the cleanup model.
// That can't be used in a function that has objects that require unwinding (compile // That can't be used in a function that has objects that require unwinding (compile
// error C2712), so move it into a separate function. // error C2712), so move it into a separate function.
void Threading::pxThread::internal_callback_helper(void *itsme) void Threading::pxThread::internal_callback_helper(void* itsme)
{ {
pxThread &owner = *static_cast<pxThread *>(itsme); pxThread& owner = *static_cast<pxThread*>(itsme);
pthread_cleanup_push(_pt_callback_cleanup, itsme); pthread_cleanup_push(_pt_callback_cleanup, itsme);
owner._internal_execute(); owner._internal_execute();
pthread_cleanup_pop(true); pthread_cleanup_pop(true);
} }
void Threading::pxThread::_DoSetThreadName(const wxString &name) void Threading::pxThread::_DoSetThreadName(const wxString& name)
{ {
_DoSetThreadName(static_cast<const char *>(name.ToUTF8())); _DoSetThreadName(static_cast<const char*>(name.ToUTF8()));
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -746,23 +768,23 @@ void Threading::WaitEvent::Wait()
wxString Exception::BaseThreadError::FormatDiagnosticMessage() const wxString Exception::BaseThreadError::FormatDiagnosticMessage() const
{ {
wxString null_str(L"Null Thread Object"); wxString null_str(L"Null Thread Object");
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName())); return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
} }
wxString Exception::BaseThreadError::FormatDisplayMessage() const wxString Exception::BaseThreadError::FormatDisplayMessage() const
{ {
wxString null_str(L"Null Thread Object"); wxString null_str(L"Null Thread Object");
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName())); return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
} }
pxThread &Exception::BaseThreadError::Thread() pxThread& Exception::BaseThreadError::Thread()
{ {
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception."); pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
return *m_thread; return *m_thread;
} }
const pxThread &Exception::BaseThreadError::Thread() const const pxThread& Exception::BaseThreadError::Thread() const
{ {
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception."); pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
return *m_thread; return *m_thread;
} }

View File

@ -32,7 +32,7 @@
#undef Yield // release the burden of windows.h global namespace spam. #undef Yield // release the burden of windows.h global namespace spam.
#define AffinityAssert_AllowFrom_MainUI() \ #define AffinityAssert_AllowFrom_MainUI() \
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.") pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxThreadLog / ConsoleLogSource_Threading // pxThreadLog / ConsoleLogSource_Threading
@ -40,25 +40,25 @@
class ConsoleLogSource_Threading : ConsoleLogSource class ConsoleLogSource_Threading : ConsoleLogSource
{ {
typedef ConsoleLogSource _parent; typedef ConsoleLogSource _parent;
public: public:
using _parent::IsActive; using _parent::IsActive;
ConsoleLogSource_Threading(); ConsoleLogSource_Threading();
bool Write(const wxString &thrname, const wxChar *msg) bool Write(const wxString& thrname, const wxChar* msg)
{ {
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg); return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
} }
bool Warn(const wxString &thrname, const wxChar *msg) bool Warn(const wxString& thrname, const wxChar* msg)
{ {
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg); return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
} }
bool Error(const wxString &thrname, const wxChar *msg) bool Error(const wxString& thrname, const wxChar* msg)
{ {
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg); return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
} }
}; };
extern ConsoleLogSource_Threading pxConLog_Thread; extern ConsoleLogSource_Threading pxConLog_Thread;
@ -88,97 +88,97 @@ class wxTimeSpan;
namespace Threading namespace Threading
{ {
class pxThread; class pxThread;
class RwMutex; class RwMutex;
extern void pxTestCancel(); extern void pxTestCancel();
extern pxThread *pxGetCurrentThread(); extern pxThread* pxGetCurrentThread();
extern wxString pxGetCurrentThreadName(); extern wxString pxGetCurrentThreadName();
extern u64 GetThreadCpuTime(); extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond(); extern u64 GetThreadTicksPerSecond();
// Yields the current thread and provides cancellation points if the thread is managed by // Yields the current thread and provides cancellation points if the thread is managed by
// pxThread. Unmanaged threads use standard Sleep. // pxThread. Unmanaged threads use standard Sleep.
extern void pxYield(int ms); extern void pxYield(int ms);
} } // namespace Threading
namespace Exception namespace Exception
{ {
class BaseThreadError : public RuntimeError class BaseThreadError : public RuntimeError
{ {
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError) DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(BaseThreadError) DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
public: public:
Threading::pxThread *m_thread; Threading::pxThread* m_thread;
protected: protected:
BaseThreadError() BaseThreadError()
{ {
m_thread = NULL; m_thread = NULL;
} }
public: public:
explicit BaseThreadError(Threading::pxThread *_thread) explicit BaseThreadError(Threading::pxThread* _thread)
{ {
m_thread = _thread; m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)"; m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
} }
explicit BaseThreadError(Threading::pxThread &_thread) explicit BaseThreadError(Threading::pxThread& _thread)
{ {
m_thread = &_thread; m_thread = &_thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)"; m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
} }
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
Threading::pxThread &Thread(); Threading::pxThread& Thread();
const Threading::pxThread &Thread() const; const Threading::pxThread& Thread() const;
}; };
class ThreadCreationError : public BaseThreadError class ThreadCreationError : public BaseThreadError
{ {
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError) DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
public: public:
explicit ThreadCreationError(Threading::pxThread *_thread) explicit ThreadCreationError(Threading::pxThread* _thread)
{ {
m_thread = _thread; m_thread = _thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread."); SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
} }
explicit ThreadCreationError(Threading::pxThread &_thread) explicit ThreadCreationError(Threading::pxThread& _thread)
{ {
m_thread = &_thread; m_thread = &_thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread."); SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
} }
}; };
} } // namespace Exception
namespace Threading namespace Threading
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Platform Specific External APIs // Platform Specific External APIs
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations, // The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp // which are found in WinThreads.cpp and LnxThreads.cpp
// Releases a timeslice to other threads. // Releases a timeslice to other threads.
extern void Timeslice(); extern void Timeslice();
// For use in spin/wait loops. // For use in spin/wait loops.
extern void SpinWait(); extern void SpinWait();
// Optional implementation to enable hires thread/process scheduler for the operating system. // Optional implementation to enable hires thread/process scheduler for the operating system.
// Needed by Windows, but might not be relevant to other platforms. // Needed by Windows, but might not be relevant to other platforms.
extern void EnableHiresScheduler(); extern void EnableHiresScheduler();
extern void DisableHiresScheduler(); extern void DisableHiresScheduler();
// sleeps the current thread for the given number of milliseconds. // sleeps the current thread for the given number of milliseconds.
extern void Sleep(int ms); extern void Sleep(int ms);
// pthread Cond is an evil api that is not suited for Pcsx2 needs. // pthread Cond is an evil api that is not suited for Pcsx2 needs.
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air) // Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
@ -196,230 +196,230 @@ extern void Sleep(int ms);
}; };
#endif #endif
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// NonblockingMutex // NonblockingMutex
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's // This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable // trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange. // of blocking waits. It basically optimizes to a single InterlockedExchange.
// //
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread. // Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking // If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
// it later. // it later.
// //
class NonblockingMutex class NonblockingMutex
{ {
protected: protected:
std::atomic_flag val; std::atomic_flag val;
public: public:
NonblockingMutex() { val.clear(); } NonblockingMutex() { val.clear(); }
virtual ~NonblockingMutex() = default; virtual ~NonblockingMutex() = default;
bool TryAcquire() noexcept bool TryAcquire() noexcept
{ {
return !val.test_and_set(); return !val.test_and_set();
} }
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object // Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
bool IsLocked() bool IsLocked()
{ {
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex"); pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
return false; return false;
} }
void Release() void Release()
{ {
val.clear(); val.clear();
} }
}; };
class Semaphore class Semaphore
{ {
protected: protected:
#ifdef __APPLE__ #ifdef __APPLE__
semaphore_t m_sema; semaphore_t m_sema;
int m_counter; int m_counter;
#else #else
sem_t m_sema; sem_t m_sema;
#endif #endif
public: public:
Semaphore(); Semaphore();
virtual ~Semaphore(); virtual ~Semaphore();
void Reset(); void Reset();
void Post(); void Post();
void Post(int multiple); void Post(int multiple);
void WaitWithoutYield(); void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan &timeout); bool WaitWithoutYield(const wxTimeSpan& timeout);
void WaitNoCancel(); void WaitNoCancel();
void WaitNoCancel(const wxTimeSpan &timeout); void WaitNoCancel(const wxTimeSpan& timeout);
int Count(); int Count();
void Wait(); void Wait();
bool Wait(const wxTimeSpan &timeout); bool Wait(const wxTimeSpan& timeout);
}; };
class Mutex class Mutex
{ {
protected: protected:
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
public: public:
Mutex(); Mutex();
virtual ~Mutex(); virtual ~Mutex();
virtual bool IsRecursive() const { return false; } virtual bool IsRecursive() const { return false; }
void Recreate(); void Recreate();
bool RecreateIfLocked(); bool RecreateIfLocked();
void Detach(); void Detach();
void Acquire(); void Acquire();
bool Acquire(const wxTimeSpan &timeout); bool Acquire(const wxTimeSpan& timeout);
bool TryAcquire(); bool TryAcquire();
void Release(); void Release();
void AcquireWithoutYield(); void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan &timeout); bool AcquireWithoutYield(const wxTimeSpan& timeout);
void Wait(); void Wait();
bool Wait(const wxTimeSpan &timeout); bool Wait(const wxTimeSpan& timeout);
void WaitWithoutYield(); void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan &timeout); bool WaitWithoutYield(const wxTimeSpan& timeout);
protected: protected:
// empty constructor used by MutexLockRecursive // empty constructor used by MutexLockRecursive
Mutex(bool) {} Mutex(bool) {}
}; };
class MutexRecursive : public Mutex class MutexRecursive : public Mutex
{ {
public: public:
MutexRecursive(); MutexRecursive();
virtual ~MutexRecursive(); virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; } virtual bool IsRecursive() const { return true; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ScopedLock // ScopedLock
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Helper class for using Mutexes. Using this class provides an exception-safe (and // Helper class for using Mutexes. Using this class provides an exception-safe (and
// generally clean) method of locking code inside a function or conditional block. The lock // generally clean) method of locking code inside a function or conditional block. The lock
// will be automatically released on any return or exit from the function. // will be automatically released on any return or exit from the function.
// //
// Const qualification note: // Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified // ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales: // by locking and unlocking. Two rationales:
// //
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes, // 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
// this class needs a const hack to allow those accessors to be const (which is typically // this class needs a const hack to allow those accessors to be const (which is typically
// *very* important). // *very* important).
// //
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or // 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
// scope exits, by any means. Only via manual calls to Release or Acquire does that // scope exits, by any means. Only via manual calls to Release or Acquire does that
// change, and typically those are only used in very special circumstances of their own. // change, and typically those are only used in very special circumstances of their own.
// //
class ScopedLock class ScopedLock
{ {
DeclareNoncopyableObject(ScopedLock); DeclareNoncopyableObject(ScopedLock);
protected: protected:
Mutex *m_lock; Mutex* m_lock;
bool m_IsLocked; bool m_IsLocked;
public: public:
virtual ~ScopedLock(); virtual ~ScopedLock();
explicit ScopedLock(const Mutex *locker = NULL); explicit ScopedLock(const Mutex* locker = NULL);
explicit ScopedLock(const Mutex &locker); explicit ScopedLock(const Mutex& locker);
void AssignAndLock(const Mutex &locker); void AssignAndLock(const Mutex& locker);
void AssignAndLock(const Mutex *locker); void AssignAndLock(const Mutex* locker);
void Assign(const Mutex &locker); void Assign(const Mutex& locker);
void Assign(const Mutex *locker); void Assign(const Mutex* locker);
void Release(); void Release();
void Acquire(); void Acquire();
bool IsLocked() const { return m_IsLocked; } bool IsLocked() const { return m_IsLocked; }
protected: protected:
// Special constructor used by ScopedTryLock // Special constructor used by ScopedTryLock
ScopedLock(const Mutex &locker, bool isTryLock); ScopedLock(const Mutex& locker, bool isTryLock);
}; };
class ScopedTryLock : public ScopedLock class ScopedTryLock : public ScopedLock
{ {
public: public:
ScopedTryLock(const Mutex &locker) ScopedTryLock(const Mutex& locker)
: ScopedLock(locker, true) : ScopedLock(locker, true)
{ {
} }
virtual ~ScopedTryLock() = default; virtual ~ScopedTryLock() = default;
bool Failed() const { return !m_IsLocked; } bool Failed() const { return !m_IsLocked; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ScopedNonblockingLock // ScopedNonblockingLock
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details. // A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
// //
class ScopedNonblockingLock class ScopedNonblockingLock
{ {
DeclareNoncopyableObject(ScopedNonblockingLock); DeclareNoncopyableObject(ScopedNonblockingLock);
protected: protected:
NonblockingMutex &m_lock; NonblockingMutex& m_lock;
bool m_IsLocked; bool m_IsLocked;
public: public:
ScopedNonblockingLock(NonblockingMutex &locker) ScopedNonblockingLock(NonblockingMutex& locker)
: m_lock(locker) : m_lock(locker)
, m_IsLocked(m_lock.TryAcquire()) , m_IsLocked(m_lock.TryAcquire())
{ {
} }
virtual ~ScopedNonblockingLock() virtual ~ScopedNonblockingLock()
{ {
if (m_IsLocked) if (m_IsLocked)
m_lock.Release(); m_lock.Release();
} }
bool Failed() const { return !m_IsLocked; } bool Failed() const { return !m_IsLocked; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// ScopedLockBool // ScopedLockBool
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks. // A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
// Note that the isLockedBool should only be used as an indicator for the locked status, // Note that the isLockedBool should only be used as an indicator for the locked status,
// and not actually depended on for thread synchronization... // and not actually depended on for thread synchronization...
struct ScopedLockBool struct ScopedLockBool
{ {
ScopedLock m_lock; ScopedLock m_lock;
std::atomic<bool> &m_bool; std::atomic<bool>& m_bool;
ScopedLockBool(Mutex &mutexToLock, std::atomic<bool> &isLockedBool) ScopedLockBool(Mutex& mutexToLock, std::atomic<bool>& isLockedBool)
: m_lock(mutexToLock) : m_lock(mutexToLock)
, m_bool(isLockedBool) , m_bool(isLockedBool)
{ {
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed); m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
} }
virtual ~ScopedLockBool() virtual ~ScopedLockBool()
{ {
m_bool.store(false, std::memory_order_relaxed); m_bool.store(false, std::memory_order_relaxed);
} }
void Acquire() void Acquire()
{ {
m_lock.Acquire(); m_lock.Acquire();
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed); m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
} }
void Release() void Release()
{ {
m_bool.store(false, std::memory_order_relaxed); m_bool.store(false, std::memory_order_relaxed);
m_lock.Release(); m_lock.Release();
} }
}; };
} } // namespace Threading

View File

@ -25,60 +25,60 @@ wxDEFINE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers); wxIMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers);
Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString &title, const wxString &heading) Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString& title, const wxString& heading)
: wxDialogWithHelpers(NULL, _("Waiting for tasks...")) : wxDialogWithHelpers(NULL, _("Waiting for tasks..."))
//, m_Timer(this) //, m_Timer(this)
{ {
SetMinWidth(300); SetMinWidth(300);
//m_sem = sem; //m_sem = sem;
//m_mutex = mutex; //m_mutex = mutex;
wxString m_title(title); wxString m_title(title);
wxString m_heading(heading); wxString m_heading(heading);
if (m_title.IsEmpty()) if (m_title.IsEmpty())
m_title = _("Waiting for task..."); m_title = _("Waiting for task...");
if (m_heading.IsEmpty()) if (m_heading.IsEmpty())
m_heading = m_title; m_heading = m_title;
Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this); Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this);
*this += 12; *this += 12;
*this += Heading(m_heading).Unwrapped() | StdExpand(); *this += Heading(m_heading).Unwrapped() | StdExpand();
*this += 12; *this += 12;
// TODO : Implement a cancel button. Not quite sure the best way to do // TODO : Implement a cancel button. Not quite sure the best way to do
// that, since it requires a thread or event handler context, or something. // that, since it requires a thread or event handler context, or something.
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter; //applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
//applyDlg += 6; //applyDlg += 6;
//Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId()); //Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId());
//m_Timer.Start( 200 ); //m_Timer.Start( 200 );
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) ); //GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
} }
void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent &evt) void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent& evt)
{ {
evt.Skip(); evt.Skip();
// Note: we don't throw exceptions from the pending task here. // Note: we don't throw exceptions from the pending task here.
// Instead we wait until we exit the modal loop below -- this gives // Instead we wait until we exit the modal loop below -- this gives
// the caller a chance to handle the exception themselves, and if // the caller a chance to handle the exception themselves, and if
// not the exception will still fall back on the standard app-level // not the exception will still fall back on the standard app-level
// exception handler. // exception handler.
// (this also avoids any sticky business with the modal dialog not getting // (this also avoids any sticky business with the modal dialog not getting
// closed out right due to stack unwinding skipping dialog closure crap) // closed out right due to stack unwinding skipping dialog closure crap)
m_sync.WaitForResult_NoExceptions(); m_sync.WaitForResult_NoExceptions();
EndModal(wxID_OK); EndModal(wxID_OK);
} }
int Threading::WaitForTaskDialog::ShowModal() int Threading::WaitForTaskDialog::ShowModal()
{ {
int result = _parent::ShowModal(); int result = _parent::ShowModal();
m_sync.RethrowException(); m_sync.RethrowException();
return result; return result;
} }

View File

@ -22,31 +22,31 @@ wxDECLARE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
namespace Threading namespace Threading
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// WaitForTaskDialog // WaitForTaskDialog
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// This dialog is displayed whenever the main thread is recursively waiting on multiple // This dialog is displayed whenever the main thread is recursively waiting on multiple
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events // mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
// but it *does* support opening a modal dialog, which disables the interface (preventing // but it *does* support opening a modal dialog, which disables the interface (preventing
// the user from starting additional actions), and processes messages (allowing the system // the user from starting additional actions), and processes messages (allowing the system
// to continue to manage threads and process logging). // to continue to manage threads and process logging).
// //
class WaitForTaskDialog : public wxDialogWithHelpers class WaitForTaskDialog : public wxDialogWithHelpers
{ {
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog); wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
typedef wxDialogWithHelpers _parent; typedef wxDialogWithHelpers _parent;
protected: protected:
SynchronousActionState m_sync; SynchronousActionState m_sync;
public: public:
WaitForTaskDialog(const wxString &title = wxEmptyString, const wxString &heading = wxEmptyString); WaitForTaskDialog(const wxString& title = wxEmptyString, const wxString& heading = wxEmptyString);
virtual ~WaitForTaskDialog() = default; virtual ~WaitForTaskDialog() = default;
virtual int ShowModal(); virtual int ShowModal();
protected: protected:
void OnTaskComplete(wxCommandEvent &evt); void OnTaskComplete(wxCommandEvent& evt);
//void OnTimer( wxTimerEvent& evt ); //void OnTimer( wxTimerEvent& evt );
}; };
} } // namespace Threading

View File

@ -21,10 +21,10 @@
namespace Threading namespace Threading
{ {
extern const wxTimeSpan def_yieldgui_interval; extern const wxTimeSpan def_yieldgui_interval;
extern bool _WaitGui_RecursionGuard(const wxChar *name); extern bool _WaitGui_RecursionGuard(const wxChar* name);
extern void YieldToMain(); extern void YieldToMain();
extern bool AllowDeletions(); extern bool AllowDeletions();
} } // namespace Threading

View File

@ -29,20 +29,20 @@
// //
struct TraceLogDescriptor struct TraceLogDescriptor
{ {
// short name, alphanumerics only: used for saving/loading options. // short name, alphanumerics only: used for saving/loading options.
const wxChar *ShortName; const wxChar* ShortName;
// Standard UI name for this log source. Used in menus, options dialogs. // Standard UI name for this log source. Used in menus, options dialogs.
const wxChar *Name; const wxChar* Name;
// Length description for use as a tooltip or menu item description. // Length description for use as a tooltip or menu item description.
const wxChar *Description; const wxChar* Description;
wxString GetShortName() const wxString GetShortName() const
{ {
pxAssumeDev(Name, "Tracelog descriptors require a valid name!"); pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
return ShortName ? ShortName : Name; return ShortName ? ShortName : Name;
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -66,51 +66,51 @@ struct TraceLogDescriptor
class BaseTraceLogSource class BaseTraceLogSource
{ {
protected: protected:
const TraceLogDescriptor *m_Descriptor; const TraceLogDescriptor* m_Descriptor;
public: public:
// Indicates if the user has enabled this specific log. This boolean only represents // Indicates if the user has enabled this specific log. This boolean only represents
// the configured status of this log, and does *NOT* actually mean the log is active // the configured status of this log, and does *NOT* actually mean the log is active
// even when TRUE. Because many tracelogs have master enablers that act on a group // even when TRUE. Because many tracelogs have master enablers that act on a group
// of logs, logging checks should always use IsActive() instead to determine if a log // of logs, logging checks should always use IsActive() instead to determine if a log
// should be processed or not. // should be processed or not.
bool Enabled; bool Enabled;
protected: protected:
BaseTraceLogSource() BaseTraceLogSource()
: m_Descriptor(NULL) : m_Descriptor(NULL)
, Enabled(false) , Enabled(false)
{ {
} }
public: public:
TraceLog_ImplementBaseAPI(BaseTraceLogSource) TraceLog_ImplementBaseAPI(BaseTraceLogSource)
BaseTraceLogSource(const TraceLogDescriptor *desc) BaseTraceLogSource(const TraceLogDescriptor* desc)
{ {
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor."); pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
Enabled = false; Enabled = false;
m_Descriptor = desc; m_Descriptor = desc;
} }
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form. // Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
// (use periods in favor of colons, since they do not require escape characters when // (use periods in favor of colons, since they do not require escape characters when
// written to ini/config files). // written to ini/config files).
virtual wxString GetCategory() const { return wxEmptyString; } virtual wxString GetCategory() const { return wxEmptyString; }
// This method should be used to determine if a log should be generated or not. // This method should be used to determine if a log should be generated or not.
// See the class overview comments for details on how and why this method should // See the class overview comments for details on how and why this method should
// be used. // be used.
virtual bool IsActive() const { return Enabled; } virtual bool IsActive() const { return Enabled; }
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); } virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
virtual const wxChar *GetName() const { return m_Descriptor->Name; } virtual const wxChar* GetName() const { return m_Descriptor->Name; }
virtual const wxChar *GetDescription() const virtual const wxChar* GetDescription() const
{ {
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString; return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
} }
virtual bool HasDescription() const { return m_Descriptor->Description != NULL; } virtual bool HasDescription() const { return m_Descriptor->Description != NULL; }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -122,32 +122,32 @@ public:
class TextFileTraceLog : public BaseTraceLogSource class TextFileTraceLog : public BaseTraceLogSource
{ {
public: public:
TextFileTraceLog(const TraceLogDescriptor *desc) TextFileTraceLog(const TraceLogDescriptor* desc)
: BaseTraceLogSource(desc) : BaseTraceLogSource(desc)
{ {
} }
bool Write(const char *fmt, ...) const bool Write(const char* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool WriteV(const char *fmt, va_list list) const bool WriteV(const char* fmt, va_list list) const
{ {
FastFormatAscii ascii; FastFormatAscii ascii;
ApplyPrefix(ascii); ApplyPrefix(ascii);
ascii.WriteV(fmt, list); ascii.WriteV(fmt, list);
DoWrite(ascii); DoWrite(ascii);
return false; return false;
} }
virtual void ApplyPrefix(FastFormatAscii &ascii) const {} virtual void ApplyPrefix(FastFormatAscii& ascii) const {}
virtual void DoWrite(const char *fmt) const = 0; virtual void DoWrite(const char* fmt) const = 0;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -159,130 +159,130 @@ public:
class ConsoleLogSource : public BaseTraceLogSource class ConsoleLogSource : public BaseTraceLogSource
{ {
public: public:
ConsoleColors DefaultColor; ConsoleColors DefaultColor;
protected: protected:
ConsoleLogSource() ConsoleLogSource()
: DefaultColor(Color_Gray) : DefaultColor(Color_Gray)
{ {
} }
public: public:
ConsoleLog_ImplementBaseAPI(ConsoleLogSource) ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
ConsoleLogSource(const TraceLogDescriptor *desc, ConsoleColors defaultColor = Color_Gray) ConsoleLogSource(const TraceLogDescriptor* desc, ConsoleColors defaultColor = Color_Gray)
: BaseTraceLogSource(desc) : BaseTraceLogSource(desc)
{ {
DefaultColor = defaultColor; DefaultColor = defaultColor;
} }
// Writes to the console using the source's default color. Note that the source's default // Writes to the console using the source's default color. Note that the source's default
// color will always be used, thus ConsoleColorScope() will not be effectual unless the // color will always be used, thus ConsoleColorScope() will not be effectual unless the
// console's default color is Color_Default. // console's default color is Color_Default.
bool Write(const char *fmt, ...) const bool Write(const char* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool Write(const wxChar *fmt, ...) const bool Write(const wxChar* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt, list); WriteV(fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool Write(const wxString fmt, ...) const bool Write(const wxString fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(fmt.wx_str(), list); WriteV(fmt.wx_str(), list);
va_end(list); va_end(list);
return false; return false;
} }
// Writes to the console using the specified color. This overrides the default color setting // Writes to the console using the specified color. This overrides the default color setting
// for this log. // for this log.
bool Write(ConsoleColors color, const char *fmt, ...) const bool Write(ConsoleColors color, const char* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(color, fmt, list); WriteV(color, fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool Write(ConsoleColors color, const wxChar *fmt, ...) const bool Write(ConsoleColors color, const wxChar* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(color, fmt, list); WriteV(color, fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
// Writes to the console using bold yellow text -- overrides the log source's default // Writes to the console using bold yellow text -- overrides the log source's default
// color settings. // color settings.
bool Warn(const wxChar *fmt, ...) const bool Warn(const wxChar* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(Color_StrongYellow, fmt, list); WriteV(Color_StrongYellow, fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool Warn(const wxString fmt, ...) const bool Warn(const wxString fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(Color_StrongYellow, fmt.wx_str(), list); WriteV(Color_StrongYellow, fmt.wx_str(), list);
va_end(list); va_end(list);
return false; return false;
} }
// Writes to the console using bold red text -- overrides the log source's default // Writes to the console using bold red text -- overrides the log source's default
// color settings. // color settings.
bool Error(const wxChar *fmt, ...) const bool Error(const wxChar* fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(Color_StrongRed, fmt, list); WriteV(Color_StrongRed, fmt, list);
va_end(list); va_end(list);
return false; return false;
} }
bool Error(const wxString fmt, ...) const bool Error(const wxString fmt, ...) const
{ {
va_list list; va_list list;
va_start(list, fmt); va_start(list, fmt);
WriteV(Color_StrongRed, fmt.wx_str(), list); WriteV(Color_StrongRed, fmt.wx_str(), list);
va_end(list); va_end(list);
return false; return false;
} }
bool WriteV(const char *fmt, va_list list) const; bool WriteV(const char* fmt, va_list list) const;
bool WriteV(const wxChar *fmt, va_list list) const; bool WriteV(const wxChar* fmt, va_list list) const;
bool WriteV(ConsoleColors color, const char *fmt, va_list list) const; bool WriteV(ConsoleColors color, const char* fmt, va_list list) const;
bool WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const; bool WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const;
virtual void DoWrite(const wxChar *msg) const virtual void DoWrite(const wxChar* msg) const
{ {
Console.DoWriteLn(msg); Console.DoWriteLn(msg);
} }
}; };

View File

@ -22,18 +22,19 @@
template class EventSource<IEventListener_PageFault>; template class EventSource<IEventListener_PageFault>;
SrcType_PageFault *Source_PageFault = NULL; SrcType_PageFault* Source_PageFault = NULL;
Threading::Mutex PageFault_Mutex; Threading::Mutex PageFault_Mutex;
void pxInstallSignalHandler() void pxInstallSignalHandler()
{ {
if (!Source_PageFault) { if (!Source_PageFault)
Source_PageFault = new SrcType_PageFault(); {
} Source_PageFault = new SrcType_PageFault();
}
_platform_InstallSignalHandler(); _platform_InstallSignalHandler();
// NOP on Win32 systems -- we use __try{} __except{} instead. // NOP on Win32 systems -- we use __try{} __except{} instead.
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -41,200 +42,221 @@ void pxInstallSignalHandler()
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
EventListener_PageFault::EventListener_PageFault() EventListener_PageFault::EventListener_PageFault()
{ {
pxAssert(Source_PageFault); pxAssert(Source_PageFault);
Source_PageFault->Add(*this); Source_PageFault->Add(*this);
} }
EventListener_PageFault::~EventListener_PageFault() EventListener_PageFault::~EventListener_PageFault()
{ {
if (Source_PageFault) if (Source_PageFault)
Source_PageFault->Remove(*this); Source_PageFault->Remove(*this);
} }
void SrcType_PageFault::Dispatch(const PageFaultInfo &params) void SrcType_PageFault::Dispatch(const PageFaultInfo& params)
{ {
m_handled = false; m_handled = false;
_parent::Dispatch(params); _parent::Dispatch(params);
} }
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt) void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt)
{ {
do { do
(*iter)->DispatchEvent(evt, m_handled); {
} while ((++iter != iend) && !m_handled); (*iter)->DispatchEvent(evt, m_handled);
} while ((++iter != iend) && !m_handled);
} }
static size_t pageAlign(size_t size) static size_t pageAlign(size_t size)
{ {
return (size + __pagesize - 1) / __pagesize * __pagesize; return (size + __pagesize - 1) / __pagesize * __pagesize;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// VirtualMemoryManager (implementations) // VirtualMemoryManager (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
VirtualMemoryManager::VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds, bool strict) VirtualMemoryManager::VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds, bool strict)
: m_name(name), m_baseptr(0), m_pageuse(nullptr), m_pages_reserved(0) : m_name(name)
, m_baseptr(0)
, m_pageuse(nullptr)
, m_pages_reserved(0)
{ {
if (!size) return; if (!size)
return;
uptr reserved_bytes = pageAlign(size); uptr reserved_bytes = pageAlign(size);
m_pages_reserved = reserved_bytes / __pagesize; m_pages_reserved = reserved_bytes / __pagesize;
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes); m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) { if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...", {
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size)); DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
SafeSysMunmap(m_baseptr, reserved_bytes); SafeSysMunmap(m_baseptr, reserved_bytes);
if (base) { if (base)
// Let's try again at an OS-picked memory area, and then hope it meets needed {
// boundschecking criteria below. // Let's try again at an OS-picked memory area, and then hope it meets needed
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes); // boundschecking criteria below.
} m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
} }
}
bool fulfillsRequirements = true; bool fulfillsRequirements = true;
if (strict && m_baseptr != base) if (strict && m_baseptr != base)
fulfillsRequirements = false; fulfillsRequirements = false;
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds)) if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
fulfillsRequirements = false; fulfillsRequirements = false;
if (!fulfillsRequirements) { if (!fulfillsRequirements)
SafeSysMunmap(m_baseptr, reserved_bytes); {
} SafeSysMunmap(m_baseptr, reserved_bytes);
}
if (!m_baseptr) return; if (!m_baseptr)
return;
m_pageuse = new std::atomic<bool>[m_pages_reserved](); m_pageuse = new std::atomic<bool>[m_pages_reserved]();
FastFormatUnicode mbkb; FastFormatUnicode mbkb;
uint mbytes = reserved_bytes / _1mb; uint mbytes = reserved_bytes / _1mb;
if (mbytes) if (mbytes)
mbkb.Write("[%umb]", mbytes); mbkb.Write("[%umb]", mbytes);
else else
mbkb.Write("[%ukb]", reserved_bytes / 1024); mbkb.Write("[%ukb]", reserved_bytes / 1024);
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name), DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str()); pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
} }
VirtualMemoryManager::~VirtualMemoryManager() VirtualMemoryManager::~VirtualMemoryManager()
{ {
if (m_pageuse) delete[] m_pageuse; if (m_pageuse)
if (m_baseptr) HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize); delete[] m_pageuse;
if (m_baseptr)
HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
} }
static bool VMMMarkPagesAsInUse(std::atomic<bool> *begin, std::atomic<bool> *end) { static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
for (auto current = begin; current < end; current++) {
bool expected = false;
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed) {
// This was already allocated! Undo the things we've set until this point
while (--current >= begin) {
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
// In the time we were doing this, someone set one of the things we just set to true back to false
// This should never happen, but if it does we'll just stop and hope nothing bad happens
pxAssert(0);
return false;
}
}
return false;
}
}
return true;
}
void *VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
{ {
size = pageAlign(size); for (auto current = begin; current < end; current++)
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation")) {
return nullptr; bool expected = false;
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area")) if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed)
return nullptr; {
if (m_baseptr == 0) // This was already allocated! Undo the things we've set until this point
return nullptr; while (--current >= begin)
auto puStart = &m_pageuse[offsetLocation / __pagesize]; {
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize]; if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed))
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped")) {
return nullptr; // In the time we were doing this, someone set one of the things we just set to true back to false
return (void *)(m_baseptr + offsetLocation); // This should never happen, but if it does we'll just stop and hope nothing bad happens
pxAssert(0);
return false;
}
}
return false;
}
}
return true;
} }
void VirtualMemoryManager::Free(void *address, size_t size) const void* VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
{ {
uptr offsetLocation = (uptr)address - m_baseptr; size = pageAlign(size);
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address")) { if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
uptr newLoc = pageAlign(offsetLocation); return nullptr;
size -= (offsetLocation - newLoc); if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
offsetLocation = newLoc; return nullptr;
} if (m_baseptr == 0)
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size")) return nullptr;
size -= size % __pagesize; auto puStart = &m_pageuse[offsetLocation / __pagesize];
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area")) auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
return; if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
auto puStart = &m_pageuse[offsetLocation / __pagesize]; return nullptr;
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize]; return (void*)(m_baseptr + offsetLocation);
for (; puStart < puEnd; puStart++) { }
bool expected = true;
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed)) { void VirtualMemoryManager::Free(void* address, size_t size) const
pxAssertDev(0, "(VirtaulMemoryManager) double-free"); {
} uptr offsetLocation = (uptr)address - m_baseptr;
} if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address"))
{
uptr newLoc = pageAlign(offsetLocation);
size -= (offsetLocation - newLoc);
offsetLocation = newLoc;
}
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
size -= size % __pagesize;
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
return;
auto puStart = &m_pageuse[offsetLocation / __pagesize];
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
for (; puStart < puEnd; puStart++)
{
bool expected = true;
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed))
{
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
}
}
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// VirtualMemoryBumpAllocator (implementations) // VirtualMemoryBumpAllocator (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size) VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
: m_allocator(std::move(allocator)), m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size)), m_endptr(m_baseptr + size) : m_allocator(std::move(allocator))
, m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size))
, m_endptr(m_baseptr + size)
{ {
if (m_baseptr.load() == 0) if (m_baseptr.load() == 0)
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager"); pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
} }
void *VirtualMemoryBumpAllocator::Alloc(size_t size) void* VirtualMemoryBumpAllocator::Alloc(size_t size)
{ {
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization) if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
return nullptr; return nullptr;
size_t reservedSize = pageAlign(size); size_t reservedSize = pageAlign(size);
uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed); uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory")) if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
return nullptr; return nullptr;
return (void *)out; return (void*)out;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// VirtualMemoryReserve (implementations) // VirtualMemoryReserve (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
VirtualMemoryReserve::VirtualMemoryReserve(const wxString &name, size_t size) VirtualMemoryReserve::VirtualMemoryReserve(const wxString& name, size_t size)
: m_name(name) : m_name(name)
{ {
m_defsize = size; m_defsize = size;
m_allocator = nullptr; m_allocator = nullptr;
m_pages_commited = 0; m_pages_commited = 0;
m_pages_reserved = 0; m_pages_reserved = 0;
m_baseptr = nullptr; m_baseptr = nullptr;
m_prot_mode = PageAccess_None(); m_prot_mode = PageAccess_None();
m_allow_writes = true; m_allow_writes = true;
} }
VirtualMemoryReserve &VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode &mode) VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode& mode)
{ {
m_prot_mode = mode; m_prot_mode = mode;
return *this; return *this;
} }
size_t VirtualMemoryReserve::GetSize(size_t requestedSize) size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
{ {
if (!requestedSize) if (!requestedSize)
return pageAlign(m_defsize); return pageAlign(m_defsize);
return pageAlign(requestedSize); return pageAlign(requestedSize);
} }
// Notes: // Notes:
@ -245,84 +267,85 @@ size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
// baseptr - the new base pointer that's about to be assigned // baseptr - the new base pointer that's about to be assigned
// size - size of the region pointed to by baseptr // size - size of the region pointed to by baseptr
// //
void *VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void * baseptr, size_t size) void* VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size)
{ {
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved.")) if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
return m_baseptr; return m_baseptr;
if (!size) if (!size)
return nullptr; return nullptr;
m_allocator = std::move(allocator); m_allocator = std::move(allocator);
m_baseptr = baseptr; m_baseptr = baseptr;
uptr reserved_bytes = pageAlign(size); uptr reserved_bytes = pageAlign(size);
m_pages_reserved = reserved_bytes / __pagesize; m_pages_reserved = reserved_bytes / __pagesize;
if (!m_baseptr) if (!m_baseptr)
return nullptr; return nullptr;
FastFormatUnicode mbkb; FastFormatUnicode mbkb;
uint mbytes = reserved_bytes / _1mb; uint mbytes = reserved_bytes / _1mb;
if (mbytes) if (mbytes)
mbkb.Write("[%umb]", mbytes); mbkb.Write("[%umb]", mbytes);
else else
mbkb.Write("[%ukb]", reserved_bytes / 1024); mbkb.Write("[%ukb]", reserved_bytes / 1024);
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name), DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str()); pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
return m_baseptr; return m_baseptr;
} }
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode &newmode) void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode& newmode)
{ {
if (!m_pages_commited) if (!m_pages_commited)
return; return;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode); HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
} }
// Clears all committed blocks, restoring the allocation to a reserve only. // Clears all committed blocks, restoring the allocation to a reserve only.
void VirtualMemoryReserve::Reset() void VirtualMemoryReserve::Reset()
{ {
if (!m_pages_commited) if (!m_pages_commited)
return; return;
ReprotectCommittedBlocks(PageAccess_None()); ReprotectCommittedBlocks(PageAccess_None());
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize); HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
m_pages_commited = 0; m_pages_commited = 0;
} }
void VirtualMemoryReserve::Release() void VirtualMemoryReserve::Release()
{ {
if (!m_baseptr) return; if (!m_baseptr)
Reset(); return;
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize); Reset();
m_baseptr = nullptr; m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
m_baseptr = nullptr;
} }
bool VirtualMemoryReserve::Commit() bool VirtualMemoryReserve::Commit()
{ {
if (!m_pages_reserved) if (!m_pages_reserved)
return false; return false;
if (!pxAssert(!m_pages_commited)) if (!pxAssert(!m_pages_commited))
return true; return true;
m_pages_commited = m_pages_reserved; m_pages_commited = m_pages_reserved;
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode); return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
} }
void VirtualMemoryReserve::AllowModification() void VirtualMemoryReserve::AllowModification()
{ {
m_allow_writes = true; m_allow_writes = true;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode); HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
} }
void VirtualMemoryReserve::ForbidModification() void VirtualMemoryReserve::ForbidModification()
{ {
m_allow_writes = false; m_allow_writes = false;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false)); HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
} }
@ -337,39 +360,43 @@ void VirtualMemoryReserve::ForbidModification()
// newsize - new size of the reserved buffer, in bytes. // newsize - new size of the reserved buffer, in bytes.
bool VirtualMemoryReserve::TryResize(uint newsize) bool VirtualMemoryReserve::TryResize(uint newsize)
{ {
uint newPages = pageAlign(newsize) / __pagesize; uint newPages = pageAlign(newsize) / __pagesize;
if (newPages > m_pages_reserved) { if (newPages > m_pages_reserved)
uint toReservePages = newPages - m_pages_reserved; {
uint toReserveBytes = toReservePages * __pagesize; uint toReservePages = newPages - m_pages_reserved;
uint toReserveBytes = toReservePages * __pagesize;
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages); DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes)) { if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes))
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name)); {
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes); Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
return false; Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
} return false;
}
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name), DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb); m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
} else if (newPages < m_pages_reserved) { }
if (m_pages_commited > newsize) else if (newPages < m_pages_reserved)
return false; {
if (m_pages_commited > newsize)
return false;
uint toRemovePages = m_pages_reserved - newPages; uint toRemovePages = m_pages_reserved - newPages;
uint toRemoveBytes = toRemovePages * __pagesize; uint toRemoveBytes = toRemovePages * __pagesize;
DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages); DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages);
m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes); m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes);
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name), DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb); m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
} }
m_pages_reserved = newPages; m_pages_reserved = newPages;
return true; return true;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -377,27 +404,27 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxString PageProtectionMode::ToString() const wxString PageProtectionMode::ToString() const
{ {
wxString modeStr; wxString modeStr;
if (m_read) if (m_read)
modeStr += L"Read"; modeStr += L"Read";
if (m_write) if (m_write)
modeStr += L"Write"; modeStr += L"Write";
if (m_exec) if (m_exec)
modeStr += L"Exec"; modeStr += L"Exec";
if (modeStr.IsEmpty()) if (modeStr.IsEmpty())
return L"NoAccess"; return L"NoAccess";
if (modeStr.Length() <= 5) if (modeStr.Length() <= 5)
modeStr += L"Only"; modeStr += L"Only";
return modeStr; return modeStr;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Common HostSys implementation // Common HostSys implementation
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
void HostSys::Munmap(void *base, size_t size) void HostSys::Munmap(void* base, size_t size)
{ {
Munmap((uptr)base, size); Munmap((uptr)base, size);
} }

View File

@ -18,136 +18,146 @@
#include "common/RedtapeWindows.h" #include "common/RedtapeWindows.h"
#include "common/PageFaultSource.h" #include "common/PageFaultSource.h"
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps) static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{ {
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
// Note: This exception can be accessed by the EE or MTVU thread // Note: This exception can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information // Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better... // so for now we lock this exception code unless someone can fix this better...
Threading::ScopedLock lock(PageFault_Mutex); Threading::ScopedLock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1])); Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
} }
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps) long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{ {
// Prevent recursive exception filtering by catching the exception from the filter here. // Prevent recursive exception filtering by catching the exception from the filter here.
// In the event that the filter causes an access violation (happened during shutdown // In the event that the filter causes an access violation (happened during shutdown
// because Source_PageFault was deallocated), this will allow the debugger to catch the // because Source_PageFault was deallocated), this will allow the debugger to catch the
// exception. // exception.
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that // TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
// work but I don't fully understand why some do and some don't. // work but I don't fully understand why some do and some don't.
__try { __try
return DoSysPageFaultExceptionFilter(eps); {
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return DoSysPageFaultExceptionFilter(eps);
return EXCEPTION_CONTINUE_SEARCH; }
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return EXCEPTION_CONTINUE_SEARCH;
}
} }
void _platform_InstallSignalHandler() void _platform_InstallSignalHandler()
{ {
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead #ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter); AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
#endif #endif
} }
static DWORD ConvertToWinApi(const PageProtectionMode &mode) static DWORD ConvertToWinApi(const PageProtectionMode& mode)
{ {
DWORD winmode = PAGE_NOACCESS; DWORD winmode = PAGE_NOACCESS;
// Windows has some really bizarre memory protection enumeration that uses bitwise // Windows has some really bizarre memory protection enumeration that uses bitwise
// numbering (like flags) but is in fact not a flag value. *Someone* from the early // numbering (like flags) but is in fact not a flag value. *Someone* from the early
// microsoft days wasn't a very good coder, me thinks. --air // microsoft days wasn't a very good coder, me thinks. --air
if (mode.CanExecute()) { if (mode.CanExecute())
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; {
} else if (mode.CanRead()) { winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY; }
} else if (mode.CanRead())
{
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
}
return winmode; return winmode;
} }
void *HostSys::MmapReservePtr(void *base, size_t size) void* HostSys::MmapReservePtr(void* base, size_t size)
{ {
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
} }
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode) bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
{ {
void *result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)); void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
if (result) if (result)
return true; return true;
const DWORD errcode = GetLastError(); const DWORD errcode = GetLastError();
if (errcode == ERROR_COMMITMENT_MINIMUM) { if (errcode == ERROR_COMMITMENT_MINIMUM)
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM); {
Sleep(1000); // Cut windows some time to rework its memory... Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
} else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) { Sleep(1000); // Cut windows some time to rework its memory...
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); }
return false; else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
} {
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
return false;
}
if (!pxDoOutOfMemory) if (!pxDoOutOfMemory)
return false; return false;
pxDoOutOfMemory(size); pxDoOutOfMemory(size);
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL; return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
} }
void HostSys::MmapResetPtr(void *base, size_t size) void HostSys::MmapResetPtr(void* base, size_t size)
{ {
VirtualFree(base, size, MEM_DECOMMIT); VirtualFree(base, size, MEM_DECOMMIT);
} }
void *HostSys::MmapReserve(uptr base, size_t size) void* HostSys::MmapReserve(uptr base, size_t size)
{ {
return MmapReservePtr((void *)base, size); return MmapReservePtr((void*)base, size);
} }
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode) bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
{ {
return MmapCommitPtr((void *)base, size, mode); return MmapCommitPtr((void*)base, size, mode);
} }
void HostSys::MmapReset(uptr base, size_t size) void HostSys::MmapReset(uptr base, size_t size)
{ {
MmapResetPtr((void *)base, size); MmapResetPtr((void*)base, size);
} }
void *HostSys::Mmap(uptr base, size_t size) void* HostSys::Mmap(uptr base, size_t size)
{ {
return VirtualAlloc((void *)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
} }
void HostSys::Munmap(uptr base, size_t size) void HostSys::Munmap(uptr base, size_t size)
{ {
if (!base) if (!base)
return; return;
//VirtualFree((void*)base, size, MEM_DECOMMIT); //VirtualFree((void*)base, size, MEM_DECOMMIT);
VirtualFree((void *)base, 0, MEM_RELEASE); VirtualFree((void*)base, 0, MEM_RELEASE);
} }
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode) void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{ {
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt( pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
L"Memory block size must be a multiple of the target platform's page size.\n" L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
__pagesize, __pagesize, size, size)); __pagesize, __pagesize, size, size));
DWORD OldProtect; // enjoy my uselessness, yo! DWORD OldProtect; // enjoy my uselessness, yo!
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect)) { if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect))
Exception::WinApiError apiError; {
Exception::WinApiError apiError;
apiError.SetDiagMsg( apiError.SetDiagMsg(
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)", pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str())); baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
pxFailDev(apiError.FormatDiagnosticMessage()); pxFailDev(apiError.FormatDiagnosticMessage());
} }
} }
#endif #endif

View File

@ -21,115 +21,118 @@
__fi void Threading::Sleep(int ms) __fi void Threading::Sleep(int ms)
{ {
::Sleep(ms); ::Sleep(ms);
} }
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption. // improve performance and reduce cpu power consumption.
__fi void Threading::SpinWait() __fi void Threading::SpinWait()
{ {
_mm_pause(); _mm_pause();
} }
__fi void Threading::EnableHiresScheduler() __fi void Threading::EnableHiresScheduler()
{ {
// This improves accuracy of Sleep() by some amount, and only adds a negligible amount of // This improves accuracy of Sleep() by some amount, and only adds a negligible amount of
// overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in // overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in
// particular may have a scheduler Period of 15 or 20ms to extend battery life. // particular may have a scheduler Period of 15 or 20ms to extend battery life.
// (note: this same trick is used by most multimedia software and games) // (note: this same trick is used by most multimedia software and games)
timeBeginPeriod(1); timeBeginPeriod(1);
} }
__fi void Threading::DisableHiresScheduler() __fi void Threading::DisableHiresScheduler()
{ {
timeEndPeriod(1); timeEndPeriod(1);
} }
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't // This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
// packed (but for any x86 CPU and microsoft compiler, they will be). // packed (but for any x86 CPU and microsoft compiler, they will be).
union FileTimeSucks union FileTimeSucks
{ {
FILETIME filetime; FILETIME filetime;
u64 u64time; u64 u64time;
}; };
u64 Threading::GetThreadCpuTime() u64 Threading::GetThreadCpuTime()
{ {
FileTimeSucks user, kernel; FileTimeSucks user, kernel;
FILETIME dummy; FILETIME dummy;
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime); GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time; return user.u64time + kernel.u64time;
} }
u64 Threading::GetThreadTicksPerSecond() u64 Threading::GetThreadTicksPerSecond()
{ {
return 10000000; return 10000000;
} }
u64 Threading::pxThread::GetCpuTime() const u64 Threading::pxThread::GetCpuTime() const
{ {
if (!m_native_handle) if (!m_native_handle)
return 0; return 0;
FileTimeSucks user, kernel; FileTimeSucks user, kernel;
FILETIME dummy; FILETIME dummy;
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime)) if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
return user.u64time + kernel.u64time; return user.u64time + kernel.u64time;
return 0; // thread prolly doesn't exist anymore. return 0; // thread prolly doesn't exist anymore.
} }
void Threading::pxThread::_platform_specific_OnStartInThread() void Threading::pxThread::_platform_specific_OnStartInThread()
{ {
// OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more), // OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
// however we own our process threads, so shouldn't matter in any case... // however we own our process threads, so shouldn't matter in any case...
m_native_id = (uptr)GetCurrentThreadId(); m_native_id = (uptr)GetCurrentThreadId();
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id); m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
pxAssertDev(m_native_handle, wxNullChar); pxAssertDev(m_native_handle, wxNullChar);
} }
void Threading::pxThread::_platform_specific_OnCleanupInThread() void Threading::pxThread::_platform_specific_OnCleanupInThread()
{ {
CloseHandle((HANDLE)m_native_handle); CloseHandle((HANDLE)m_native_handle);
} }
void Threading::SetNameOfCurrentThread(const char *name) void Threading::SetNameOfCurrentThread(const char* name)
{ {
// This feature needs Windows headers and MSVC's SEH support: // This feature needs Windows headers and MSVC's SEH support:
#if defined(_WIN32) && defined(_MSC_VER) #if defined(_WIN32) && defined(_MSC_VER)
// This code sample was borrowed form some obscure MSDN article. // This code sample was borrowed form some obscure MSDN article.
// In a rare bout of sanity, it's an actual Microsoft-published hack // In a rare bout of sanity, it's an actual Microsoft-published hack
// that actually works! // that actually works!
static const int MS_VC_EXCEPTION = 0x406D1388; static const int MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8) #pragma pack(push, 8)
struct THREADNAME_INFO struct THREADNAME_INFO
{ {
DWORD dwType; // Must be 0x1000. DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space). LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread). DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero. DWORD dwFlags; // Reserved for future use, must be zero.
}; };
#pragma pack(pop) #pragma pack(pop)
THREADNAME_INFO info; THREADNAME_INFO info;
info.dwType = 0x1000; info.dwType = 0x1000;
info.szName = name; info.szName = name;
info.dwThreadID = GetCurrentThreadId(); info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0; info.dwFlags = 0;
__try { __try
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); {
} __except (EXCEPTION_EXECUTE_HANDLER) { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
} }
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#endif #endif
} }

View File

@ -21,10 +21,10 @@
// FreeBSD/OsX need something far more complicated (apparently) // FreeBSD/OsX need something far more complicated (apparently)
void x86capabilities::CountLogicalCores() void x86capabilities::CountLogicalCores()
{ {
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1 // Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or // if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
// alternatives, apparently. // alternatives, apparently.
LogicalCores = wxThread::GetCPUCount(); LogicalCores = wxThread::GetCPUCount();
} }
// Not implemented yet for linux (see cpudetect_internal.h for details) // Not implemented yet for linux (see cpudetect_internal.h for details)

View File

@ -20,65 +20,66 @@
void x86capabilities::CountLogicalCores() void x86capabilities::CountLogicalCores()
{ {
DWORD_PTR vProcessCPUs; DWORD_PTR vProcessCPUs;
DWORD_PTR vSystemCPUs; DWORD_PTR vSystemCPUs;
LogicalCores = 1; LogicalCores = 1;
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs)) if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
return; return;
uint CPUs = 0; uint CPUs = 0;
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1) for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
if (vSystemCPUs & bit) if (vSystemCPUs & bit)
CPUs++; CPUs++;
LogicalCores = CPUs; LogicalCores = CPUs;
} }
SingleCoreAffinity::SingleCoreAffinity() SingleCoreAffinity::SingleCoreAffinity()
{ {
s_threadId = nullptr; s_threadId = nullptr;
s_oldmask = ERROR_INVALID_PARAMETER; s_oldmask = ERROR_INVALID_PARAMETER;
DWORD_PTR availProcCpus; DWORD_PTR availProcCpus;
DWORD_PTR availSysCpus; DWORD_PTR availSysCpus;
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus)) if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
return; return;
int cpu = 0; int cpu = 0;
DWORD_PTR affinityMask; DWORD_PTR affinityMask;
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu) for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
if (availProcCpus & affinityMask) if (availProcCpus & affinityMask)
break; break;
s_threadId = GetCurrentThread(); s_threadId = GetCurrentThread();
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask); s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
if (s_oldmask == ERROR_INVALID_PARAMETER) { if (s_oldmask == ERROR_INVALID_PARAMETER)
const int hexWidth = 2 * sizeof(DWORD_PTR); {
Console.Warning( const int hexWidth = 2 * sizeof(DWORD_PTR);
"CpuDetect: SetThreadAffinityMask failed...\n" Console.Warning(
"\tSystem Affinity : 0x%0*x\n" "CpuDetect: SetThreadAffinityMask failed...\n"
"\tProcess Affinity: 0x%0*x\n" "\tSystem Affinity : 0x%0*x\n"
"\tAttempted Thread Affinity CPU: %i", "\tProcess Affinity: 0x%0*x\n"
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu); "\tAttempted Thread Affinity CPU: %i",
} hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
}
Sleep(2); Sleep(2);
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This // Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
// means that the current thread will need to be switched to Core 0 if it's currently // means that the current thread will need to be switched to Core 0 if it's currently
// scheduled on a difference cpu/core. However, Windows does not necessarily perform // scheduled on a difference cpu/core. However, Windows does not necessarily perform
// that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent // that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent
// on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time // on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time
// to issue a timeslice and move our thread to Core 0. Without this, it tends to move // to issue a timeslice and move our thread to Core 0. Without this, it tends to move
// the thread during the cpuSpeed test instead, causing totally wacky results. // the thread during the cpuSpeed test instead, causing totally wacky results.
}; };
SingleCoreAffinity::~SingleCoreAffinity() SingleCoreAffinity::~SingleCoreAffinity()
{ {
if (s_oldmask != ERROR_INVALID_PARAMETER) if (s_oldmask != ERROR_INVALID_PARAMETER)
SetThreadAffinityMask(s_threadId, s_oldmask); SetThreadAffinityMask(s_threadId, s_oldmask);
} }
#endif #endif

View File

@ -19,17 +19,17 @@
namespace x86Emitter namespace x86Emitter
{ {
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6}; const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5}; const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5}; const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2}; const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const
{ {
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2); xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
} }
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const
{ {
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2); xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
} }
} } // namespace x86Emitter

View File

@ -31,12 +31,12 @@
static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count) static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count)
{ {
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); __cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
} }
static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType) static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType)
{ {
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); __cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
} }
#endif #endif
@ -46,23 +46,23 @@ using namespace x86Emitter;
__aligned16 x86capabilities x86caps; __aligned16 x86capabilities x86caps;
x86capabilities::x86capabilities() x86capabilities::x86capabilities()
: isIdentified(false) : isIdentified(false)
, VendorID(x86Vendor_Unknown) , VendorID(x86Vendor_Unknown)
, FamilyID(0) , FamilyID(0)
, Model(0) , Model(0)
, TypeID(0) , TypeID(0)
, StepID(0) , StepID(0)
, Flags(0) , Flags(0)
, Flags2(0) , Flags2(0)
, EFlags(0) , EFlags(0)
, EFlags2(0) , EFlags2(0)
, SEFlag(0) , SEFlag(0)
, AllCapabilities(0) , AllCapabilities(0)
, PhysicalCores(0) , PhysicalCores(0)
, LogicalCores(0) , LogicalCores(0)
{ {
memzero(VendorName); memzero(VendorName);
memzero(FamilyName); memzero(FamilyName);
} }
// Warning! We've had problems with the MXCSR detection code causing stack corruption in // Warning! We've had problems with the MXCSR detection code causing stack corruption in
@ -72,28 +72,29 @@ x86capabilities::x86capabilities()
// Note: recSSE was deleted // Note: recSSE was deleted
void x86capabilities::SIMD_EstablishMXCSRmask() void x86capabilities::SIMD_EstablishMXCSRmask()
{ {
if (!hasStreamingSIMDExtensions) if (!hasStreamingSIMDExtensions)
return; return;
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
if (hasStreamingSIMD2Extensions) { if (hasStreamingSIMD2Extensions)
// This is generally safe assumption, but FXSAVE is the "correct" way to {
// detect MXCSR masking features of the cpu, so we use it's result below // This is generally safe assumption, but FXSAVE is the "correct" way to
// and override this. // detect MXCSR masking features of the cpu, so we use it's result below
// and override this.
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
} }
__aligned16 u8 targetFXSAVE[512]; __aligned16 u8 targetFXSAVE[512];
// Work for recent enough GCC/CLANG/MSVC 2012 // Work for recent enough GCC/CLANG/MSVC 2012
_fxsave(&targetFXSAVE); _fxsave(&targetFXSAVE);
u32 result; u32 result;
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask. memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
if (result != 0) if (result != 0)
MXCSR_Mask.bitmask = result; MXCSR_Mask.bitmask = result;
} }
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter // Counts the number of cpu cycles executed over the requested number of PerformanceCounter
@ -103,221 +104,229 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
// by the operating system task switches. // by the operating system task switches.
s64 x86capabilities::_CPUSpeedHz(u64 time) const s64 x86capabilities::_CPUSpeedHz(u64 time) const
{ {
u64 timeStart, timeStop; u64 timeStart, timeStop;
s64 startCycle, endCycle; s64 startCycle, endCycle;
if (!hasTimeStampCounter) if (!hasTimeStampCounter)
return 0; return 0;
SingleCoreAffinity affinity_lock; SingleCoreAffinity affinity_lock;
// Align the cpu execution to a cpuTick boundary. // Align the cpu execution to a cpuTick boundary.
do { do
timeStart = GetCPUTicks(); {
startCycle = __rdtsc(); timeStart = GetCPUTicks();
} while (GetCPUTicks() == timeStart); startCycle = __rdtsc();
} while (GetCPUTicks() == timeStart);
do { do
timeStop = GetCPUTicks(); {
endCycle = __rdtsc(); timeStop = GetCPUTicks();
} while ((timeStop - timeStart) < time); endCycle = __rdtsc();
} while ((timeStop - timeStart) < time);
s64 cycleCount = endCycle - startCycle; s64 cycleCount = endCycle - startCycle;
s64 timeCount = timeStop - timeStart; s64 timeCount = timeStop - timeStart;
s64 overrun = timeCount - time; s64 overrun = timeCount - time;
if (!overrun) if (!overrun)
return cycleCount; return cycleCount;
// interference could cause us to overshoot the target time, compensate: // interference could cause us to overshoot the target time, compensate:
double cyclesPerTick = (double)cycleCount / (double)timeCount; double cyclesPerTick = (double)cycleCount / (double)timeCount;
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun); double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
return (s64)newCycleCount; return (s64)newCycleCount;
} }
wxString x86capabilities::GetTypeName() const wxString x86capabilities::GetTypeName() const
{ {
switch (TypeID) { switch (TypeID)
case 0: {
return L"Standard OEM"; case 0:
case 1: return L"Standard OEM";
return L"Overdrive"; case 1:
case 2: return L"Overdrive";
return L"Dual"; case 2:
case 3: return L"Dual";
return L"Reserved"; case 3:
default: return L"Reserved";
return L"Unknown"; default:
} return L"Unknown";
}
} }
void x86capabilities::CountCores() void x86capabilities::CountCores()
{ {
Identify(); Identify();
s32 regs[4]; s32 regs[4];
u32 cmds; u32 cmds;
cpuid(regs, 0x80000000); cpuid(regs, 0x80000000);
cmds = regs[0]; cmds = regs[0];
// detect multicore for AMD cpu // detect multicore for AMD cpu
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD)) { if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
// AMD note: they don't support hyperthreading, but they like to flag this true {
// anyway. Let's force-unflag it until we come up with a better solution. // AMD note: they don't support hyperthreading, but they like to flag this true
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do // anyway. Let's force-unflag it until we come up with a better solution.
// not seem to do this) --air // (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
hasMultiThreading = 0; // not seem to do this) --air
} hasMultiThreading = 0;
}
// This will assign values into LogicalCores and PhysicalCores // This will assign values into LogicalCores and PhysicalCores
CountLogicalCores(); CountLogicalCores();
} }
static const char *tbl_x86vendors[] = static const char* tbl_x86vendors[] =
{ {
"GenuineIntel", "GenuineIntel",
"AuthenticAMD", "AuthenticAMD",
"Unknown ", "Unknown ",
}; };
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for // Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
// the cpuSpeed and the mxcsr masks. Those must be completed manually. // the cpuSpeed and the mxcsr masks. Those must be completed manually.
void x86capabilities::Identify() void x86capabilities::Identify()
{ {
if (isIdentified) if (isIdentified)
return; return;
isIdentified = true; isIdentified = true;
s32 regs[4]; s32 regs[4];
u32 cmds; u32 cmds;
memzero(VendorName); memzero(VendorName);
cpuid(regs, 0); cpuid(regs, 0);
cmds = regs[0]; cmds = regs[0];
memcpy(&VendorName[0], &regs[1], 4); memcpy(&VendorName[0], &regs[1], 4);
memcpy(&VendorName[4], &regs[3], 4); memcpy(&VendorName[4], &regs[3], 4);
memcpy(&VendorName[8], &regs[2], 4); memcpy(&VendorName[8], &regs[2], 4);
// Determine Vendor Specifics! // Determine Vendor Specifics!
// It's really not recommended that we base much (if anything) on CPU vendor names, // It's really not recommended that we base much (if anything) on CPU vendor names,
// however it's currently necessary in order to gain a (pseudo)reliable count of cores // however it's currently necessary in order to gain a (pseudo)reliable count of cores
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available). // and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
int vid; int vid;
for (vid = 0; vid < x86Vendor_Unknown; ++vid) { for (vid = 0; vid < x86Vendor_Unknown; ++vid)
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0) {
break; if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
} break;
VendorID = static_cast<x86VendorType>(vid); }
VendorID = static_cast<x86VendorType>(vid);
if (cmds >= 0x00000001) { if (cmds >= 0x00000001)
cpuid(regs, 0x00000001); {
cpuid(regs, 0x00000001);
StepID = regs[0] & 0xf; StepID = regs[0] & 0xf;
Model = (regs[0] >> 4) & 0xf; Model = (regs[0] >> 4) & 0xf;
FamilyID = (regs[0] >> 8) & 0xf; FamilyID = (regs[0] >> 8) & 0xf;
TypeID = (regs[0] >> 12) & 0x3; TypeID = (regs[0] >> 12) & 0x3;
#ifdef __M_X86_64 #ifdef __M_X86_64
//u32 x86_64_8BITBRANDID = regs[1] & 0xff; //u32 x86_64_8BITBRANDID = regs[1] & 0xff;
#endif #endif
Flags = regs[3]; Flags = regs[3];
Flags2 = regs[2]; Flags2 = regs[2];
} }
if (cmds >= 0x00000007) { if (cmds >= 0x00000007)
// Note: ECX must be 0 for AVX2 detection. {
cpuidex(regs, 0x00000007, 0); // Note: ECX must be 0 for AVX2 detection.
cpuidex(regs, 0x00000007, 0);
SEFlag = regs[1]; SEFlag = regs[1];
} }
cpuid(regs, 0x80000000); cpuid(regs, 0x80000000);
cmds = regs[0]; cmds = regs[0];
if (cmds >= 0x80000001) { if (cmds >= 0x80000001)
cpuid(regs, 0x80000001); {
cpuid(regs, 0x80000001);
#ifdef __M_X86_64 #ifdef __M_X86_64
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff; //u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
#endif #endif
EFlags2 = regs[2]; EFlags2 = regs[2];
EFlags = regs[3]; EFlags = regs[3];
} }
memzero(FamilyName); memzero(FamilyName);
cpuid((int *)FamilyName, 0x80000002); cpuid((int*)FamilyName, 0x80000002);
cpuid((int *)(FamilyName + 16), 0x80000003); cpuid((int*)(FamilyName + 16), 0x80000003);
cpuid((int *)(FamilyName + 32), 0x80000004); cpuid((int*)(FamilyName + 32), 0x80000004);
hasFloatingPointUnit = (Flags >> 0) & 1; hasFloatingPointUnit = (Flags >> 0) & 1;
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1; hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
hasDebuggingExtensions = (Flags >> 2) & 1; hasDebuggingExtensions = (Flags >> 2) & 1;
hasPageSizeExtensions = (Flags >> 3) & 1; hasPageSizeExtensions = (Flags >> 3) & 1;
hasTimeStampCounter = (Flags >> 4) & 1; hasTimeStampCounter = (Flags >> 4) & 1;
hasModelSpecificRegisters = (Flags >> 5) & 1; hasModelSpecificRegisters = (Flags >> 5) & 1;
hasPhysicalAddressExtension = (Flags >> 6) & 1; hasPhysicalAddressExtension = (Flags >> 6) & 1;
hasMachineCheckArchitecture = (Flags >> 7) & 1; hasMachineCheckArchitecture = (Flags >> 7) & 1;
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1; hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1; hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
hasSEPFastSystemCall = (Flags >> 11) & 1; hasSEPFastSystemCall = (Flags >> 11) & 1;
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1; hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
hasPTEGlobalFlag = (Flags >> 13) & 1; hasPTEGlobalFlag = (Flags >> 13) & 1;
hasMachineCheckArchitecture = (Flags >> 14) & 1; hasMachineCheckArchitecture = (Flags >> 14) & 1;
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1; hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
hasFGPageAttributeTable = (Flags >> 16) & 1; hasFGPageAttributeTable = (Flags >> 16) & 1;
has36bitPageSizeExtension = (Flags >> 17) & 1; has36bitPageSizeExtension = (Flags >> 17) & 1;
hasProcessorSerialNumber = (Flags >> 18) & 1; hasProcessorSerialNumber = (Flags >> 18) & 1;
hasCFLUSHInstruction = (Flags >> 19) & 1; hasCFLUSHInstruction = (Flags >> 19) & 1;
hasDebugStore = (Flags >> 21) & 1; hasDebugStore = (Flags >> 21) & 1;
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1; hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1; hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2 hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
hasSelfSnoop = (Flags >> 27) & 1; hasSelfSnoop = (Flags >> 27) & 1;
hasMultiThreading = (Flags >> 28) & 1; hasMultiThreading = (Flags >> 28) & 1;
hasThermalMonitor = (Flags >> 29) & 1; hasThermalMonitor = (Flags >> 29) & 1;
hasIntel64BitArchitecture = (Flags >> 30) & 1; hasIntel64BitArchitecture = (Flags >> 30) & 1;
// ------------------------------------------------- // -------------------------------------------------
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <-- // --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
// ------------------------------------------------- // -------------------------------------------------
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3 hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3 hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1 hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2 hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
if ((Flags2 >> 27) & 1) // OSXSAVE if ((Flags2 >> 27) & 1) // OSXSAVE
{ {
// Note: In theory, we should use xgetbv to check OS support // Note: In theory, we should use xgetbv to check OS support
// but all OSes we officially run under support it // but all OSes we officially run under support it
// and its intrinsic requires extra compiler flags // and its intrinsic requires extra compiler flags
hasAVX = (Flags2 >> 28) & 1; //avx hasAVX = (Flags2 >> 28) & 1; //avx
hasFMA = (Flags2 >> 12) & 1; //fma hasFMA = (Flags2 >> 12) & 1; //fma
hasAVX2 = (SEFlag >> 5) & 1; //avx2 hasAVX2 = (SEFlag >> 5) & 1; //avx2
} }
hasBMI1 = (SEFlag >> 3) & 1; hasBMI1 = (SEFlag >> 3) & 1;
hasBMI2 = (SEFlag >> 8) & 1; hasBMI2 = (SEFlag >> 8) & 1;
// Ones only for AMDs: // Ones only for AMDs:
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
isIdentified = true; isIdentified = true;
} }
u32 x86capabilities::CalculateMHz() const u32 x86capabilities::CalculateMHz() const
{ {
InitCPUTicks(); InitCPUTicks();
u64 span = GetTickFrequency(); u64 span = GetTickFrequency();
if ((span % 1000) < 400) // helps minimize rounding errors if ((span % 1000) < 400) // helps minimize rounding errors
return (u32)(_CPUSpeedHz(span / 1000) / 1000); return (u32)(_CPUSpeedHz(span / 1000) / 1000);
else else
return (u32)(_CPUSpeedHz(span / 500) / 2000); return (u32)(_CPUSpeedHz(span / 500) / 2000);
} }

View File

@ -28,11 +28,11 @@ class SingleCoreAffinity
{ {
protected: protected:
#ifdef _WIN32 #ifdef _WIN32
HANDLE s_threadId; HANDLE s_threadId;
DWORD_PTR s_oldmask; DWORD_PTR s_oldmask;
#endif #endif
public: public:
SingleCoreAffinity(); SingleCoreAffinity();
virtual ~SingleCoreAffinity(); virtual ~SingleCoreAffinity();
}; };

View File

@ -21,9 +21,9 @@
/* fld m32 to fpu reg stack */ /* fld m32 to fpu reg stack */
emitterT void FLD32(u32 from) emitterT void FLD32(u32 from)
{ {
xWrite8(0xD9); xWrite8(0xD9);
ModRM(0, 0x0, DISP32); ModRM(0, 0x0, DISP32);
xWrite32(MEMADDR(from, 4)); xWrite32(MEMADDR(from, 4));
} }
// fld st(i) // fld st(i)
@ -34,9 +34,9 @@ emitterT void FLDL2E() { xWrite16(0xead9); }
/* fstp m32 from fpu reg stack */ /* fstp m32 from fpu reg stack */
emitterT void FSTP32(u32 to) emitterT void FSTP32(u32 to)
{ {
xWrite8(0xD9); xWrite8(0xD9);
ModRM(0, 0x3, DISP32); ModRM(0, 0x3, DISP32);
xWrite32(MEMADDR(to, 4)); xWrite32(MEMADDR(to, 4));
} }
// fstp st(i) // fstp st(i)
@ -52,21 +52,21 @@ emitterT void FSIN(void) { xWrite16(0xfed9); }
/* fadd ST(0) to fpu reg stack ST(src) */ /* fadd ST(0) to fpu reg stack ST(src) */
emitterT void FADD320toR(x86IntRegType src) emitterT void FADD320toR(x86IntRegType src)
{ {
xWrite8(0xDC); xWrite8(0xDC);
xWrite8(0xC0 + src); xWrite8(0xC0 + src);
} }
/* fsub ST(src) to fpu reg stack ST(0) */ /* fsub ST(src) to fpu reg stack ST(0) */
emitterT void FSUB32Rto0(x86IntRegType src) emitterT void FSUB32Rto0(x86IntRegType src)
{ {
xWrite8(0xD8); xWrite8(0xD8);
xWrite8(0xE0 + src); xWrite8(0xE0 + src);
} }
/* fmul m32 to fpu reg stack */ /* fmul m32 to fpu reg stack */
emitterT void FMUL32(u32 from) emitterT void FMUL32(u32 from)
{ {
xWrite8(0xD8); xWrite8(0xD8);
ModRM(0, 0x1, DISP32); ModRM(0, 0x1, DISP32);
xWrite32(MEMADDR(from, 4)); xWrite32(MEMADDR(from, 4));
} }

View File

@ -34,222 +34,237 @@
namespace x86Emitter namespace x86Emitter
{ {
// ===================================================================================================== // =====================================================================================================
// Group 1 Instructions - ADD, SUB, ADC, etc. // Group 1 Instructions - ADD, SUB, ADC, etc.
// ===================================================================================================== // =====================================================================================================
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a // Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates // compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
// with one of the other overloads). // with one of the other overloads).
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess &sibdest, int imm) static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
{ {
if (sibdest.Is8BitOp()) { if (sibdest.Is8BitOp())
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest); {
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
xWrite<s8>(imm); xWrite<s8>(imm);
} else { }
u8 opcode = is_s8(imm) ? 0x83 : 0x81; else
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize()); {
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
if (is_s8(imm)) if (is_s8(imm))
xWrite<s8>(imm); xWrite<s8>(imm);
else else
sibdest.xWriteImm(imm); sibdest.xWriteImm(imm);
} }
} }
void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from) void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from)
{ {
pxAssert(to.GetOperandSize() == from.GetOperandSize()); pxAssert(to.GetOperandSize() == from.GetOperandSize());
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3); u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, from, to); xOpWrite(to.GetPrefix16(), opcode, from, to);
} }
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid &sibdest, const xRegisterInt &from) static void _g1_EmitOp(G1Type InstType, const xIndirectVoid& sibdest, const xRegisterInt& from)
{ {
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3); u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(from.GetPrefix16(), opcode, from, sibdest); xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
} }
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xIndirectVoid &sibsrc) static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xIndirectVoid& sibsrc)
{ {
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3); u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc); xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
} }
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, int imm) static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
{ {
if (!to.Is8BitOp() && is_s8(imm)) { if (!to.Is8BitOp() && is_s8(imm))
xOpWrite(to.GetPrefix16(), 0x83, InstType, to); {
xWrite<s8>(imm); xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
} else { xWrite<s8>(imm);
if (to.IsAccumulator()) { }
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3); else
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to); {
} else { if (to.IsAccumulator())
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81; {
xOpWrite(to.GetPrefix16(), opcode, InstType, to); u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
} xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
to.xWriteImm(imm); }
} else
} {
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
}
to.xWriteImm(imm);
}
}
#define ImplementGroup1(g1type, insttype) \ #define ImplementGroup1(g1type, insttype) \
void g1type::operator()(const xRegisterInt &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \ void g1type::operator()(const xRegisterInt& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
void g1type::operator()(const xIndirectVoid &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \ void g1type::operator()(const xIndirectVoid& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
void g1type::operator()(const xRegisterInt &to, const xIndirectVoid &from) const { _g1_EmitOp(insttype, to, from); } \ void g1type::operator()(const xRegisterInt& to, const xIndirectVoid& from) const { _g1_EmitOp(insttype, to, from); } \
void g1type::operator()(const xRegisterInt &to, int imm) const { _g1_EmitOp(insttype, to, imm); } \ void g1type::operator()(const xRegisterInt& to, int imm) const { _g1_EmitOp(insttype, to, imm); } \
void g1type::operator()(const xIndirect64orLess &sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); } void g1type::operator()(const xIndirect64orLess& sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
ImplementGroup1(xImpl_Group1, InstType) ImplementGroup1(xImpl_Group1, InstType)
ImplementGroup1(xImpl_G1Logic, InstType) ImplementGroup1(xImpl_G1Logic, InstType)
ImplementGroup1(xImpl_G1Arith, InstType) ImplementGroup1(xImpl_G1Arith, InstType)
ImplementGroup1(xImpl_G1Compare, G1Type_CMP) ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}}; const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}}; const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}}; const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}}; const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}};
const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}}; const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}};
const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}}; const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
const xImpl_Group1 xADC = {G1Type_ADC}; const xImpl_Group1 xADC = {G1Type_ADC};
const xImpl_Group1 xSBB = {G1Type_SBB}; const xImpl_Group1 xSBB = {G1Type_SBB};
// ===================================================================================================== // =====================================================================================================
// Group 2 Instructions - SHR, SHL, etc. // Group 2 Instructions - SHR, SHL, etc.
// ===================================================================================================== // =====================================================================================================
void xImpl_Group2::operator()(const xRegisterInt &to, const xRegisterCL & /* from */) const void xImpl_Group2::operator()(const xRegisterInt& to, const xRegisterCL& /* from */) const
{ {
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to); xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
} }
void xImpl_Group2::operator()(const xRegisterInt &to, u8 imm) const void xImpl_Group2::operator()(const xRegisterInt& to, u8 imm) const
{ {
if (imm == 0) if (imm == 0)
return; return;
if (imm == 1) { if (imm == 1)
// special encoding of 1's {
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to); // special encoding of 1's
} else { xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to); }
xWrite8(imm); else
} {
} xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
xWrite8(imm);
}
}
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, const xRegisterCL & /* from */) const void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, const xRegisterCL& /* from */) const
{ {
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest); xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
} }
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, u8 imm) const void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, u8 imm) const
{ {
if (imm == 0) if (imm == 0)
return; return;
if (imm == 1) { if (imm == 1)
// special encoding of 1's {
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest); // special encoding of 1's
} else { xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1); }
xWrite8(imm); else
} {
} xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
xWrite8(imm);
}
}
const xImpl_Group2 xROL = {G2Type_ROL}; const xImpl_Group2 xROL = {G2Type_ROL};
const xImpl_Group2 xROR = {G2Type_ROR}; const xImpl_Group2 xROR = {G2Type_ROR};
const xImpl_Group2 xRCL = {G2Type_RCL}; const xImpl_Group2 xRCL = {G2Type_RCL};
const xImpl_Group2 xRCR = {G2Type_RCR}; const xImpl_Group2 xRCR = {G2Type_RCR};
const xImpl_Group2 xSHL = {G2Type_SHL}; const xImpl_Group2 xSHL = {G2Type_SHL};
const xImpl_Group2 xSHR = {G2Type_SHR}; const xImpl_Group2 xSHR = {G2Type_SHR};
const xImpl_Group2 xSAR = {G2Type_SAR}; const xImpl_Group2 xSAR = {G2Type_SAR};
// ===================================================================================================== // =====================================================================================================
// Group 3 Instructions - NOT, NEG, MUL, DIV // Group 3 Instructions - NOT, NEG, MUL, DIV
// ===================================================================================================== // =====================================================================================================
static void _g3_EmitOp(G3Type InstType, const xRegisterInt &from) static void _g3_EmitOp(G3Type InstType, const xRegisterInt& from)
{ {
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from); xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
} }
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess &from) static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess& from)
{ {
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from); xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
} }
void xImpl_Group3::operator()(const xRegisterInt &from) const { _g3_EmitOp(InstType, from); } void xImpl_Group3::operator()(const xRegisterInt& from) const { _g3_EmitOp(InstType, from); }
void xImpl_Group3::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(InstType, from); } void xImpl_Group3::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(InstType, from); }
void xImpl_iDiv::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iDIV, from); } void xImpl_iDiv::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iDIV, from); }
void xImpl_iDiv::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iDIV, from); } void xImpl_iDiv::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iDIV, from); }
template <typename SrcType> template <typename SrcType>
static void _imul_ImmStyle(const xRegisterInt &param1, const SrcType &param2, int imm) static void _imul_ImmStyle(const xRegisterInt& param1, const SrcType& param2, int imm)
{ {
pxAssert(param1.GetOperandSize() == param2.GetOperandSize()); pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize()); xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize());
if (is_s8(imm)) if (is_s8(imm))
xWrite8((u8)imm); xWrite8((u8)imm);
else else
param1.xWriteImm(imm); param1.xWriteImm(imm);
} }
void xImpl_iMul::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iMUL, from); } void xImpl_iMul::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iMUL, from); }
void xImpl_iMul::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iMUL, from); } void xImpl_iMul::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iMUL, from); }
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from) const { xOpWrite0F(0xaf, to, from); } void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from) const { xOpWrite0F(0xaf, to, from); }
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &src) const { xOpWrite0F(0xaf, to, src); } void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& src) const { xOpWrite0F(0xaf, to, src); }
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from) const { xOpWrite0F(0x66, 0xaf, to, from); } void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from) const { xOpWrite0F(0x66, 0xaf, to, from); }
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &src) const { xOpWrite0F(0x66, 0xaf, to, src); } void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& src) const { xOpWrite0F(0x66, 0xaf, to, src); }
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const { _imul_ImmStyle(to, from, imm); } void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const { _imul_ImmStyle(to, from, imm); } void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const { _imul_ImmStyle(to, from, imm); } void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const { _imul_ImmStyle(to, from, imm); } void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
const xImpl_Group3 xNOT = {G3Type_NOT}; const xImpl_Group3 xNOT = {G3Type_NOT};
const xImpl_Group3 xNEG = {G3Type_NEG}; const xImpl_Group3 xNEG = {G3Type_NEG};
const xImpl_Group3 xUMUL = {G3Type_MUL}; const xImpl_Group3 xUMUL = {G3Type_MUL};
const xImpl_Group3 xUDIV = {G3Type_DIV}; const xImpl_Group3 xUDIV = {G3Type_DIV};
const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}}; const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}}; const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}};
// ===================================================================================================== // =====================================================================================================
// Group 8 Instructions // Group 8 Instructions
// ===================================================================================================== // =====================================================================================================
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const
{ {
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize()); pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset); xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset);
} }
void xImpl_Group8::operator()(const xIndirect64 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); } void xImpl_Group8::operator()(const xIndirect64& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
void xImpl_Group8::operator()(const xIndirect32 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); } void xImpl_Group8::operator()(const xIndirect32& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
void xImpl_Group8::operator()(const xIndirect16 &bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); } void xImpl_Group8::operator()(const xIndirect16& bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); }
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const
{ {
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset); xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
} }
void xImpl_Group8::operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const void xImpl_Group8::operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const
{ {
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase); xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
} }
const xImpl_Group8 xBT = {G8Type_BT}; const xImpl_Group8 xBT = {G8Type_BT};
const xImpl_Group8 xBTR = {G8Type_BTR}; const xImpl_Group8 xBTR = {G8Type_BTR};
const xImpl_Group8 xBTS = {G8Type_BTS}; const xImpl_Group8 xBTS = {G8Type_BTS};
const xImpl_Group8 xBTC = {G8Type_BTC}; const xImpl_Group8 xBTC = {G8Type_BTC};

View File

@ -20,19 +20,19 @@
namespace x86Emitter namespace x86Emitter
{ {
struct xImplBMI_RVM struct xImplBMI_RVM
{ {
u8 Prefix; u8 Prefix;
u8 MbPrefix; u8 MbPrefix;
u8 Opcode; u8 Opcode;
// RVM // RVM
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers // MULX Unsigned multiply without affecting flags, and arbitrary destination registers
// PDEP Parallel bits deposit // PDEP Parallel bits deposit
// PEXT Parallel bits extract // PEXT Parallel bits extract
// ANDN Logical and not ~x & y // ANDN Logical and not ~x & y
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const; void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const;
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const; void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const;
#if 0 #if 0
// RMV // RMV
@ -57,5 +57,5 @@ struct xImplBMI_RVM
void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const; void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const;
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const; void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
#endif #endif
}; };
} } // namespace x86Emitter

View File

@ -18,27 +18,27 @@
namespace x86Emitter namespace x86Emitter
{ {
// Implementations here cover SHLD and SHRD. // Implementations here cover SHLD and SHRD.
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_DowrdShift // xImpl_DowrdShift
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// I use explicit method declarations here instead of templates, in order to provide // I use explicit method declarations here instead of templates, in order to provide
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD). // *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
// //
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization // Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
// because shifts by 0 do *not* affect flags status (intel docs cited). // because shifts by 0 do *not* affect flags status (intel docs cited).
// //
struct xImpl_DwordShift struct xImpl_DwordShift
{ {
u16 OpcodeBase; u16 OpcodeBase;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, const xRegisterCL &clreg) const; void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, u8 shiftcnt) const; void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, u8 shiftcnt) const;
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, const xRegisterCL &clreg) const; void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, u8 shiftcnt) const; void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, u8 shiftcnt) const;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -18,32 +18,33 @@
namespace x86Emitter namespace x86Emitter
{ {
enum G1Type { enum G1Type
G1Type_ADD = 0, {
G1Type_OR, G1Type_ADD = 0,
G1Type_ADC, G1Type_OR,
G1Type_SBB, G1Type_ADC,
G1Type_AND, G1Type_SBB,
G1Type_SUB, G1Type_AND,
G1Type_XOR, G1Type_SUB,
G1Type_CMP G1Type_XOR,
}; G1Type_CMP
};
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from); extern void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_Group1 // xImpl_Group1
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImpl_Group1 struct xImpl_Group1
{ {
G1Type InstType; G1Type InstType;
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const; void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const; void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
void operator()(const xRegisterInt &to, int imm) const; void operator()(const xRegisterInt& to, int imm) const;
void operator()(const xIndirect64orLess &to, int imm) const; void operator()(const xIndirect64orLess& to, int imm) const;
#if 0 #if 0
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -79,64 +80,64 @@ struct xImpl_Group1
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) ); _DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
} }
#endif #endif
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT). // This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
// Note: ANDN [AndNot] is handled below separately. // Note: ANDN [AndNot] is handled below separately.
// //
struct xImpl_G1Logic struct xImpl_G1Logic
{ {
G1Type InstType; G1Type InstType;
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const; void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const; void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
void operator()(const xRegisterInt &to, int imm) const; void operator()(const xRegisterInt& to, int imm) const;
void operator()(const xIndirect64orLess &to, int imm) const; void operator()(const xIndirect64orLess& to, int imm) const;
xImplSimd_DestRegSSE PS; // packed single precision xImplSimd_DestRegSSE PS; // packed single precision
xImplSimd_DestRegSSE PD; // packed double precision xImplSimd_DestRegSSE PD; // packed double precision
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB). // This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
// //
struct xImpl_G1Arith struct xImpl_G1Arith
{ {
G1Type InstType; G1Type InstType;
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const; void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const; void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
void operator()(const xRegisterInt &to, int imm) const; void operator()(const xRegisterInt& to, int imm) const;
void operator()(const xIndirect64orLess &to, int imm) const; void operator()(const xIndirect64orLess& to, int imm) const;
xImplSimd_DestRegSSE PS; // packed single precision xImplSimd_DestRegSSE PS; // packed single precision
xImplSimd_DestRegSSE PD; // packed double precision xImplSimd_DestRegSSE PD; // packed double precision
xImplSimd_DestRegSSE SS; // scalar single precision xImplSimd_DestRegSSE SS; // scalar single precision
xImplSimd_DestRegSSE SD; // scalar double precision xImplSimd_DestRegSSE SD; // scalar double precision
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
struct xImpl_G1Compare struct xImpl_G1Compare
{ {
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const; void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const; void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
void operator()(const xRegisterInt &to, int imm) const; void operator()(const xRegisterInt& to, int imm) const;
void operator()(const xIndirect64orLess &to, int imm) const; void operator()(const xIndirect64orLess& to, int imm) const;
xImplSimd_DestSSE_CmpImm PS; xImplSimd_DestSSE_CmpImm PS;
xImplSimd_DestSSE_CmpImm PD; xImplSimd_DestSSE_CmpImm PD;
xImplSimd_DestSSE_CmpImm SS; xImplSimd_DestSSE_CmpImm SS;
xImplSimd_DestSSE_CmpImm SD; xImplSimd_DestSSE_CmpImm SD;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -18,32 +18,33 @@
namespace x86Emitter namespace x86Emitter
{ {
enum G2Type { enum G2Type
G2Type_ROL = 0, {
G2Type_ROR, G2Type_ROL = 0,
G2Type_RCL, G2Type_ROR,
G2Type_RCR, G2Type_RCL,
G2Type_SHL, G2Type_RCR,
G2Type_SHR, G2Type_SHL,
G2Type_Unused, G2Type_SHR,
G2Type_SAR G2Type_Unused,
}; G2Type_SAR
};
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_Group2 // xImpl_Group2
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Group 2 (shift) instructions have no Sib/ModRM forms. // Group 2 (shift) instructions have no Sib/ModRM forms.
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero. // Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
// This is a safe optimization since any zero-value shift does not affect any flags. // This is a safe optimization since any zero-value shift does not affect any flags.
// //
struct xImpl_Group2 struct xImpl_Group2
{ {
G2Type InstType; G2Type InstType;
void operator()(const xRegisterInt &to, const xRegisterCL &from) const; void operator()(const xRegisterInt& to, const xRegisterCL& from) const;
void operator()(const xIndirect64orLess &to, const xRegisterCL &from) const; void operator()(const xIndirect64orLess& to, const xRegisterCL& from) const;
void operator()(const xRegisterInt &to, u8 imm) const; void operator()(const xRegisterInt& to, u8 imm) const;
void operator()(const xIndirect64orLess &to, u8 imm) const; void operator()(const xIndirect64orLess& to, u8 imm) const;
#if 0 #if 0
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -57,6 +58,6 @@ struct xImpl_Group2
_DoI_helpermess( *this, to, from ); _DoI_helpermess( *this, to, from );
} }
#endif #endif
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -18,24 +18,25 @@
namespace x86Emitter namespace x86Emitter
{ {
enum G3Type { enum G3Type
G3Type_NOT = 2, {
G3Type_NEG = 3, G3Type_NOT = 2,
G3Type_MUL = 4, G3Type_NEG = 3,
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp G3Type_MUL = 4,
G3Type_DIV = 6, G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
G3Type_iDIV = 7 G3Type_DIV = 6,
}; G3Type_iDIV = 7
};
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_Group3 // xImpl_Group3
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImpl_Group3 struct xImpl_Group3
{ {
G3Type InstType; G3Type InstType;
void operator()(const xRegisterInt &from) const; void operator()(const xRegisterInt& from) const;
void operator()(const xIndirect64orLess &from) const; void operator()(const xIndirect64orLess& from) const;
#if 0 #if 0
template< typename T > template< typename T >
@ -44,65 +45,65 @@ struct xImpl_Group3
_DoI_helpermess( *this, from ); _DoI_helpermess( *this, from );
} }
#endif #endif
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_MulDivBase // xImpl_MulDivBase
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV. // This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
// //
struct xImpl_MulDivBase struct xImpl_MulDivBase
{ {
G3Type InstType; G3Type InstType;
u16 OpcodeSSE; u16 OpcodeSSE;
void operator()(const xRegisterInt &from) const; void operator()(const xRegisterInt& from) const;
void operator()(const xIndirect64orLess &from) const; void operator()(const xIndirect64orLess& from) const;
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD; const xImplSimd_DestRegSSE PD;
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_iDiv // xImpl_iDiv
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImpl_iDiv struct xImpl_iDiv
{ {
void operator()(const xRegisterInt &from) const; void operator()(const xRegisterInt& from) const;
void operator()(const xIndirect64orLess &from) const; void operator()(const xIndirect64orLess& from) const;
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD; const xImplSimd_DestRegSSE PD;
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_iMul // xImpl_iMul
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// //
struct xImpl_iMul struct xImpl_iMul
{ {
void operator()(const xRegisterInt &from) const; void operator()(const xRegisterInt& from) const;
void operator()(const xIndirect64orLess &from) const; void operator()(const xIndirect64orLess& from) const;
// The following iMul-specific forms are valid for 16 and 32 bit register operands only! // The following iMul-specific forms are valid for 16 and 32 bit register operands only!
void operator()(const xRegister32 &to, const xRegister32 &from) const; void operator()(const xRegister32& to, const xRegister32& from) const;
void operator()(const xRegister32 &to, const xIndirectVoid &src) const; void operator()(const xRegister32& to, const xIndirectVoid& src) const;
void operator()(const xRegister16 &to, const xRegister16 &from) const; void operator()(const xRegister16& to, const xRegister16& from) const;
void operator()(const xRegister16 &to, const xIndirectVoid &src) const; void operator()(const xRegister16& to, const xIndirectVoid& src) const;
void operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const; void operator()(const xRegister32& to, const xRegister32& from, s32 imm) const;
void operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const; void operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const;
void operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const; void operator()(const xRegister16& to, const xRegister16& from, s16 imm) const;
void operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const; void operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const;
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD; const xImplSimd_DestRegSSE PD;
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
}; };
} } // namespace x86Emitter

View File

@ -21,15 +21,15 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_IncDec // xImpl_IncDec
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImpl_IncDec struct xImpl_IncDec
{ {
bool isDec; bool isDec;
void operator()(const xRegisterInt &to) const; void operator()(const xRegisterInt& to) const;
void operator()(const xIndirect64orLess &to) const; void operator()(const xIndirect64orLess& to) const;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -20,74 +20,75 @@
namespace x86Emitter namespace x86Emitter
{ {
extern void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward); extern void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
struct xImpl_JmpCall struct xImpl_JmpCall
{ {
bool isJmp; bool isJmp;
void operator()(const xAddressReg &absreg) const; void operator()(const xAddressReg& absreg) const;
void operator()(const xIndirectNative &src) const; void operator()(const xIndirectNative& src) const;
// Special form for calling functions. This form automatically resolves the // Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated. // correct displacement based on the size of the instruction being generated.
void operator()(void *func) const void operator()(void* func) const
{ {
if (isJmp) if (isJmp)
xJccKnownTarget(Jcc_Unconditional, (void *)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
else { else
// calls are relative to the instruction after this one, and length is {
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic). // calls are relative to the instruction after this one, and length is
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5); sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!"); pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
xWrite8(0xe8); xWrite8(0xe8);
xWrite32(dest); xWrite32(dest);
} }
} }
}; };
// yes it is awful. Due to template code is in a header with a nice circular dep. // yes it is awful. Due to template code is in a header with a nice circular dep.
extern const xImpl_Mov xMOV; extern const xImpl_Mov xMOV;
extern const xImpl_JmpCall xCALL; extern const xImpl_JmpCall xCALL;
struct xImpl_FastCall struct xImpl_FastCall
{ {
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop // FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
// some registers. But I think it is enough to handle the first call. // some registers. But I think it is enough to handle the first call.
void operator()(void *f, const xRegister32 &a1 = xEmptyReg, const xRegister32 &a2 = xEmptyReg) const; void operator()(void* f, const xRegister32& a1 = xEmptyReg, const xRegister32& a2 = xEmptyReg) const;
void operator()(void *f, u32 a1, const xRegister32 &a2) const; void operator()(void* f, u32 a1, const xRegister32& a2) const;
void operator()(void *f, const xIndirect32 &a1) const; void operator()(void* f, const xIndirect32& a1) const;
void operator()(void *f, u32 a1, u32 a2) const; void operator()(void* f, u32 a1, u32 a2) const;
void operator()(void *f, void *a1) const; void operator()(void* f, void* a1) const;
#ifdef __M_X86_64 #ifdef __M_X86_64
void operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2 = xEmptyReg) const; void operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
void operator()(void *f, u32 a1, const xRegisterLong &a2) const; void operator()(void* f, u32 a1, const xRegisterLong& a2) const;
#endif #endif
template <typename T> template <typename T>
__fi void operator()(T *func, u32 a1, const xRegisterLong &a2 = xEmptyReg) const __fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
{ {
(*this)((void *)func, a1, a2); (*this)((void*)func, a1, a2);
} }
template <typename T> template <typename T>
__fi void operator()(T *func, const xIndirect32 &a1) const __fi void operator()(T* func, const xIndirect32& a1) const
{ {
(*this)((void*)func, a1); (*this)((void*)func, a1);
} }
template <typename T> template <typename T>
__fi void operator()(T *func, u32 a1, u32 a2) const __fi void operator()(T* func, u32 a1, u32 a2) const
{ {
(*this)((void*)func, a1, a2); (*this)((void*)func, a1, a2);
} }
void operator()(const xIndirectNative &f, const xRegisterLong &a1 = xEmptyReg, const xRegisterLong &a2 = xEmptyReg) const; void operator()(const xIndirectNative& f, const xRegisterLong& a1 = xEmptyReg, const xRegisterLong& a2 = xEmptyReg) const;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -21,20 +21,20 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// MovImplAll // MovImplAll
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// MOV instruction Implementation, plus many SIMD sub-mov variants. // MOV instruction Implementation, plus many SIMD sub-mov variants.
// //
struct xImpl_Mov struct xImpl_Mov
{ {
xImpl_Mov() {} // Satisfy GCC's whims. xImpl_Mov() {} // Satisfy GCC's whims.
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirectVoid &dest, const xRegisterInt &from) const; void operator()(const xIndirectVoid& dest, const xRegisterInt& from) const;
void operator()(const xRegisterInt &to, const xIndirectVoid &src) const; void operator()(const xRegisterInt& to, const xIndirectVoid& src) const;
void operator()(const xIndirect64orLess &dest, sptr imm) const; void operator()(const xIndirect64orLess& dest, sptr imm) const;
void operator()(const xRegisterInt &to, sptr imm, bool preserve_flags = false) const; void operator()(const xRegisterInt& to, sptr imm, bool preserve_flags = false) const;
#if 0 #if 0
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
@ -68,73 +68,73 @@ struct xImpl_Mov
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) ); _DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
}*/ }*/
#endif #endif
}; };
#ifdef __M_X86_64 #ifdef __M_X86_64
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_MovImm64 // xImpl_MovImm64
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Mov with 64-bit immediates (only available on 64-bit platforms) // Mov with 64-bit immediates (only available on 64-bit platforms)
// //
struct xImpl_MovImm64 struct xImpl_MovImm64
{ {
xImpl_MovImm64() {} // Satisfy GCC's whims. xImpl_MovImm64() {} // Satisfy GCC's whims.
void operator()(const xRegister64 &to, s64 imm, bool preserve_flags = false) const; void operator()(const xRegister64& to, s64 imm, bool preserve_flags = false) const;
}; };
#endif #endif
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_CMov // xImpl_CMov
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and .. // CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
// SETcc !! [more glory, less lack!] // SETcc !! [more glory, less lack!]
// //
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you // CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
// realize that it cannot load immediate values into registers. -_- // realize that it cannot load immediate values into registers. -_-
// //
// I use explicit method declarations here instead of templates, in order to provide // I use explicit method declarations here instead of templates, in order to provide
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV). // *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
// //
struct xImpl_CMov struct xImpl_CMov
{ {
JccComparisonType ccType; JccComparisonType ccType;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const; void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const; void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ); //void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const; //void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
}; };
struct xImpl_Set struct xImpl_Set
{ {
JccComparisonType ccType; JccComparisonType ccType;
void operator()(const xRegister8 &to) const; void operator()(const xRegister8& to) const;
void operator()(const xIndirect8 &dest) const; void operator()(const xIndirect8& dest) const;
//void operator()( const xDirectOrIndirect8& dest ) const; //void operator()( const xDirectOrIndirect8& dest ) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_MovExtend // xImpl_MovExtend
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Mov with sign/zero extension implementations (movsx / movzx) // Mov with sign/zero extension implementations (movsx / movzx)
// //
struct xImpl_MovExtend struct xImpl_MovExtend
{ {
bool SignExtend; bool SignExtend;
void operator()(const xRegister16or32or64 &to, const xRegister8 &from) const; void operator()(const xRegister16or32or64& to, const xRegister8& from) const;
void operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const; void operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const;
void operator()(const xRegister32or64 &to, const xRegister16 &from) const; void operator()(const xRegister32or64& to, const xRegister16& from) const;
void operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const; void operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const;
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const; //void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const; //void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const; //void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -18,299 +18,299 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// _SimdShiftHelper // _SimdShiftHelper
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct _SimdShiftHelper struct _SimdShiftHelper
{ {
u8 Prefix; u8 Prefix;
u16 Opcode; u16 Opcode;
u16 OpcodeImm; u16 OpcodeImm;
u8 Modcode; u8 Modcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
void operator()(const xRegisterSSE &to, u8 imm8) const; void operator()(const xRegisterSSE& to, u8 imm8) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ // xImplSimd_Shift / xImplSimd_ShiftWithoutQ
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Used for PSRA, which lacks the Q form. // Used for PSRA, which lacks the Q form.
// //
struct xImplSimd_ShiftWithoutQ struct xImplSimd_ShiftWithoutQ
{ {
const _SimdShiftHelper W; const _SimdShiftHelper W;
const _SimdShiftHelper D; const _SimdShiftHelper D;
}; };
// Implements PSRL and PSLL // Implements PSRL and PSLL
// //
struct xImplSimd_Shift struct xImplSimd_Shift
{ {
const _SimdShiftHelper W; const _SimdShiftHelper W;
const _SimdShiftHelper D; const _SimdShiftHelper D;
const _SimdShiftHelper Q; const _SimdShiftHelper Q;
void DQ(const xRegisterSSE &to, u8 imm8) const; void DQ(const xRegisterSSE& to, u8 imm8) const;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_AddSub struct xImplSimd_AddSub
{ {
const xImplSimd_DestRegEither B; const xImplSimd_DestRegEither B;
const xImplSimd_DestRegEither W; const xImplSimd_DestRegEither W;
const xImplSimd_DestRegEither D; const xImplSimd_DestRegEither D;
const xImplSimd_DestRegEither Q; const xImplSimd_DestRegEither Q;
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results. // Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SB; const xImplSimd_DestRegEither SB;
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results. // Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SW; const xImplSimd_DestRegEither SW;
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results. // Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USB; const xImplSimd_DestRegEither USB;
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results. // Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USW; const xImplSimd_DestRegEither USW;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_PMul struct xImplSimd_PMul
{ {
const xImplSimd_DestRegEither LW; const xImplSimd_DestRegEither LW;
const xImplSimd_DestRegEither HW; const xImplSimd_DestRegEither HW;
const xImplSimd_DestRegEither HUW; const xImplSimd_DestRegEither HUW;
const xImplSimd_DestRegEither UDQ; const xImplSimd_DestRegEither UDQ;
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the // [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit // corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant // integers. Each intermediate 32-bit integer is truncated to the 18 most significant
// bits. Rounding is always performed by adding 1 to the least significant bit of the // bits. Rounding is always performed by adding 1 to the least significant bit of the
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits // 18-bit intermediate result. The final result is obtained by selecting the 16 bits
// immediately to the right of the most significant bit of each 18-bit intermediate // immediately to the right of the most significant bit of each 18-bit intermediate
// result and packed to the destination operand. // result and packed to the destination operand.
// //
// Both operands can be MMX or XMM registers. Source can be register or memory. // Both operands can be MMX or XMM registers. Source can be register or memory.
// //
const xImplSimd_DestRegEither HRSW; const xImplSimd_DestRegEither HRSW;
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store // [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
// the low 32 bits of each product in xmm1. // the low 32 bits of each product in xmm1.
const xImplSimd_DestRegSSE LD; const xImplSimd_DestRegSSE LD;
// [SSE-4.1] Multiply the packed signed dword integers in dest with src. // [SSE-4.1] Multiply the packed signed dword integers in dest with src.
const xImplSimd_DestRegSSE DQ; const xImplSimd_DestRegSSE DQ;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions) // For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
// //
struct xImplSimd_rSqrt struct xImplSimd_rSqrt
{ {
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// SQRT has PS/SS/SD forms, but not the PD form. // SQRT has PS/SS/SD forms, but not the PD form.
// //
struct xImplSimd_Sqrt struct xImplSimd_Sqrt
{ {
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_AndNot struct xImplSimd_AndNot
{ {
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD; const xImplSimd_DestRegSSE PD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Packed absolute value. [sSSE3 only] // Packed absolute value. [sSSE3 only]
// //
struct xImplSimd_PAbsolute struct xImplSimd_PAbsolute
{ {
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result // [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
// in dest, as UNSIGNED. // in dest, as UNSIGNED.
const xImplSimd_DestRegEither B; const xImplSimd_DestRegEither B;
// [sSSE-3] Computes the absolute value of word in the src, and stores the result // [sSSE-3] Computes the absolute value of word in the src, and stores the result
// in dest, as UNSIGNED. // in dest, as UNSIGNED.
const xImplSimd_DestRegEither W; const xImplSimd_DestRegEither W;
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the // [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
// result in dest, as UNSIGNED. // result in dest, as UNSIGNED.
const xImplSimd_DestRegEither D; const xImplSimd_DestRegEither D;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the // Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
// corresponding sign in src. // corresponding sign in src.
// //
struct xImplSimd_PSign struct xImplSimd_PSign
{ {
// [sSSE-3] negates each byte element of dest if the signed integer value of the // [sSSE-3] negates each byte element of dest if the signed integer value of the
// corresponding data element in src is less than zero. If the signed integer value // corresponding data element in src is less than zero. If the signed integer value
// of a data element in src is positive, the corresponding data element in dest is // of a data element in src is positive, the corresponding data element in dest is
// unchanged. If a data element in src is zero, the corresponding data element in // unchanged. If a data element in src is zero, the corresponding data element in
// dest is set to zero. // dest is set to zero.
const xImplSimd_DestRegEither B; const xImplSimd_DestRegEither B;
// [sSSE-3] negates each word element of dest if the signed integer value of the // [sSSE-3] negates each word element of dest if the signed integer value of the
// corresponding data element in src is less than zero. If the signed integer value // corresponding data element in src is less than zero. If the signed integer value
// of a data element in src is positive, the corresponding data element in dest is // of a data element in src is positive, the corresponding data element in dest is
// unchanged. If a data element in src is zero, the corresponding data element in // unchanged. If a data element in src is zero, the corresponding data element in
// dest is set to zero. // dest is set to zero.
const xImplSimd_DestRegEither W; const xImplSimd_DestRegEither W;
// [sSSE-3] negates each doubleword element of dest if the signed integer value // [sSSE-3] negates each doubleword element of dest if the signed integer value
// of the corresponding data element in src is less than zero. If the signed integer // of the corresponding data element in src is less than zero. If the signed integer
// value of a data element in src is positive, the corresponding data element in dest // value of a data element in src is positive, the corresponding data element in dest
// is unchanged. If a data element in src is zero, the corresponding data element in // is unchanged. If a data element in src is zero, the corresponding data element in
// dest is set to zero. // dest is set to zero.
const xImplSimd_DestRegEither D; const xImplSimd_DestRegEither D;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Packed Multiply and Add!! // Packed Multiply and Add!!
// //
struct xImplSimd_PMultAdd struct xImplSimd_PMultAdd
{ {
// Multiplies the individual signed words of dest by the corresponding signed words // Multiplies the individual signed words of dest by the corresponding signed words
// of src, producing temporary signed, doubleword results. The adjacent doubleword // of src, producing temporary signed, doubleword results. The adjacent doubleword
// results are then summed and stored in the destination operand. // results are then summed and stored in the destination operand.
// //
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] ); // DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] ); // DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
// [.. repeat in the case of XMM src/dest operands ..] // [.. repeat in the case of XMM src/dest operands ..]
// //
const xImplSimd_DestRegEither WD; const xImplSimd_DestRegEither WD;
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding // [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent // signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
// pair of signed words is added and the saturated result is packed to dest. // pair of signed words is added and the saturated result is packed to dest.
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied // For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
// and the intermediate signed word result is added with the corresponding // and the intermediate signed word result is added with the corresponding
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands; // intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
// the sign-saturated result is stored in the lowest word of dest (bits 15-0). // the sign-saturated result is stored in the lowest word of dest (bits 15-0).
// The same operation is performed on the other pairs of adjacent bytes. // The same operation is performed on the other pairs of adjacent bytes.
// //
// In Coder Speak: // In Coder Speak:
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] ); // DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] ); // DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..] // [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
// //
const xImplSimd_DestRegEither UBSW; const xImplSimd_DestRegEither UBSW;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Packed Horizontal Add [SSE3 only] // Packed Horizontal Add [SSE3 only]
// //
struct xImplSimd_HorizAdd struct xImplSimd_HorizAdd
{ {
// [SSE-3] Horizontal Add of Packed Data. A three step process: // [SSE-3] Horizontal Add of Packed Data. A three step process:
// * Adds the single-precision floating-point values in the first and second dwords of // * Adds the single-precision floating-point values in the first and second dwords of
// dest and stores the result in the first dword of dest. // dest and stores the result in the first dword of dest.
// * Adds single-precision floating-point values in the third and fourth dword of dest // * Adds single-precision floating-point values in the third and fourth dword of dest
// stores the result in the second dword of dest. // stores the result in the second dword of dest.
// * Adds single-precision floating-point values in the first and second dword of *src* // * Adds single-precision floating-point values in the first and second dword of *src*
// and stores the result in the third dword of dest. // and stores the result in the third dword of dest.
const xImplSimd_DestRegSSE PS; const xImplSimd_DestRegSSE PS;
// [SSE-3] Horizontal Add of Packed Data. A two step process: // [SSE-3] Horizontal Add of Packed Data. A two step process:
// * Adds the double-precision floating-point values in the high and low quadwords of // * Adds the double-precision floating-point values in the high and low quadwords of
// dest and stores the result in the low quadword of dest. // dest and stores the result in the low quadword of dest.
// * Adds the double-precision floating-point values in the high and low quadwords of // * Adds the double-precision floating-point values in the high and low quadwords of
// *src* stores the result in the high quadword of dest. // *src* stores the result in the high quadword of dest.
const xImplSimd_DestRegSSE PD; const xImplSimd_DestRegSSE PD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// DotProduct calculation (SSE4.1 only!) // DotProduct calculation (SSE4.1 only!)
// //
struct xImplSimd_DotProduct struct xImplSimd_DotProduct
{ {
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point // [SSE-4.1] Conditionally multiplies the packed single precision floating-point
// values in dest with the packed single-precision floats in src depending on a // values in dest with the packed single-precision floats in src depending on a
// mask extracted from the high 4 bits of the immediate byte. If a condition mask // mask extracted from the high 4 bits of the immediate byte. If a condition mask
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value // bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
// of 0.0. The four resulting single-precision values are summed into an inter- // of 0.0. The four resulting single-precision values are summed into an inter-
// mediate result. // mediate result.
// //
// The intermediate result is conditionally broadcasted to the destination using a // The intermediate result is conditionally broadcasted to the destination using a
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast // broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
// mask bit is 1, the intermediate result is copied to the corresponding dword // mask bit is 1, the intermediate result is copied to the corresponding dword
// element in dest. If a broadcast mask bit is zero, the corresponding element in // element in dest. If a broadcast mask bit is zero, the corresponding element in
// the destination is set to zero. // the destination is set to zero.
// //
xImplSimd_DestRegImmSSE PS; xImplSimd_DestRegImmSSE PS;
// [SSE-4.1] // [SSE-4.1]
xImplSimd_DestRegImmSSE PD; xImplSimd_DestRegImmSSE PD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode. // Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
// (SSE4.1 only!) // (SSE4.1 only!)
struct xImplSimd_Round struct xImplSimd_Round
{ {
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest. // [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
// //
// Imm8 specifies control fields for the rounding operation: // Imm8 specifies control fields for the rounding operation:
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact) // Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8. // Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
// Bits 1:0 - Specifies a rounding mode for this instruction only. // Bits 1:0 - Specifies a rounding mode for this instruction only.
// //
// Rounding Mode Reference: // Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate. // 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
// //
const xImplSimd_DestRegImmSSE PS; const xImplSimd_DestRegImmSSE PS;
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest. // [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
// //
// Imm8 specifies control fields for the rounding operation: // Imm8 specifies control fields for the rounding operation:
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact) // Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8. // Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
// Bits 1:0 - Specifies a rounding mode for this instruction only. // Bits 1:0 - Specifies a rounding mode for this instruction only.
// //
// Rounding Mode Reference: // Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate. // 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
// //
const xImplSimd_DestRegImmSSE PD; const xImplSimd_DestRegImmSSE PD;
// [SSE-4.1] Rounds the single-precision src value and stores in dest. // [SSE-4.1] Rounds the single-precision src value and stores in dest.
// //
// Imm8 specifies control fields for the rounding operation: // Imm8 specifies control fields for the rounding operation:
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact) // Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8. // Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
// Bits 1:0 - Specifies a rounding mode for this instruction only. // Bits 1:0 - Specifies a rounding mode for this instruction only.
// //
// Rounding Mode Reference: // Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate. // 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
// //
const xImplSimd_DestRegImmSSE SS; const xImplSimd_DestRegImmSSE SS;
// [SSE-4.1] Rounds the double-precision src value and stores in dest. // [SSE-4.1] Rounds the double-precision src value and stores in dest.
// //
// Imm8 specifies control fields for the rounding operation: // Imm8 specifies control fields for the rounding operation:
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact) // Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8. // Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
// Bits 1:0 - Specifies a rounding mode for this instruction only. // Bits 1:0 - Specifies a rounding mode for this instruction only.
// //
// Rounding Mode Reference: // Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate. // 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
// //
const xImplSimd_DestRegImmSSE SD; const xImplSimd_DestRegImmSSE SD;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

View File

@ -18,106 +18,106 @@
namespace x86Emitter namespace x86Emitter
{ {
struct xImplSimd_MinMax struct xImplSimd_MinMax
{ {
const xImplSimd_DestRegSSE PS; // packed single precision const xImplSimd_DestRegSSE PS; // packed single precision
const xImplSimd_DestRegSSE PD; // packed double precision const xImplSimd_DestRegSSE PD; // packed double precision
const xImplSimd_DestRegSSE SS; // scalar single precision const xImplSimd_DestRegSSE SS; // scalar single precision
const xImplSimd_DestRegSSE SD; // scalar double precision const xImplSimd_DestRegSSE SD; // scalar double precision
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_Compare struct xImplSimd_Compare
{ {
SSE2_ComparisonType CType; SSE2_ComparisonType CType;
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const; void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const; void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const; void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const; void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
void SS(const xRegisterSSE &to, const xRegisterSSE &from) const; void SS(const xRegisterSSE& to, const xRegisterSSE& from) const;
void SS(const xRegisterSSE &to, const xIndirectVoid &from) const; void SS(const xRegisterSSE& to, const xIndirectVoid& from) const;
void SD(const xRegisterSSE &to, const xRegisterSSE &from) const; void SD(const xRegisterSSE& to, const xRegisterSSE& from) const;
void SD(const xRegisterSSE &to, const xIndirectVoid &from) const; void SD(const xRegisterSSE& to, const xIndirectVoid& from) const;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered) // Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
// //
struct xImplSimd_COMI struct xImplSimd_COMI
{ {
const xImplSimd_DestRegSSE SS; const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_PCompare struct xImplSimd_PCompare
{ {
public: public:
// Compare packed bytes for equality. // Compare packed bytes for equality.
// If a data element in dest is equal to the corresponding date element src, the // If a data element in dest is equal to the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither EQB; const xImplSimd_DestRegEither EQB;
// Compare packed words for equality. // Compare packed words for equality.
// If a data element in dest is equal to the corresponding date element src, the // If a data element in dest is equal to the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither EQW; const xImplSimd_DestRegEither EQW;
// Compare packed doublewords [32-bits] for equality. // Compare packed doublewords [32-bits] for equality.
// If a data element in dest is equal to the corresponding date element src, the // If a data element in dest is equal to the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither EQD; const xImplSimd_DestRegEither EQD;
// Compare packed signed bytes for greater than. // Compare packed signed bytes for greater than.
// If a data element in dest is greater than the corresponding date element src, the // If a data element in dest is greater than the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither GTB; const xImplSimd_DestRegEither GTB;
// Compare packed signed words for greater than. // Compare packed signed words for greater than.
// If a data element in dest is greater than the corresponding date element src, the // If a data element in dest is greater than the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither GTW; const xImplSimd_DestRegEither GTW;
// Compare packed signed doublewords [32-bits] for greater than. // Compare packed signed doublewords [32-bits] for greater than.
// If a data element in dest is greater than the corresponding date element src, the // If a data element in dest is greater than the corresponding date element src, the
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s. // corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
const xImplSimd_DestRegEither GTD; const xImplSimd_DestRegEither GTD;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
struct xImplSimd_PMinMax struct xImplSimd_PMinMax
{ {
// Compare packed unsigned byte integers in dest to src and store packed min/max // Compare packed unsigned byte integers in dest to src and store packed min/max
// values in dest. // values in dest.
const xImplSimd_DestRegEither UB; const xImplSimd_DestRegEither UB;
// Compare packed signed word integers in dest to src and store packed min/max // Compare packed signed word integers in dest to src and store packed min/max
// values in dest. // values in dest.
const xImplSimd_DestRegEither SW; const xImplSimd_DestRegEither SW;
// [SSE-4.1] Compare packed signed byte integers in dest to src and store // [SSE-4.1] Compare packed signed byte integers in dest to src and store
// packed min/max values in dest. (SSE operands only) // packed min/max values in dest. (SSE operands only)
const xImplSimd_DestRegSSE SB; const xImplSimd_DestRegSSE SB;
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store // [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
// packed min/max values in dest. (SSE operands only) // packed min/max values in dest. (SSE operands only)
const xImplSimd_DestRegSSE SD; const xImplSimd_DestRegSSE SD;
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store // [SSE-4.1] Compare packed unsigned word integers in dest to src and store
// packed min/max values in dest. (SSE operands only) // packed min/max values in dest. (SSE operands only)
const xImplSimd_DestRegSSE UW; const xImplSimd_DestRegSSE UW;
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store // [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
// packed min/max values in dest. (SSE operands only) // packed min/max values in dest. (SSE operands only)
const xImplSimd_DestRegSSE UD; const xImplSimd_DestRegSSE UD;
}; };
} // end namespace x86Emitter } // end namespace x86Emitter

View File

@ -18,56 +18,56 @@
namespace x86Emitter namespace x86Emitter
{ {
// ===================================================================================================== // =====================================================================================================
// xImpl_SIMD Types (template free!) // xImpl_SIMD Types (template free!)
// ===================================================================================================== // =====================================================================================================
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only, // For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
// like ANDPS/ANDPD // like ANDPS/ANDPD
// //
struct xImplSimd_DestRegSSE struct xImplSimd_DestRegSSE
{ {
u8 Prefix; u8 Prefix;
u16 Opcode; u16 Opcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only // For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
// (PSHUFD / PSHUFHW / etc). // (PSHUFD / PSHUFHW / etc).
// //
struct xImplSimd_DestRegImmSSE struct xImplSimd_DestRegImmSSE
{ {
u8 Prefix; u8 Prefix;
u16 Opcode; u16 Opcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, u8 imm) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from, u8 imm) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm) const;
}; };
struct xImplSimd_DestSSE_CmpImm struct xImplSimd_DestSSE_CmpImm
{ {
u8 Prefix; u8 Prefix;
u16 Opcode; u16 Opcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, SSE2_ComparisonType imm) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, SSE2_ComparisonType imm) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from, SSE2_ComparisonType imm) const;
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// For implementing SSE operations that have reg,reg/rm forms only, // For implementing SSE operations that have reg,reg/rm forms only,
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops). // but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
// //
struct xImplSimd_DestRegEither struct xImplSimd_DestRegEither
{ {
u8 Prefix; u8 Prefix;
u16 Opcode; u16 Opcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
}; };
} // end namespace x86Emitter } // end namespace x86Emitter

View File

@ -18,156 +18,156 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_MovHL // xImplSimd_MovHL
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Moves to/from high/low portions of an xmm register. // Moves to/from high/low portions of an xmm register.
// These instructions cannot be used in reg/reg form. // These instructions cannot be used in reg/reg form.
// //
struct xImplSimd_MovHL struct xImplSimd_MovHL
{ {
u16 Opcode; u16 Opcode;
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const; void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
void PS(const xIndirectVoid &to, const xRegisterSSE &from) const; void PS(const xIndirectVoid& to, const xRegisterSSE& from) const;
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const; void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
void PD(const xIndirectVoid &to, const xRegisterSSE &from) const; void PD(const xIndirectVoid& to, const xRegisterSSE& from) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_MovHL_RtoR // xImplSimd_MovHL_RtoR
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but // RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
// do something kinda different! Fun! // do something kinda different! Fun!
// //
struct xImplSimd_MovHL_RtoR struct xImplSimd_MovHL_RtoR
{ {
u16 Opcode; u16 Opcode;
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const; void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const; void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_MoveSSE // xImplSimd_MoveSSE
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD // Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
// //
// All implementations of Unaligned Movs will, when possible, use aligned movs instead. // All implementations of Unaligned Movs will, when possible, use aligned movs instead.
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement // This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
// which can be checked for alignment at runtime. // which can be checked for alignment at runtime.
// //
struct xImplSimd_MoveSSE struct xImplSimd_MoveSSE
{ {
u8 Prefix; u8 Prefix;
bool isAligned; bool isAligned;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const; void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_MoveDQ // xImplSimd_MoveDQ
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Implementations for MOVDQA / MOVDQU // Implementations for MOVDQA / MOVDQU
// //
// All implementations of Unaligned Movs will, when possible, use aligned movs instead. // All implementations of Unaligned Movs will, when possible, use aligned movs instead.
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement // This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
// which can be checked for alignment at runtime. // which can be checked for alignment at runtime.
struct xImplSimd_MoveDQ struct xImplSimd_MoveDQ
{ {
u8 Prefix; u8 Prefix;
bool isAligned; bool isAligned;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const; void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const; void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_Blend // xImplSimd_Blend
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Blend - Conditional copying of values in src into dest. // Blend - Conditional copying of values in src into dest.
// //
struct xImplSimd_Blend struct xImplSimd_Blend
{ {
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the // [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a // mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
// dword element in a 128-bit operand. // dword element in a 128-bit operand.
// //
// If a mask bit is 1, then the corresponding dword in the source operand is copied // If a mask bit is 1, then the corresponding dword in the source operand is copied
// to dest, else the dword element in dest is left unchanged. // to dest, else the dword element in dest is left unchanged.
// //
xImplSimd_DestRegImmSSE PS; xImplSimd_DestRegImmSSE PS;
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the // [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a // mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
// quadword element in a 128-bit operand. // quadword element in a 128-bit operand.
// //
// If a mask bit is 1, then the corresponding dword in the source operand is copied // If a mask bit is 1, then the corresponding dword in the source operand is copied
// to dest, else the dword element in dest is left unchanged. // to dest, else the dword element in dest is left unchanged.
// //
xImplSimd_DestRegImmSSE PD; xImplSimd_DestRegImmSSE PD;
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the // [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds // mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
// to a dword element in the 128-bit operand. // to a dword element in the 128-bit operand.
// //
// If a mask bit is 1, then the corresponding dword in the source operand is copied // If a mask bit is 1, then the corresponding dword in the source operand is copied
// to dest, else the dword element in dest is left unchanged. // to dest, else the dword element in dest is left unchanged.
// //
xImplSimd_DestRegSSE VPS; xImplSimd_DestRegSSE VPS;
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the // [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds // mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
// to a quadword element in the 128-bit operand. // to a quadword element in the 128-bit operand.
// //
// If a mask bit is 1, then the corresponding dword in the source operand is copied // If a mask bit is 1, then the corresponding dword in the source operand is copied
// to dest, else the dword element in dest is left unchanged. // to dest, else the dword element in dest is left unchanged.
// //
xImplSimd_DestRegSSE VPD; xImplSimd_DestRegSSE VPD;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_PMove // xImplSimd_PMove
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Packed Move with Sign or Zero extension. // Packed Move with Sign or Zero extension.
// //
struct xImplSimd_PMove struct xImplSimd_PMove
{ {
u16 OpcodeBase; u16 OpcodeBase;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers // [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
// and store them in dest. // and store them in dest.
void BW(const xRegisterSSE &to, const xRegisterSSE &from) const; void BW(const xRegisterSSE& to, const xRegisterSSE& from) const;
void BW(const xRegisterSSE &to, const xIndirect64 &from) const; void BW(const xRegisterSSE& to, const xIndirect64& from) const;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers // [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
// and store them in dest. // and store them in dest.
void BD(const xRegisterSSE &to, const xRegisterSSE &from) const; void BD(const xRegisterSSE& to, const xRegisterSSE& from) const;
void BD(const xRegisterSSE &to, const xIndirect32 &from) const; void BD(const xRegisterSSE& to, const xIndirect32& from) const;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers // [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
// and store them in dest. // and store them in dest.
void BQ(const xRegisterSSE &to, const xRegisterSSE &from) const; void BQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
void BQ(const xRegisterSSE &to, const xIndirect16 &from) const; void BQ(const xRegisterSSE& to, const xIndirect16& from) const;
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers // [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
// and store them in dest. // and store them in dest.
void WD(const xRegisterSSE &to, const xRegisterSSE &from) const; void WD(const xRegisterSSE& to, const xRegisterSSE& from) const;
void WD(const xRegisterSSE &to, const xIndirect64 &from) const; void WD(const xRegisterSSE& to, const xIndirect64& from) const;
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers // [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
// and store them in dest. // and store them in dest.
void WQ(const xRegisterSSE &to, const xRegisterSSE &from) const; void WQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
void WQ(const xRegisterSSE &to, const xIndirect32 &from) const; void WQ(const xRegisterSSE& to, const xIndirect32& from) const;
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers // [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
// and store them in dest. // and store them in dest.
void DQ(const xRegisterSSE &to, const xRegisterSSE &from) const; void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
void DQ(const xRegisterSSE &to, const xIndirect64 &from) const; void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
}; };
} } // namespace x86Emitter

View File

@ -18,50 +18,50 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_Shuffle // xImplSimd_Shuffle
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImplSimd_Shuffle struct xImplSimd_Shuffle
{ {
inline void _selector_assertion_check(u8 selector) const; inline void _selector_assertion_check(u8 selector) const;
void PS(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const; void PS(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
void PS(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const; void PS(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
void PD(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const; void PD(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
void PD(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const; void PD(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImplSimd_PShuffle // xImplSimd_PShuffle
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImplSimd_PShuffle struct xImplSimd_PShuffle
{ {
// Copies doublewords from src and inserts them into dest at dword locations selected // Copies doublewords from src and inserts them into dest at dword locations selected
// with the order operand (8 bit immediate). // with the order operand (8 bit immediate).
const xImplSimd_DestRegImmSSE D; const xImplSimd_DestRegImmSSE D;
// Copies words from the low quadword of src and inserts them into the low quadword // Copies words from the low quadword of src and inserts them into the low quadword
// of dest at word locations selected with the order operand (8 bit immediate). // of dest at word locations selected with the order operand (8 bit immediate).
// The high quadword of src is copied to the high quadword of dest. // The high quadword of src is copied to the high quadword of dest.
const xImplSimd_DestRegImmSSE LW; const xImplSimd_DestRegImmSSE LW;
// Copies words from the high quadword of src and inserts them into the high quadword // Copies words from the high quadword of src and inserts them into the high quadword
// of dest at word locations selected with the order operand (8 bit immediate). // of dest at word locations selected with the order operand (8 bit immediate).
// The low quadword of src is copied to the low quadword of dest. // The low quadword of src is copied to the low quadword of dest.
const xImplSimd_DestRegImmSSE HW; const xImplSimd_DestRegImmSSE HW;
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle // [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
// control mask in src. If the most significant bit (bit[7]) of each byte of the // control mask in src. If the most significant bit (bit[7]) of each byte of the
// shuffle control mask is set, then constant zero is written in the result byte. // shuffle control mask is set, then constant zero is written in the result byte.
// Each byte in the shuffle control mask forms an index to permute the corresponding // Each byte in the shuffle control mask forms an index to permute the corresponding
// byte in dest. The value of each index is the least significant 4 bits (128-bit // byte in dest. The value of each index is the least significant 4 bits (128-bit
// operation) or 3 bits (64-bit operation) of the shuffle control byte. // operation) or 3 bits (64-bit operation) of the shuffle control byte.
// //
const xImplSimd_DestRegEither B; const xImplSimd_DestRegEither B;
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense // below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air // but it doesn't (makes it worse). Will try again in MSVC 2010. --air
#if 0 #if 0
// Copies words from src and inserts them into dest at word locations selected with // Copies words from src and inserts them into dest at word locations selected with
@ -94,148 +94,148 @@ struct xImplSimd_PShuffle
void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); } void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); } void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
#endif #endif
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SimdImpl_PUnpack // SimdImpl_PUnpack
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct SimdImpl_PUnpack struct SimdImpl_PUnpack
{ {
// Unpack and interleave low-order bytes from src and dest into dest. // Unpack and interleave low-order bytes from src and dest into dest.
const xImplSimd_DestRegEither LBW; const xImplSimd_DestRegEither LBW;
// Unpack and interleave low-order words from src and dest into dest. // Unpack and interleave low-order words from src and dest into dest.
const xImplSimd_DestRegEither LWD; const xImplSimd_DestRegEither LWD;
// Unpack and interleave low-order doublewords from src and dest into dest. // Unpack and interleave low-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither LDQ; const xImplSimd_DestRegEither LDQ;
// Unpack and interleave low-order quadwords from src and dest into dest. // Unpack and interleave low-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE LQDQ; const xImplSimd_DestRegSSE LQDQ;
// Unpack and interleave high-order bytes from src and dest into dest. // Unpack and interleave high-order bytes from src and dest into dest.
const xImplSimd_DestRegEither HBW; const xImplSimd_DestRegEither HBW;
// Unpack and interleave high-order words from src and dest into dest. // Unpack and interleave high-order words from src and dest into dest.
const xImplSimd_DestRegEither HWD; const xImplSimd_DestRegEither HWD;
// Unpack and interleave high-order doublewords from src and dest into dest. // Unpack and interleave high-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither HDQ; const xImplSimd_DestRegEither HDQ;
// Unpack and interleave high-order quadwords from src and dest into dest. // Unpack and interleave high-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE HQDQ; const xImplSimd_DestRegSSE HQDQ;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SimdImpl_Pack // SimdImpl_Pack
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Pack with Signed or Unsigned Saturation // Pack with Signed or Unsigned Saturation
// //
struct SimdImpl_Pack struct SimdImpl_Pack
{ {
// Converts packed signed word integers from src and dest into packed signed // Converts packed signed word integers from src and dest into packed signed
// byte integers in dest, using signed saturation. // byte integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSWB; const xImplSimd_DestRegEither SSWB;
// Converts packed signed dword integers from src and dest into packed signed // Converts packed signed dword integers from src and dest into packed signed
// word integers in dest, using signed saturation. // word integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSDW; const xImplSimd_DestRegEither SSDW;
// Converts packed unsigned word integers from src and dest into packed unsigned // Converts packed unsigned word integers from src and dest into packed unsigned
// byte integers in dest, using unsigned saturation. // byte integers in dest, using unsigned saturation.
const xImplSimd_DestRegEither USWB; const xImplSimd_DestRegEither USWB;
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed // [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
// unsigned word integers in dest, using signed saturation. // unsigned word integers in dest, using signed saturation.
const xImplSimd_DestRegSSE USDW; const xImplSimd_DestRegSSE USDW;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SimdImpl_Unpack // SimdImpl_Unpack
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct xImplSimd_Unpack struct xImplSimd_Unpack
{ {
// Unpacks the high doubleword [single-precision] values from src and dest into // Unpacks the high doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this: // dest, such that the result of dest looks like this:
// dest[0] <- dest[2] // dest[0] <- dest[2]
// dest[1] <- src[2] // dest[1] <- src[2]
// dest[2] <- dest[3] // dest[2] <- dest[3]
// dest[3] <- src[3] // dest[3] <- src[3]
// //
const xImplSimd_DestRegSSE HPS; const xImplSimd_DestRegSSE HPS;
// Unpacks the high quadword [double-precision] values from src and dest into // Unpacks the high quadword [double-precision] values from src and dest into
// dest, such that the result of dest looks like this: // dest, such that the result of dest looks like this:
// dest.lo <- dest.hi // dest.lo <- dest.hi
// dest.hi <- src.hi // dest.hi <- src.hi
// //
const xImplSimd_DestRegSSE HPD; const xImplSimd_DestRegSSE HPD;
// Unpacks the low doubleword [single-precision] values from src and dest into // Unpacks the low doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this: // dest, such that the result of dest looks like this:
// dest[3] <- src[1] // dest[3] <- src[1]
// dest[2] <- dest[1] // dest[2] <- dest[1]
// dest[1] <- src[0] // dest[1] <- src[0]
// dest[0] <- dest[0] // dest[0] <- dest[0]
// //
const xImplSimd_DestRegSSE LPS; const xImplSimd_DestRegSSE LPS;
// Unpacks the low quadword [double-precision] values from src and dest into // Unpacks the low quadword [double-precision] values from src and dest into
// dest, effectively moving the low portion of src into the upper portion of dest. // dest, effectively moving the low portion of src into the upper portion of dest.
// The result of dest is loaded as such: // The result of dest is loaded as such:
// dest.hi <- src.lo // dest.hi <- src.lo
// dest.lo <- dest.lo [remains unchanged!] // dest.lo <- dest.lo [remains unchanged!]
// //
const xImplSimd_DestRegSSE LPD; const xImplSimd_DestRegSSE LPD;
}; };
struct xImplSimd_InsertExtractHelper struct xImplSimd_InsertExtractHelper
{ {
u16 Opcode; u16 Opcode;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid) // [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const; void operator()(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid) // [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const; void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SimdImpl_PInsert // SimdImpl_PInsert
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// PINSRW/B/D [all but Word form are SSE4.1 only!] // PINSRW/B/D [all but Word form are SSE4.1 only!]
// //
struct xImplSimd_PInsert struct xImplSimd_PInsert
{ {
void W(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const; void W(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
void W(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const; void W(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid) // [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
xImplSimd_InsertExtractHelper B; xImplSimd_InsertExtractHelper B;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid) // [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
xImplSimd_InsertExtractHelper D; xImplSimd_InsertExtractHelper D;
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// PEXTRW/B/D [all but Word form are SSE4.1 only!] // PEXTRW/B/D [all but Word form are SSE4.1 only!]
// //
// Note: Word form's indirect memory form is only available in SSE4.1. // Note: Word form's indirect memory form is only available in SSE4.1.
// //
struct SimdImpl_PExtract struct SimdImpl_PExtract
{ {
// Copies the word element specified by imm8 from src to dest. The upper bits // Copies the word element specified by imm8 from src to dest. The upper bits
// of dest are zero-extended (cleared). This can be used to extract any single packed // of dest are zero-extended (cleared). This can be used to extract any single packed
// word value from src into an x86 32 bit register. // word value from src into an x86 32 bit register.
// //
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension! // [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
// //
void W(const xRegister32 &to, const xRegisterSSE &from, u8 imm8) const; void W(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
void W(const xIndirectVoid &dest, const xRegisterSSE &from, u8 imm8) const; void W(const xIndirectVoid& dest, const xRegisterSSE& from, u8 imm8) const;
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits // [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
// of dest are zero-extended (cleared). This can be used to extract any single packed // of dest are zero-extended (cleared). This can be used to extract any single packed
// byte value from src into an x86 32 bit register. // byte value from src into an x86 32 bit register.
const xImplSimd_InsertExtractHelper B; const xImplSimd_InsertExtractHelper B;
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be // [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
// used to extract any single packed dword value from src into an x86 32 bit register. // used to extract any single packed dword value from src into an x86 32 bit register.
const xImplSimd_InsertExtractHelper D; const xImplSimd_InsertExtractHelper D;
}; };
} } // namespace x86Emitter

View File

@ -26,13 +26,13 @@ template <u8 Prefix, u16 Opcode>
class SimdImpl_DestRegSSE class SimdImpl_DestRegSSE
{ {
public: public:
__forceinline void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const { xOpWrite0F(Prefix, Opcode, to, from); } __forceinline void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const { xOpWrite0F(Prefix, Opcode, to, from); }
__forceinline void operator()(const xRegisterSSE &to, const ModSibBase &from) const __forceinline void operator()(const xRegisterSSE& to, const ModSibBase& from) const
{ {
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty(); bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load."); pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load.");
xOpWrite0F(Prefix, Opcode, to, from); xOpWrite0F(Prefix, Opcode, to, from);
} }
SimdImpl_DestRegSSE() {} //GCWho? SimdImpl_DestRegSSE() {} //GCWho?
}; };

View File

@ -20,55 +20,56 @@
namespace x86Emitter namespace x86Emitter
{ {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_Test // xImpl_Test
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// //
struct xImpl_Test struct xImpl_Test
{ {
void operator()(const xRegisterInt &to, const xRegisterInt &from) const; void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirect64orLess &dest, int imm) const; void operator()(const xIndirect64orLess& dest, int imm) const;
void operator()(const xRegisterInt &to, int imm) const; void operator()(const xRegisterInt& to, int imm) const;
}; };
enum G8Type { enum G8Type
G8Type_BT = 4, {
G8Type_BTS, G8Type_BT = 4,
G8Type_BTR, G8Type_BTS,
G8Type_BTC, G8Type_BTR,
}; G8Type_BTC,
};
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BSF / BSR // BSF / BSR
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet. // 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
// //
struct xImpl_BitScan struct xImpl_BitScan
{ {
// 0xbc [fwd] / 0xbd [rev] // 0xbc [fwd] / 0xbd [rev]
u16 Opcode; u16 Opcode;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const; void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const; void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// xImpl_Group8 // xImpl_Group8
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Bit Test Instructions - Valid on 16/32 bit instructions only. // Bit Test Instructions - Valid on 16/32 bit instructions only.
// //
struct xImpl_Group8 struct xImpl_Group8
{ {
G8Type InstType; G8Type InstType;
void operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const; void operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const;
void operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const; void operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const;
void operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const; void operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const;
void operator()(const xIndirect64 &bitbase, u8 bitoffset) const; void operator()(const xIndirect64& bitbase, u8 bitoffset) const;
void operator()(const xIndirect32 &bitbase, u8 bitoffset) const; void operator()(const xIndirect32& bitbase, u8 bitoffset) const;
void operator()(const xIndirect16 &bitbase, u8 bitoffset) const; void operator()(const xIndirect16& bitbase, u8 bitoffset) const;
}; };
} // End namespace x86Emitter } // End namespace x86Emitter

File diff suppressed because it is too large Load Diff

View File

@ -23,165 +23,168 @@ namespace x86Emitter
#define OpWriteSSE(pre, op) xOpWrite0F(pre, op, to, from) #define OpWriteSSE(pre, op) xOpWrite0F(pre, op, to, from)
extern void SimdPrefix(u8 prefix, u16 opcode); extern void SimdPrefix(u8 prefix, u16 opcode);
extern void EmitSibMagic(uint regfield, const void *address, int extraRIPOffset = 0); extern void EmitSibMagic(uint regfield, const void* address, int extraRIPOffset = 0);
extern void EmitSibMagic(uint regfield, const xIndirectVoid &info, int extraRIPOffset = 0); extern void EmitSibMagic(uint regfield, const xIndirectVoid& info, int extraRIPOffset = 0);
extern void EmitSibMagic(uint reg1, const xRegisterBase &reg2, int = 0); extern void EmitSibMagic(uint reg1, const xRegisterBase& reg2, int = 0);
extern void EmitSibMagic(const xRegisterBase &reg1, const xRegisterBase &reg2, int = 0); extern void EmitSibMagic(const xRegisterBase& reg1, const xRegisterBase& reg2, int = 0);
extern void EmitSibMagic(const xRegisterBase &reg1, const void *src, int extraRIPOffset = 0); extern void EmitSibMagic(const xRegisterBase& reg1, const void* src, int extraRIPOffset = 0);
extern void EmitSibMagic(const xRegisterBase &reg1, const xIndirectVoid &sib, int extraRIPOffset = 0); extern void EmitSibMagic(const xRegisterBase& reg1, const xIndirectVoid& sib, int extraRIPOffset = 0);
extern void EmitRex(uint regfield, const void *address); extern void EmitRex(uint regfield, const void* address);
extern void EmitRex(uint regfield, const xIndirectVoid &info); extern void EmitRex(uint regfield, const xIndirectVoid& info);
extern void EmitRex(uint reg1, const xRegisterBase &reg2); extern void EmitRex(uint reg1, const xRegisterBase& reg2);
extern void EmitRex(const xRegisterBase &reg1, const xRegisterBase &reg2); extern void EmitRex(const xRegisterBase& reg1, const xRegisterBase& reg2);
extern void EmitRex(const xRegisterBase &reg1, const void *src); extern void EmitRex(const xRegisterBase& reg1, const void* src);
extern void EmitRex(const xRegisterBase &reg1, const xIndirectVoid &sib); extern void EmitRex(const xRegisterBase& reg1, const xIndirectVoid& sib);
extern void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from); extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
template <typename T> template <typename T>
inline void xWrite(T val) inline void xWrite(T val)
{ {
*(T *)x86Ptr = val; *(T*)x86Ptr = val;
x86Ptr += sizeof(T); x86Ptr += sizeof(T);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1 &param1, const T2 &param2, int extraRIPOffset = 0) __emitinline void xOpWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2, int extraRIPOffset = 0)
{ {
if (prefix != 0) if (prefix != 0)
xWrite8(prefix); xWrite8(prefix);
EmitRex(param1, param2); EmitRex(param1, param2);
xWrite8(opcode); xWrite8(opcode);
EmitSibMagic(param1, param2, extraRIPOffset); EmitSibMagic(param1, param2, extraRIPOffset);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1 &param1, const T2 &param2) __emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2)
{ {
if (prefix != 0) if (prefix != 0)
xWrite8(prefix); xWrite8(prefix);
EmitRex(param1, param2); EmitRex(param1, param2);
xWrite8(opcode); xWrite8(opcode);
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// emitter helpers for xmm instruction with prefixes, most of which are using // emitter helpers for xmm instruction with prefixes, most of which are using
// the basic opcode format (items inside braces denote optional or conditional // the basic opcode format (items inside braces denote optional or conditional
// emission): // emission):
// //
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB] // [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
// //
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or // Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
// 0x3a [and other value will result in assertion failue]. // 0x3a [and other value will result in assertion failue].
// //
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 &param1, const T2 &param2) __emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2)
{ {
if (prefix != 0) if (prefix != 0)
xWrite8(prefix); xWrite8(prefix);
EmitRex(param1, param2); EmitRex(param1, param2);
SimdPrefix(0, opcode); SimdPrefix(0, opcode);
EmitSibMagic(param1, param2); EmitSibMagic(param1, param2);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 &param1, const T2 &param2, u8 imm8) __emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8)
{ {
if (prefix != 0) if (prefix != 0)
xWrite8(prefix); xWrite8(prefix);
EmitRex(param1, param2); EmitRex(param1, param2);
SimdPrefix(0, opcode); SimdPrefix(0, opcode);
EmitSibMagic(param1, param2, 1); EmitSibMagic(param1, param2, 1);
xWrite8(imm8); xWrite8(imm8);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1 &param1, const T2 &param2) __emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2)
{ {
xOpWrite0F(0, opcode, param1, param2); xOpWrite0F(0, opcode, param1, param2);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1 &param1, const T2 &param2, u8 imm8) __emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2, u8 imm8)
{ {
xOpWrite0F(0, opcode, param1, param2, imm8); xOpWrite0F(0, opcode, param1, param2, imm8);
} }
// VEX 2 Bytes Prefix // VEX 2 Bytes Prefix
template <typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
__emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1 &param1, const T2 &param2, const T3 &param3) __emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3)
{ {
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2); pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
const xRegisterInt &reg = param1.IsReg() ? param1 : param2; const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
#ifdef __M_X86_64 #ifdef __M_X86_64
u8 nR = reg.IsExtended() ? 0x00 : 0x80; u8 nR = reg.IsExtended() ? 0x00 : 0x80;
#else #else
u8 nR = 0x80; u8 nR = 0x80;
#endif #endif
u8 L = reg.IsWideSIMD() ? 4 : 0; u8 L = reg.IsWideSIMD() ? 4 : 0;
u8 nv = (~param2.GetId() & 0xF) << 3; u8 nv = (~param2.GetId() & 0xF) << 3;
u8 p = u8 p =
prefix == 0xF2 ? 3 : prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 : prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 : 0; prefix == 0x66 ? 1 :
0;
xWrite8(0xC5); xWrite8(0xC5);
xWrite8(nR | nv | L | p); xWrite8(nR | nv | L | p);
xWrite8(opcode); xWrite8(opcode);
EmitSibMagic(param1, param3); EmitSibMagic(param1, param3);
} }
// VEX 3 Bytes Prefix // VEX 3 Bytes Prefix
template <typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
__emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1 &param1, const T2 &param2, const T3 &param3, int w = -1) __emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3, int w = -1)
{ {
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2); pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A); pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
const xRegisterInt &reg = param1.IsReg() ? param1 : param2; const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
#ifdef __M_X86_64 #ifdef __M_X86_64
u8 nR = reg.IsExtended() ? 0x00 : 0x80; u8 nR = reg.IsExtended() ? 0x00 : 0x80;
u8 nB = param3.IsExtended() ? 0x00 : 0x20; u8 nB = param3.IsExtended() ? 0x00 : 0x20;
u8 nX = 0x40; // likely unused so hardwired to disabled u8 nX = 0x40; // likely unused so hardwired to disabled
#else #else
u8 nR = 0x80; u8 nR = 0x80;
u8 nB = 0x20; u8 nB = 0x20;
u8 nX = 0x40; u8 nX = 0x40;
#endif #endif
u8 L = reg.IsWideSIMD() ? 4 : 0; u8 L = reg.IsWideSIMD() ? 4 : 0;
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
0x80 * w; // take directly the W value 0x80 * w; // take directly the W value
u8 nv = (~param2.GetId() & 0xF) << 3; u8 nv = (~param2.GetId() & 0xF) << 3;
u8 p = u8 p =
prefix == 0xF2 ? 3 : prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 : prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 : 0; prefix == 0x66 ? 1 :
0;
u8 m = u8 m =
mb_prefix == 0x3A ? 3 : mb_prefix == 0x3A ? 3 :
mb_prefix == 0x38 ? 2 : 1; mb_prefix == 0x38 ? 2 :
1;
xWrite8(0xC4); xWrite8(0xC4);
xWrite8(nR | nX | nB | m); xWrite8(nR | nX | nB | m);
xWrite8(W | nv | L | p); xWrite8(W | nv | L | p);
xWrite8(opcode); xWrite8(opcode);
EmitSibMagic(param1, param3); EmitSibMagic(param1, param3);
} }
} } // namespace x86Emitter

View File

@ -33,215 +33,253 @@
namespace x86Emitter namespace x86Emitter
{ {
void xImpl_JmpCall::operator()(const xAddressReg &absreg) const { void xImpl_JmpCall::operator()(const xAddressReg& absreg) const
// Jumps are always wide and don't need the rex.W {
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide()); // Jumps are always wide and don't need the rex.W
} xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
void xImpl_JmpCall::operator()(const xIndirectNative &src) const { }
// Jumps are always wide and don't need the rex.W void xImpl_JmpCall::operator()(const xIndirectNative& src) const
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0)); {
xWrite8(0xff); // Jumps are always wide and don't need the rex.W
EmitSibMagic(isJmp ? 4 : 2, src); EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
} xWrite8(0xff);
EmitSibMagic(isJmp ? 4 : 2, src);
}
const xImpl_JmpCall xJMP = {true}; const xImpl_JmpCall xJMP = {true};
const xImpl_JmpCall xCALL = {false}; const xImpl_JmpCall xCALL = {false};
template <typename Reg1, typename Reg2> template <typename Reg1, typename Reg2>
void prepareRegsForFastcall(const Reg1 &a1, const Reg2 &a2) { void prepareRegsForFastcall(const Reg1& a1, const Reg2& a2)
if (a1.IsEmpty()) return; {
if (a1.IsEmpty())
return;
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg // Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
if (a2.Id != arg1reg.Id) { if (a2.Id != arg1reg.Id)
xMOV(Reg1(arg1reg), a1); {
if (!a2.IsEmpty()) { xMOV(Reg1(arg1reg), a1);
xMOV(Reg2(arg2reg), a2); if (!a2.IsEmpty())
} {
} else if (a1.Id != arg2reg.Id) { xMOV(Reg2(arg2reg), a2);
xMOV(Reg2(arg2reg), a2); }
xMOV(Reg1(arg1reg), a1); }
} else { else if (a1.Id != arg2reg.Id)
xPUSH(a1); {
xMOV(Reg2(arg2reg), a2); xMOV(Reg2(arg2reg), a2);
xPOP(Reg1(arg1reg)); xMOV(Reg1(arg1reg), a1);
} }
} else
{
xPUSH(a1);
xMOV(Reg2(arg2reg), a2);
xPOP(Reg1(arg1reg));
}
}
void xImpl_FastCall::operator()(void *f, const xRegister32 &a1, const xRegister32 &a2) const { void xImpl_FastCall::operator()(void* f, const xRegister32& a1, const xRegister32& a2) const
prepareRegsForFastcall(a1, a2); {
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f; prepareRegsForFastcall(a1, a2);
if ((sptr)disp == (s32)disp) { uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
xCALL(f); if ((sptr)disp == (s32)disp)
} else { {
xMOV(rax, ptrNative[f]); xCALL(f);
xCALL(rax); }
} else
} {
xMOV(rax, ptrNative[f]);
xCALL(rax);
}
}
#ifdef __M_X86_64 #ifdef __M_X86_64
void xImpl_FastCall::operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2) const { void xImpl_FastCall::operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2) const
prepareRegsForFastcall(a1, a2); {
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f; prepareRegsForFastcall(a1, a2);
if ((sptr)disp == (s32)disp) { uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
xCALL(f); if ((sptr)disp == (s32)disp)
} else { {
xMOV(rax, ptrNative[f]); xCALL(f);
xCALL(rax); }
} else
} {
xMOV(rax, ptrNative[f]);
xCALL(rax);
}
}
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegisterLong &a2) const { void xImpl_FastCall::operator()(void* f, u32 a1, const xRegisterLong& a2) const
if (!a2.IsEmpty()) { xMOV(arg2reg, a2); } {
xMOV(arg1reg, a1); if (!a2.IsEmpty())
(*this)(f, arg1reg, arg2reg); {
} xMOV(arg2reg, a2);
}
xMOV(arg1reg, a1);
(*this)(f, arg1reg, arg2reg);
}
#endif #endif
void xImpl_FastCall::operator()(void *f, void *a1) const { void xImpl_FastCall::operator()(void* f, void* a1) const
xLEA(arg1reg, ptr[a1]); {
(*this)(f, arg1reg, arg2reg); xLEA(arg1reg, ptr[a1]);
} (*this)(f, arg1reg, arg2reg);
}
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegister32 &a2) const { void xImpl_FastCall::operator()(void* f, u32 a1, const xRegister32& a2) const
if (!a2.IsEmpty()) { xMOV(arg2regd, a2); } {
xMOV(arg1regd, a1); if (!a2.IsEmpty())
(*this)(f, arg1regd, arg2regd); {
} xMOV(arg2regd, a2);
}
xMOV(arg1regd, a1);
(*this)(f, arg1regd, arg2regd);
}
void xImpl_FastCall::operator()(void *f, const xIndirect32 &a1) const { void xImpl_FastCall::operator()(void* f, const xIndirect32& a1) const
xMOV(arg1regd, a1); {
(*this)(f, arg1regd); xMOV(arg1regd, a1);
} (*this)(f, arg1regd);
}
void xImpl_FastCall::operator()(void *f, u32 a1, u32 a2) const { void xImpl_FastCall::operator()(void* f, u32 a1, u32 a2) const
xMOV(arg1regd, a1); {
xMOV(arg2regd, a2); xMOV(arg1regd, a1);
(*this)(f, arg1regd, arg2regd); xMOV(arg2regd, a2);
} (*this)(f, arg1regd, arg2regd);
}
void xImpl_FastCall::operator()(const xIndirectNative &f, const xRegisterLong &a1, const xRegisterLong &a2) const { void xImpl_FastCall::operator()(const xIndirectNative& f, const xRegisterLong& a1, const xRegisterLong& a2) const
prepareRegsForFastcall(a1, a2); {
xCALL(f); prepareRegsForFastcall(a1, a2);
} xCALL(f);
}
const xImpl_FastCall xFastCall = {}; const xImpl_FastCall xFastCall = {};
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement. // Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
// (displacements should be assigned relative to the end of the jump instruction, // (displacements should be assigned relative to the end of the jump instruction,
// or in other words *(retval+1) ) // or in other words *(retval+1) )
__emitinline s32 *xJcc32(JccComparisonType comparison, s32 displacement) __emitinline s32* xJcc32(JccComparisonType comparison, s32 displacement)
{ {
if (comparison == Jcc_Unconditional) if (comparison == Jcc_Unconditional)
xWrite8(0xe9); xWrite8(0xe9);
else { else
xWrite8(0x0f); {
xWrite8(0x80 | comparison); xWrite8(0x0f);
} xWrite8(0x80 | comparison);
xWrite<s32>(displacement); }
xWrite<s32>(displacement);
return ((s32 *)xGetPtr()) - 1; return ((s32*)xGetPtr()) - 1;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement. // Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
// (displacements should be assigned relative to the end of the jump instruction, // (displacements should be assigned relative to the end of the jump instruction,
// or in other words *(retval+1) ) // or in other words *(retval+1) )
__emitinline s8 *xJcc8(JccComparisonType comparison, s8 displacement) __emitinline s8* xJcc8(JccComparisonType comparison, s8 displacement)
{ {
xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison)); xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison));
xWrite<s8>(displacement); xWrite<s8>(displacement);
return (s8 *)xGetPtr() - 1; return (s8*)xGetPtr() - 1;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Writes a jump at the current x86Ptr, which targets a pre-established target address. // Writes a jump at the current x86Ptr, which targets a pre-established target address.
// (usually a backwards jump) // (usually a backwards jump)
// //
// slideForward - used internally by xSmartJump to indicate that the jump target is going // slideForward - used internally by xSmartJump to indicate that the jump target is going
// to slide forward in the event of an 8 bit displacement. // to slide forward in the event of an 8 bit displacement.
// //
__emitinline void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward) __emitinline void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward)
{ {
// Calculate the potential j8 displacement first, assuming an instruction length of 2: // Calculate the potential j8 displacement first, assuming an instruction length of 2:
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2); sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0; const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
displacement8 -= slideVal; displacement8 -= slideVal;
if (slideForward) { if (slideForward)
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!"); {
} pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
}
if (is_s8(displacement8)) if (is_s8(displacement8))
xJcc8(comparison, displacement8); xJcc8(comparison, displacement8);
else { else
// Perform a 32 bit jump instead. :( {
s32 *bah = xJcc32(comparison); // Perform a 32 bit jump instead. :(
sptr distance = (sptr)target - (sptr)xGetPtr(); s32* bah = xJcc32(comparison);
sptr distance = (sptr)target - (sptr)xGetPtr();
#ifdef __M_X86_64 #ifdef __M_X86_64
// This assert won't physically happen on x86 targets // This assert won't physically happen on x86 targets
pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register"); pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register");
#endif #endif
*bah = (s32)distance; *bah = (s32)distance;
} }
} }
// Low-level jump instruction! Specify a comparison type and a target in void* form, and // Low-level jump instruction! Specify a comparison type and a target in void* form, and
// a jump (either 8 or 32 bit) is generated. // a jump (either 8 or 32 bit) is generated.
__emitinline void xJcc(JccComparisonType comparison, const void *target) __emitinline void xJcc(JccComparisonType comparison, const void* target)
{ {
xJccKnownTarget(comparison, target, false); xJccKnownTarget(comparison, target, false);
} }
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype) xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
{ {
pxAssert(opsize == 1 || opsize == 4); pxAssert(opsize == 1 || opsize == 4);
pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type."); pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type.");
BasePtr = (s8 *)xGetPtr() + BasePtr = (s8*)xGetPtr() +
((opsize == 1) ? 2 : // j8's are always 2 bytes. ((opsize == 1) ? 2 : // j8's are always 2 bytes.
((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes ((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes
if (opsize == 1) if (opsize == 1)
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype)); xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
else { else
if (cctype == Jcc_Unconditional) {
xWrite8(0xe9); if (cctype == Jcc_Unconditional)
else { xWrite8(0xe9);
xWrite8(0x0f); else
xWrite8(0x80 | cctype); {
} xWrite8(0x0f);
} xWrite8(0x80 | cctype);
}
}
xAdvancePtr(opsize); xAdvancePtr(opsize);
} }
void xForwardJumpBase::_setTarget(uint opsize) const void xForwardJumpBase::_setTarget(uint opsize) const
{ {
pxAssertDev(BasePtr != NULL, ""); pxAssertDev(BasePtr != NULL, "");
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr; sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
if (opsize == 1) { if (opsize == 1)
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement."); {
BasePtr[-1] = (s8)displacement; pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
} else { BasePtr[-1] = (s8)displacement;
// full displacement, no sanity checks needed :D }
((s32 *)BasePtr)[-1] = displacement; else
} {
} // full displacement, no sanity checks needed :D
((s32*)BasePtr)[-1] = displacement;
}
}
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS. // returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
__fi JccComparisonType xInvertCond(JccComparisonType src) __fi JccComparisonType xInvertCond(JccComparisonType src)
{ {
pxAssert(src != Jcc_Unknown); pxAssert(src != Jcc_Unknown);
if (Jcc_Unconditional == src) if (Jcc_Unconditional == src)
return Jcc_Unconditional; return Jcc_Unconditional;
// x86 conditionals are clever! To invert conditional types, just invert the lower bit: // x86 conditionals are clever! To invert conditional types, just invert the lower bit:
return (JccComparisonType)((int)src ^ 1); return (JccComparisonType)((int)src ^ 1);
} }
} } // namespace x86Emitter

View File

@ -29,24 +29,24 @@
emitterT void ModRM(uint mod, uint reg, uint rm) emitterT void ModRM(uint mod, uint reg, uint rm)
{ {
// Note: Following assertions are for legacy support only. // Note: Following assertions are for legacy support only.
// The new emitter performs these sanity checks during operand construction, so these // The new emitter performs these sanity checks during operand construction, so these
// assertions can probably be removed once all legacy emitter code has been removed. // assertions can probably be removed once all legacy emitter code has been removed.
pxAssert(mod < 4); pxAssert(mod < 4);
pxAssert(reg < 8); pxAssert(reg < 8);
pxAssert(rm < 8); pxAssert(rm < 8);
xWrite8((mod << 6) | (reg << 3) | rm); xWrite8((mod << 6) | (reg << 3) | rm);
} }
emitterT void SibSB(uint ss, uint index, uint base) emitterT void SibSB(uint ss, uint index, uint base)
{ {
// Note: Following asserts are for legacy support only. // Note: Following asserts are for legacy support only.
// The new emitter performs these sanity checks during operand construction, so these // The new emitter performs these sanity checks during operand construction, so these
// assertions can probably be removed once all legacy emitter code has been removed. // assertions can probably be removed once all legacy emitter code has been removed.
pxAssert(ss < 4); pxAssert(ss < 4);
pxAssert(index < 8); pxAssert(index < 8);
pxAssert(base < 8); pxAssert(base < 8);
xWrite8((ss << 6) | (index << 3) | base); xWrite8((ss << 6) | (index << 3) | base);
} }
using namespace x86Emitter; using namespace x86Emitter;
@ -57,33 +57,33 @@ using namespace x86Emitter;
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
emitterT u8 *J8Rel(int cc, int to) emitterT u8* J8Rel(int cc, int to)
{ {
xWrite8(cc); xWrite8(cc);
xWrite8(to); xWrite8(to);
return (u8 *)(x86Ptr - 1); return (u8*)(x86Ptr - 1);
} }
emitterT u16 *J16Rel(int cc, u32 to) emitterT u16* J16Rel(int cc, u32 to)
{ {
xWrite16(0x0F66); xWrite16(0x0F66);
xWrite8(cc); xWrite8(cc);
xWrite16(to); xWrite16(to);
return (u16 *)(x86Ptr - 2); return (u16*)(x86Ptr - 2);
} }
emitterT u32 *J32Rel(int cc, u32 to) emitterT u32* J32Rel(int cc, u32 to)
{ {
xWrite8(0x0F); xWrite8(0x0F);
xWrite8(cc); xWrite8(cc);
xWrite32(to); xWrite32(to);
return (u32 *)(x86Ptr - 4); return (u32*)(x86Ptr - 4);
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
emitterT void x86SetPtr(u8 *ptr) emitterT void x86SetPtr(u8* ptr)
{ {
x86Ptr = ptr; x86Ptr = ptr;
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -92,57 +92,61 @@ emitterT void x86SetPtr(u8 *ptr)
// I don't auto-inline these because of the console logging in case of error, which tends // I don't auto-inline these because of the console logging in case of error, which tends
// to cause quite a bit of code bloat. // to cause quite a bit of code bloat.
// //
void x86SetJ8(u8 *j8) void x86SetJ8(u8* j8)
{ {
u32 jump = (x86Ptr - j8) - 1; u32 jump = (x86Ptr - j8) - 1;
if (jump > 0x7f) { if (jump > 0x7f)
Console.Error("j8 greater than 0x7f!!"); {
assert(0); Console.Error("j8 greater than 0x7f!!");
} assert(0);
*j8 = (u8)jump; }
*j8 = (u8)jump;
} }
void x86SetJ8A(u8 *j8) void x86SetJ8A(u8* j8)
{ {
u32 jump = (x86Ptr - j8) - 1; u32 jump = (x86Ptr - j8) - 1;
if (jump > 0x7f) { if (jump > 0x7f)
Console.Error("j8 greater than 0x7f!!"); {
assert(0); Console.Error("j8 greater than 0x7f!!");
} assert(0);
}
if (((uptr)x86Ptr & 0xf) > 4) { if (((uptr)x86Ptr & 0xf) > 4)
{
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf); uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
if (newjump <= 0x7f) { if (newjump <= 0x7f)
jump = newjump; {
while ((uptr)x86Ptr & 0xf) jump = newjump;
*x86Ptr++ = 0x90; while ((uptr)x86Ptr & 0xf)
} *x86Ptr++ = 0x90;
} }
*j8 = (u8)jump; }
*j8 = (u8)jump;
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
emitterT void x86SetJ32(u32 *j32) emitterT void x86SetJ32(u32* j32)
{ {
*j32 = (x86Ptr - (u8 *)j32) - 4; *j32 = (x86Ptr - (u8*)j32) - 4;
} }
emitterT void x86SetJ32A(u32 *j32) emitterT void x86SetJ32A(u32* j32)
{ {
while ((uptr)x86Ptr & 0xf) while ((uptr)x86Ptr & 0xf)
*x86Ptr++ = 0x90; *x86Ptr++ = 0x90;
x86SetJ32(j32); x86SetJ32(j32);
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
emitterT void x86Align(int bytes) emitterT void x86Align(int bytes)
{ {
// forward align // forward align
x86Ptr = (u8 *)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1)); x86Ptr = (u8*)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
} }
/********************/ /********************/
@ -154,262 +158,262 @@ emitterT void x86Align(int bytes)
//////////////////////////////////// ////////////////////////////////////
/* jmp rel8 */ /* jmp rel8 */
emitterT u8 *JMP8(u8 to) emitterT u8* JMP8(u8 to)
{ {
xWrite8(0xEB); xWrite8(0xEB);
xWrite8(to); xWrite8(to);
return x86Ptr - 1; return x86Ptr - 1;
} }
/* jmp rel32 */ /* jmp rel32 */
emitterT u32 *JMP32(uptr to) emitterT u32* JMP32(uptr to)
{ {
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff); assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
xWrite8(0xE9); xWrite8(0xE9);
xWrite32(to); xWrite32(to);
return (u32 *)(x86Ptr - 4); return (u32*)(x86Ptr - 4);
} }
/* jp rel8 */ /* jp rel8 */
emitterT u8 *JP8(u8 to) emitterT u8* JP8(u8 to)
{ {
return J8Rel(0x7A, to); return J8Rel(0x7A, to);
} }
/* jnp rel8 */ /* jnp rel8 */
emitterT u8 *JNP8(u8 to) emitterT u8* JNP8(u8 to)
{ {
return J8Rel(0x7B, to); return J8Rel(0x7B, to);
} }
/* je rel8 */ /* je rel8 */
emitterT u8 *JE8(u8 to) emitterT u8* JE8(u8 to)
{ {
return J8Rel(0x74, to); return J8Rel(0x74, to);
} }
/* jz rel8 */ /* jz rel8 */
emitterT u8 *JZ8(u8 to) emitterT u8* JZ8(u8 to)
{ {
return J8Rel(0x74, to); return J8Rel(0x74, to);
} }
/* js rel8 */ /* js rel8 */
emitterT u8 *JS8(u8 to) emitterT u8* JS8(u8 to)
{ {
return J8Rel(0x78, to); return J8Rel(0x78, to);
} }
/* jns rel8 */ /* jns rel8 */
emitterT u8 *JNS8(u8 to) emitterT u8* JNS8(u8 to)
{ {
return J8Rel(0x79, to); return J8Rel(0x79, to);
} }
/* jg rel8 */ /* jg rel8 */
emitterT u8 *JG8(u8 to) emitterT u8* JG8(u8 to)
{ {
return J8Rel(0x7F, to); return J8Rel(0x7F, to);
} }
/* jge rel8 */ /* jge rel8 */
emitterT u8 *JGE8(u8 to) emitterT u8* JGE8(u8 to)
{ {
return J8Rel(0x7D, to); return J8Rel(0x7D, to);
} }
/* jl rel8 */ /* jl rel8 */
emitterT u8 *JL8(u8 to) emitterT u8* JL8(u8 to)
{ {
return J8Rel(0x7C, to); return J8Rel(0x7C, to);
} }
/* ja rel8 */ /* ja rel8 */
emitterT u8 *JA8(u8 to) emitterT u8* JA8(u8 to)
{ {
return J8Rel(0x77, to); return J8Rel(0x77, to);
} }
emitterT u8 *JAE8(u8 to) emitterT u8* JAE8(u8 to)
{ {
return J8Rel(0x73, to); return J8Rel(0x73, to);
} }
/* jb rel8 */ /* jb rel8 */
emitterT u8 *JB8(u8 to) emitterT u8* JB8(u8 to)
{ {
return J8Rel(0x72, to); return J8Rel(0x72, to);
} }
/* jbe rel8 */ /* jbe rel8 */
emitterT u8 *JBE8(u8 to) emitterT u8* JBE8(u8 to)
{ {
return J8Rel(0x76, to); return J8Rel(0x76, to);
} }
/* jle rel8 */ /* jle rel8 */
emitterT u8 *JLE8(u8 to) emitterT u8* JLE8(u8 to)
{ {
return J8Rel(0x7E, to); return J8Rel(0x7E, to);
} }
/* jne rel8 */ /* jne rel8 */
emitterT u8 *JNE8(u8 to) emitterT u8* JNE8(u8 to)
{ {
return J8Rel(0x75, to); return J8Rel(0x75, to);
} }
/* jnz rel8 */ /* jnz rel8 */
emitterT u8 *JNZ8(u8 to) emitterT u8* JNZ8(u8 to)
{ {
return J8Rel(0x75, to); return J8Rel(0x75, to);
} }
/* jng rel8 */ /* jng rel8 */
emitterT u8 *JNG8(u8 to) emitterT u8* JNG8(u8 to)
{ {
return J8Rel(0x7E, to); return J8Rel(0x7E, to);
} }
/* jnge rel8 */ /* jnge rel8 */
emitterT u8 *JNGE8(u8 to) emitterT u8* JNGE8(u8 to)
{ {
return J8Rel(0x7C, to); return J8Rel(0x7C, to);
} }
/* jnl rel8 */ /* jnl rel8 */
emitterT u8 *JNL8(u8 to) emitterT u8* JNL8(u8 to)
{ {
return J8Rel(0x7D, to); return J8Rel(0x7D, to);
} }
/* jnle rel8 */ /* jnle rel8 */
emitterT u8 *JNLE8(u8 to) emitterT u8* JNLE8(u8 to)
{ {
return J8Rel(0x7F, to); return J8Rel(0x7F, to);
} }
/* jo rel8 */ /* jo rel8 */
emitterT u8 *JO8(u8 to) emitterT u8* JO8(u8 to)
{ {
return J8Rel(0x70, to); return J8Rel(0x70, to);
} }
/* jno rel8 */ /* jno rel8 */
emitterT u8 *JNO8(u8 to) emitterT u8* JNO8(u8 to)
{ {
return J8Rel(0x71, to); return J8Rel(0x71, to);
} }
// jb rel32 // jb rel32
emitterT u32 *JB32(u32 to) emitterT u32* JB32(u32 to)
{ {
return J32Rel(0x82, to); return J32Rel(0x82, to);
} }
/* je rel32 */ /* je rel32 */
emitterT u32 *JE32(u32 to) emitterT u32* JE32(u32 to)
{ {
return J32Rel(0x84, to); return J32Rel(0x84, to);
} }
/* jz rel32 */ /* jz rel32 */
emitterT u32 *JZ32(u32 to) emitterT u32* JZ32(u32 to)
{ {
return J32Rel(0x84, to); return J32Rel(0x84, to);
} }
/* js rel32 */ /* js rel32 */
emitterT u32 *JS32(u32 to) emitterT u32* JS32(u32 to)
{ {
return J32Rel(0x88, to); return J32Rel(0x88, to);
} }
/* jns rel32 */ /* jns rel32 */
emitterT u32 *JNS32(u32 to) emitterT u32* JNS32(u32 to)
{ {
return J32Rel(0x89, to); return J32Rel(0x89, to);
} }
/* jg rel32 */ /* jg rel32 */
emitterT u32 *JG32(u32 to) emitterT u32* JG32(u32 to)
{ {
return J32Rel(0x8F, to); return J32Rel(0x8F, to);
} }
/* jge rel32 */ /* jge rel32 */
emitterT u32 *JGE32(u32 to) emitterT u32* JGE32(u32 to)
{ {
return J32Rel(0x8D, to); return J32Rel(0x8D, to);
} }
/* jl rel32 */ /* jl rel32 */
emitterT u32 *JL32(u32 to) emitterT u32* JL32(u32 to)
{ {
return J32Rel(0x8C, to); return J32Rel(0x8C, to);
} }
/* jle rel32 */ /* jle rel32 */
emitterT u32 *JLE32(u32 to) emitterT u32* JLE32(u32 to)
{ {
return J32Rel(0x8E, to); return J32Rel(0x8E, to);
} }
/* ja rel32 */ /* ja rel32 */
emitterT u32 *JA32(u32 to) emitterT u32* JA32(u32 to)
{ {
return J32Rel(0x87, to); return J32Rel(0x87, to);
} }
/* jae rel32 */ /* jae rel32 */
emitterT u32 *JAE32(u32 to) emitterT u32* JAE32(u32 to)
{ {
return J32Rel(0x83, to); return J32Rel(0x83, to);
} }
/* jne rel32 */ /* jne rel32 */
emitterT u32 *JNE32(u32 to) emitterT u32* JNE32(u32 to)
{ {
return J32Rel(0x85, to); return J32Rel(0x85, to);
} }
/* jnz rel32 */ /* jnz rel32 */
emitterT u32 *JNZ32(u32 to) emitterT u32* JNZ32(u32 to)
{ {
return J32Rel(0x85, to); return J32Rel(0x85, to);
} }
/* jng rel32 */ /* jng rel32 */
emitterT u32 *JNG32(u32 to) emitterT u32* JNG32(u32 to)
{ {
return J32Rel(0x8E, to); return J32Rel(0x8E, to);
} }
/* jnge rel32 */ /* jnge rel32 */
emitterT u32 *JNGE32(u32 to) emitterT u32* JNGE32(u32 to)
{ {
return J32Rel(0x8C, to); return J32Rel(0x8C, to);
} }
/* jnl rel32 */ /* jnl rel32 */
emitterT u32 *JNL32(u32 to) emitterT u32* JNL32(u32 to)
{ {
return J32Rel(0x8D, to); return J32Rel(0x8D, to);
} }
/* jnle rel32 */ /* jnle rel32 */
emitterT u32 *JNLE32(u32 to) emitterT u32* JNLE32(u32 to)
{ {
return J32Rel(0x8F, to); return J32Rel(0x8F, to);
} }
/* jo rel32 */ /* jo rel32 */
emitterT u32 *JO32(u32 to) emitterT u32* JO32(u32 to)
{ {
return J32Rel(0x80, to); return J32Rel(0x80, to);
} }
/* jno rel32 */ /* jno rel32 */
emitterT u32 *JNO32(u32 to) emitterT u32* JNO32(u32 to)
{ {
return J32Rel(0x81, to); return J32Rel(0x81, to);
} }

View File

@ -25,13 +25,13 @@
//------------------------------------------------------------------ //------------------------------------------------------------------
// legacy jump/align functions // legacy jump/align functions
//------------------------------------------------------------------ //------------------------------------------------------------------
ATTR_DEP extern void x86SetPtr(u8 *ptr); ATTR_DEP extern void x86SetPtr(u8* ptr);
ATTR_DEP extern void x86SetJ8(u8 *j8); ATTR_DEP extern void x86SetJ8(u8* j8);
ATTR_DEP extern void x86SetJ8A(u8 *j8); ATTR_DEP extern void x86SetJ8A(u8* j8);
ATTR_DEP extern void x86SetJ16(u16 *j16); ATTR_DEP extern void x86SetJ16(u16* j16);
ATTR_DEP extern void x86SetJ16A(u16 *j16); ATTR_DEP extern void x86SetJ16A(u16* j16);
ATTR_DEP extern void x86SetJ32(u32 *j32); ATTR_DEP extern void x86SetJ32(u32* j32);
ATTR_DEP extern void x86SetJ32A(u32 *j32); ATTR_DEP extern void x86SetJ32A(u32* j32);
ATTR_DEP extern void x86Align(int bytes); ATTR_DEP extern void x86Align(int bytes);
ATTR_DEP extern void x86AlignExecutable(int align); ATTR_DEP extern void x86AlignExecutable(int align);
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -41,55 +41,55 @@ ATTR_DEP extern void x86AlignExecutable(int align);
//////////////////////////////////// ////////////////////////////////////
// jmp rel8 // jmp rel8
ATTR_DEP extern u8 *JMP8(u8 to); ATTR_DEP extern u8* JMP8(u8 to);
// jmp rel32 // jmp rel32
ATTR_DEP extern u32 *JMP32(uptr to); ATTR_DEP extern u32* JMP32(uptr to);
// jp rel8 // jp rel8
ATTR_DEP extern u8 *JP8(u8 to); ATTR_DEP extern u8* JP8(u8 to);
// jnp rel8 // jnp rel8
ATTR_DEP extern u8 *JNP8(u8 to); ATTR_DEP extern u8* JNP8(u8 to);
// je rel8 // je rel8
ATTR_DEP extern u8 *JE8(u8 to); ATTR_DEP extern u8* JE8(u8 to);
// jz rel8 // jz rel8
ATTR_DEP extern u8 *JZ8(u8 to); ATTR_DEP extern u8* JZ8(u8 to);
// jg rel8 // jg rel8
ATTR_DEP extern u8 *JG8(u8 to); ATTR_DEP extern u8* JG8(u8 to);
// jge rel8 // jge rel8
ATTR_DEP extern u8 *JGE8(u8 to); ATTR_DEP extern u8* JGE8(u8 to);
// js rel8 // js rel8
ATTR_DEP extern u8 *JS8(u8 to); ATTR_DEP extern u8* JS8(u8 to);
// jns rel8 // jns rel8
ATTR_DEP extern u8 *JNS8(u8 to); ATTR_DEP extern u8* JNS8(u8 to);
// jl rel8 // jl rel8
ATTR_DEP extern u8 *JL8(u8 to); ATTR_DEP extern u8* JL8(u8 to);
// ja rel8 // ja rel8
ATTR_DEP extern u8 *JA8(u8 to); ATTR_DEP extern u8* JA8(u8 to);
// jae rel8 // jae rel8
ATTR_DEP extern u8 *JAE8(u8 to); ATTR_DEP extern u8* JAE8(u8 to);
// jb rel8 // jb rel8
ATTR_DEP extern u8 *JB8(u8 to); ATTR_DEP extern u8* JB8(u8 to);
// jbe rel8 // jbe rel8
ATTR_DEP extern u8 *JBE8(u8 to); ATTR_DEP extern u8* JBE8(u8 to);
// jle rel8 // jle rel8
ATTR_DEP extern u8 *JLE8(u8 to); ATTR_DEP extern u8* JLE8(u8 to);
// jne rel8 // jne rel8
ATTR_DEP extern u8 *JNE8(u8 to); ATTR_DEP extern u8* JNE8(u8 to);
// jnz rel8 // jnz rel8
ATTR_DEP extern u8 *JNZ8(u8 to); ATTR_DEP extern u8* JNZ8(u8 to);
// jng rel8 // jng rel8
ATTR_DEP extern u8 *JNG8(u8 to); ATTR_DEP extern u8* JNG8(u8 to);
// jnge rel8 // jnge rel8
ATTR_DEP extern u8 *JNGE8(u8 to); ATTR_DEP extern u8* JNGE8(u8 to);
// jnl rel8 // jnl rel8
ATTR_DEP extern u8 *JNL8(u8 to); ATTR_DEP extern u8* JNL8(u8 to);
// jnle rel8 // jnle rel8
ATTR_DEP extern u8 *JNLE8(u8 to); ATTR_DEP extern u8* JNLE8(u8 to);
// jo rel8 // jo rel8
ATTR_DEP extern u8 *JO8(u8 to); ATTR_DEP extern u8* JO8(u8 to);
// jno rel8 // jno rel8
ATTR_DEP extern u8 *JNO8(u8 to); ATTR_DEP extern u8* JNO8(u8 to);
/* /*
// jb rel16 // jb rel16
@ -103,44 +103,44 @@ ATTR_DEP extern u16* JZ16( u16 to );
*/ */
// jns rel32 // jns rel32
ATTR_DEP extern u32 *JNS32(u32 to); ATTR_DEP extern u32* JNS32(u32 to);
// js rel32 // js rel32
ATTR_DEP extern u32 *JS32(u32 to); ATTR_DEP extern u32* JS32(u32 to);
// jb rel32 // jb rel32
ATTR_DEP extern u32 *JB32(u32 to); ATTR_DEP extern u32* JB32(u32 to);
// je rel32 // je rel32
ATTR_DEP extern u32 *JE32(u32 to); ATTR_DEP extern u32* JE32(u32 to);
// jz rel32 // jz rel32
ATTR_DEP extern u32 *JZ32(u32 to); ATTR_DEP extern u32* JZ32(u32 to);
// jg rel32 // jg rel32
ATTR_DEP extern u32 *JG32(u32 to); ATTR_DEP extern u32* JG32(u32 to);
// jge rel32 // jge rel32
ATTR_DEP extern u32 *JGE32(u32 to); ATTR_DEP extern u32* JGE32(u32 to);
// jl rel32 // jl rel32
ATTR_DEP extern u32 *JL32(u32 to); ATTR_DEP extern u32* JL32(u32 to);
// jle rel32 // jle rel32
ATTR_DEP extern u32 *JLE32(u32 to); ATTR_DEP extern u32* JLE32(u32 to);
// jae rel32 // jae rel32
ATTR_DEP extern u32 *JAE32(u32 to); ATTR_DEP extern u32* JAE32(u32 to);
// jne rel32 // jne rel32
ATTR_DEP extern u32 *JNE32(u32 to); ATTR_DEP extern u32* JNE32(u32 to);
// jnz rel32 // jnz rel32
ATTR_DEP extern u32 *JNZ32(u32 to); ATTR_DEP extern u32* JNZ32(u32 to);
// jng rel32 // jng rel32
ATTR_DEP extern u32 *JNG32(u32 to); ATTR_DEP extern u32* JNG32(u32 to);
// jnge rel32 // jnge rel32
ATTR_DEP extern u32 *JNGE32(u32 to); ATTR_DEP extern u32* JNGE32(u32 to);
// jnl rel32 // jnl rel32
ATTR_DEP extern u32 *JNL32(u32 to); ATTR_DEP extern u32* JNL32(u32 to);
// jnle rel32 // jnle rel32
ATTR_DEP extern u32 *JNLE32(u32 to); ATTR_DEP extern u32* JNLE32(u32 to);
// jo rel32 // jo rel32
ATTR_DEP extern u32 *JO32(u32 to); ATTR_DEP extern u32* JO32(u32 to);
// jno rel32 // jno rel32
ATTR_DEP extern u32 *JNO32(u32 to); ATTR_DEP extern u32* JNO32(u32 to);
// js rel32 // js rel32
ATTR_DEP extern u32 *JS32(u32 to); ATTR_DEP extern u32* JS32(u32 to);
//****************** //******************
// FPU instructions // FPU instructions

View File

@ -36,5 +36,5 @@ using x86Emitter::xWrite64;
extern void ModRM(uint mod, uint reg, uint rm); extern void ModRM(uint mod, uint reg, uint rm);
extern void SibSB(uint ss, uint index, uint base); extern void SibSB(uint ss, uint index, uint base);
extern void SET8R(int cc, int to); extern void SET8R(int cc, int to);
extern u8 *J8Rel(int cc, int to); extern u8* J8Rel(int cc, int to);
extern u32 *J32Rel(int cc, u32 to); extern u32* J32Rel(int cc, u32 to);

View File

@ -34,132 +34,146 @@
namespace x86Emitter namespace x86Emitter
{ {
void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from) void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from)
{ {
pxAssert(to.GetOperandSize() == from.GetOperandSize()); pxAssert(to.GetOperandSize() == from.GetOperandSize());
if (to == from) if (to == from)
return; // ignore redundant MOVs. return; // ignore redundant MOVs.
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to); xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
} }
void xImpl_Mov::operator()(const xRegisterInt &to, const xRegisterInt &from) const void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
{ {
// FIXME WTF? // FIXME WTF?
_xMovRtoR(to, from); _xMovRtoR(to, from);
} }
void xImpl_Mov::operator()(const xIndirectVoid &dest, const xRegisterInt &from) const void xImpl_Mov::operator()(const xIndirectVoid& dest, const xRegisterInt& from) const
{ {
// mov eax has a special from when writing directly to a DISP32 address // mov eax has a special from when writing directly to a DISP32 address
// (sans any register index/base registers). // (sans any register index/base registers).
#ifndef __M_X86_64 #ifndef __M_X86_64
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr // Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty()) { if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty())
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest); {
xWrite32(dest.Displacement); xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
} else xWrite32(dest.Displacement);
}
else
#endif #endif
{ {
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest); xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
} }
} }
void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) const void xImpl_Mov::operator()(const xRegisterInt& to, const xIndirectVoid& src) const
{ {
// mov eax has a special from when reading directly from a DISP32 address // mov eax has a special from when reading directly from a DISP32 address
// (sans any register index/base registers). // (sans any register index/base registers).
#ifndef __M_X86_64 #ifndef __M_X86_64
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr // Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty()) { if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty())
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src); {
xWrite32(src.Displacement); xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
} else xWrite32(src.Displacement);
}
else
#endif #endif
{ {
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src); xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
} }
} }
void xImpl_Mov::operator()(const xIndirect64orLess &dest, sptr imm) const void xImpl_Mov::operator()(const xIndirect64orLess& dest, sptr imm) const
{ {
switch (dest.GetOperandSize()) { switch (dest.GetOperandSize())
case 1: {
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!"); case 1:
break; pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
case 2: break;
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!"); case 2:
break; pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
case 4: break;
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!"); case 4:
break; pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
case 8: break;
pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!"); case 8:
break; pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!");
default: break;
pxAssertMsg(0, "Bad indirect size!"); default:
} pxAssertMsg(0, "Bad indirect size!");
xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize()); }
dest.xWriteImm(imm); xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize());
} dest.xWriteImm(imm);
}
// preserve_flags - set to true to disable optimizations which could alter the state of // preserve_flags - set to true to disable optimizations which could alter the state of
// the flags (namely replacing mov reg,0 with xor). // the flags (namely replacing mov reg,0 with xor).
void xImpl_Mov::operator()(const xRegisterInt &to, sptr imm, bool preserve_flags) const void xImpl_Mov::operator()(const xRegisterInt& to, sptr imm, bool preserve_flags) const
{ {
switch (to.GetOperandSize()) { switch (to.GetOperandSize())
case 1: {
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!"); case 1:
break; pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
case 2: break;
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!"); case 2:
break; pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
case 4: break;
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!"); case 4:
break; pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
case 8: break;
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!"); case 8:
break; pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!");
default: break;
pxAssertMsg(0, "Bad indirect size!"); default:
} pxAssertMsg(0, "Bad indirect size!");
const xRegisterInt& to_ = to.GetNonWide(); }
if (!preserve_flags && (imm == 0)) { const xRegisterInt& to_ = to.GetNonWide();
_g1_EmitOp(G1Type_XOR, to_, to_); if (!preserve_flags && (imm == 0))
} else if (imm == (u32)imm || !to.IsWide()) { {
// Note: MOV does not have (reg16/32,imm8) forms. _g1_EmitOp(G1Type_XOR, to_, to_);
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id; }
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_); else if (imm == (u32)imm || !to.IsWide())
to_.xWriteImm(imm); {
} else { // Note: MOV does not have (reg16/32,imm8) forms.
xOpWrite(to.GetPrefix16(), 0xc7, 0, to); u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
to.xWriteImm(imm); xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
} to_.xWriteImm(imm);
} }
else
{
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
to.xWriteImm(imm);
}
}
const xImpl_Mov xMOV; const xImpl_Mov xMOV;
#ifdef __M_X86_64 #ifdef __M_X86_64
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
{ {
if (imm == (u32)imm || imm == (s32)imm) { if (imm == (u32)imm || imm == (s32)imm)
xMOV(to, imm, preserve_flags); {
} else { xMOV(to, imm, preserve_flags);
u8 opcode = 0xb8 | to.Id; }
xOpAccWrite(to.GetPrefix16(), opcode, 0, to); else
xWrite64(imm); {
} u8 opcode = 0xb8 | to.Id;
} xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
xWrite64(imm);
}
}
const xImpl_MovImm64 xMOV64; const xImpl_MovImm64 xMOV64;
#endif #endif
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// CMOVcc // CMOVcc
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
#define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.") #define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.")
@ -169,63 +183,63 @@ const xImpl_MovImm64 xMOV64;
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const void xImpl_CMov::operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const
{ {
pxAssert(to->GetOperandSize() == from->GetOperandSize()); pxAssert(to->GetOperandSize() == from->GetOperandSize());
ccSane(); ccSane();
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from); xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from);
} }
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const void xImpl_CMov::operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const
{ {
ccSane(); ccSane();
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc); xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc);
} }
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } //void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } //void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
void xImpl_Set::operator()(const xRegister8 &to) const void xImpl_Set::operator()(const xRegister8& to) const
{ {
ccSane(); ccSane();
xOpWrite0F(0x90 | ccType, 0, to); xOpWrite0F(0x90 | ccType, 0, to);
} }
void xImpl_Set::operator()(const xIndirect8 &dest) const void xImpl_Set::operator()(const xIndirect8& dest) const
{ {
ccSane(); ccSane();
xOpWrite0F(0x90 | ccType, 0, dest); xOpWrite0F(0x90 | ccType, 0, dest);
} }
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); } //void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xRegister8 &from) const void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xRegister8& from) const
{ {
EbpAssert(); EbpAssert();
xOpWrite0F( xOpWrite0F(
(to->GetOperandSize() == 2) ? 0x66 : 0, (to->GetOperandSize() == 2) ? 0x66 : 0,
SignExtend ? 0xbe : 0xb6, SignExtend ? 0xbe : 0xb6,
to, from); to, from);
} }
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const
{ {
EbpAssert(); EbpAssert();
xOpWrite0F( xOpWrite0F(
(to->GetOperandSize() == 2) ? 0x66 : 0, (to->GetOperandSize() == 2) ? 0x66 : 0,
SignExtend ? 0xbe : 0xb6, SignExtend ? 0xbe : 0xb6,
to, sibsrc); to, sibsrc);
} }
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xRegister16 &from) const void xImpl_MovExtend::operator()(const xRegister32or64& to, const xRegister16& from) const
{ {
EbpAssert(); EbpAssert();
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from); xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from);
} }
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const void xImpl_MovExtend::operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const
{ {
EbpAssert(); EbpAssert();
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc); xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc);
} }
#if 0 #if 0
void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const
@ -241,58 +255,58 @@ void xImpl_MovExtend::operator()( const xRegister16or32& to, const xDirectOrIndi
} }
#endif #endif
const xImpl_MovExtend xMOVSX = {true}; const xImpl_MovExtend xMOVSX = {true};
const xImpl_MovExtend xMOVZX = {false}; const xImpl_MovExtend xMOVZX = {false};
const xImpl_CMov xCMOVA = {Jcc_Above}; const xImpl_CMov xCMOVA = {Jcc_Above};
const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual}; const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual};
const xImpl_CMov xCMOVB = {Jcc_Below}; const xImpl_CMov xCMOVB = {Jcc_Below};
const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual}; const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual};
const xImpl_CMov xCMOVG = {Jcc_Greater}; const xImpl_CMov xCMOVG = {Jcc_Greater};
const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual}; const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual};
const xImpl_CMov xCMOVL = {Jcc_Less}; const xImpl_CMov xCMOVL = {Jcc_Less};
const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual}; const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual};
const xImpl_CMov xCMOVZ = {Jcc_Zero}; const xImpl_CMov xCMOVZ = {Jcc_Zero};
const xImpl_CMov xCMOVE = {Jcc_Equal}; const xImpl_CMov xCMOVE = {Jcc_Equal};
const xImpl_CMov xCMOVNZ = {Jcc_NotZero}; const xImpl_CMov xCMOVNZ = {Jcc_NotZero};
const xImpl_CMov xCMOVNE = {Jcc_NotEqual}; const xImpl_CMov xCMOVNE = {Jcc_NotEqual};
const xImpl_CMov xCMOVO = {Jcc_Overflow}; const xImpl_CMov xCMOVO = {Jcc_Overflow};
const xImpl_CMov xCMOVNO = {Jcc_NotOverflow}; const xImpl_CMov xCMOVNO = {Jcc_NotOverflow};
const xImpl_CMov xCMOVC = {Jcc_Carry}; const xImpl_CMov xCMOVC = {Jcc_Carry};
const xImpl_CMov xCMOVNC = {Jcc_NotCarry}; const xImpl_CMov xCMOVNC = {Jcc_NotCarry};
const xImpl_CMov xCMOVS = {Jcc_Signed}; const xImpl_CMov xCMOVS = {Jcc_Signed};
const xImpl_CMov xCMOVNS = {Jcc_Unsigned}; const xImpl_CMov xCMOVNS = {Jcc_Unsigned};
const xImpl_CMov xCMOVPE = {Jcc_ParityEven}; const xImpl_CMov xCMOVPE = {Jcc_ParityEven};
const xImpl_CMov xCMOVPO = {Jcc_ParityOdd}; const xImpl_CMov xCMOVPO = {Jcc_ParityOdd};
const xImpl_Set xSETA = {Jcc_Above}; const xImpl_Set xSETA = {Jcc_Above};
const xImpl_Set xSETAE = {Jcc_AboveOrEqual}; const xImpl_Set xSETAE = {Jcc_AboveOrEqual};
const xImpl_Set xSETB = {Jcc_Below}; const xImpl_Set xSETB = {Jcc_Below};
const xImpl_Set xSETBE = {Jcc_BelowOrEqual}; const xImpl_Set xSETBE = {Jcc_BelowOrEqual};
const xImpl_Set xSETG = {Jcc_Greater}; const xImpl_Set xSETG = {Jcc_Greater};
const xImpl_Set xSETGE = {Jcc_GreaterOrEqual}; const xImpl_Set xSETGE = {Jcc_GreaterOrEqual};
const xImpl_Set xSETL = {Jcc_Less}; const xImpl_Set xSETL = {Jcc_Less};
const xImpl_Set xSETLE = {Jcc_LessOrEqual}; const xImpl_Set xSETLE = {Jcc_LessOrEqual};
const xImpl_Set xSETZ = {Jcc_Zero}; const xImpl_Set xSETZ = {Jcc_Zero};
const xImpl_Set xSETE = {Jcc_Equal}; const xImpl_Set xSETE = {Jcc_Equal};
const xImpl_Set xSETNZ = {Jcc_NotZero}; const xImpl_Set xSETNZ = {Jcc_NotZero};
const xImpl_Set xSETNE = {Jcc_NotEqual}; const xImpl_Set xSETNE = {Jcc_NotEqual};
const xImpl_Set xSETO = {Jcc_Overflow}; const xImpl_Set xSETO = {Jcc_Overflow};
const xImpl_Set xSETNO = {Jcc_NotOverflow}; const xImpl_Set xSETNO = {Jcc_NotOverflow};
const xImpl_Set xSETC = {Jcc_Carry}; const xImpl_Set xSETC = {Jcc_Carry};
const xImpl_Set xSETNC = {Jcc_NotCarry}; const xImpl_Set xSETNC = {Jcc_NotCarry};
const xImpl_Set xSETS = {Jcc_Signed}; const xImpl_Set xSETS = {Jcc_Signed};
const xImpl_Set xSETNS = {Jcc_Unsigned}; const xImpl_Set xSETNS = {Jcc_Unsigned};
const xImpl_Set xSETPE = {Jcc_ParityEven}; const xImpl_Set xSETPE = {Jcc_ParityEven};
const xImpl_Set xSETPO = {Jcc_ParityOdd}; const xImpl_Set xSETPO = {Jcc_ParityOdd};
} // end namespace x86Emitter } // end namespace x86Emitter

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,11 @@
#include "common/Dependencies.h" #include "common/Dependencies.h"
enum x86VendorType { enum x86VendorType
x86Vendor_Intel = 0, {
x86Vendor_AMD = 1, x86Vendor_Intel = 0,
x86Vendor_Unknown = 2 x86Vendor_AMD = 1,
x86Vendor_Unknown = 2
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -29,117 +30,120 @@ enum x86VendorType {
class x86capabilities class x86capabilities
{ {
public: public:
bool isIdentified; bool isIdentified;
public: public:
x86VendorType VendorID; x86VendorType VendorID;
uint FamilyID; // Processor Family uint FamilyID; // Processor Family
uint Model; // Processor Model uint Model; // Processor Model
uint TypeID; // Processor Type uint TypeID; // Processor Type
uint StepID; // Stepping ID uint StepID; // Stepping ID
u32 Flags; // Feature Flags u32 Flags; // Feature Flags
u32 Flags2; // More Feature Flags u32 Flags2; // More Feature Flags
u32 EFlags; // Extended Feature Flags u32 EFlags; // Extended Feature Flags
u32 EFlags2; // Extended Feature Flags pg2 u32 EFlags2; // Extended Feature Flags pg2
u32 SEFlag; // Structured Extended Feature Flags Enumeration u32 SEFlag; // Structured Extended Feature Flags Enumeration
char VendorName[16]; // Vendor/Creator ID char VendorName[16]; // Vendor/Creator ID
char FamilyName[50]; // the original cpu name char FamilyName[50]; // the original cpu name
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// x86 CPU Capabilities Section (all boolean flags!) // x86 CPU Capabilities Section (all boolean flags!)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
union union
{ {
struct struct
{ {
u32 hasFloatingPointUnit : 1; u32 hasFloatingPointUnit : 1;
u32 hasVirtual8086ModeEnhancements : 1; u32 hasVirtual8086ModeEnhancements : 1;
u32 hasDebuggingExtensions : 1; u32 hasDebuggingExtensions : 1;
u32 hasPageSizeExtensions : 1; u32 hasPageSizeExtensions : 1;
u32 hasTimeStampCounter : 1; u32 hasTimeStampCounter : 1;
u32 hasModelSpecificRegisters : 1; u32 hasModelSpecificRegisters : 1;
u32 hasPhysicalAddressExtension : 1; u32 hasPhysicalAddressExtension : 1;
u32 hasCOMPXCHG8BInstruction : 1; u32 hasCOMPXCHG8BInstruction : 1;
u32 hasAdvancedProgrammableInterruptController : 1; u32 hasAdvancedProgrammableInterruptController : 1;
u32 hasSEPFastSystemCall : 1; u32 hasSEPFastSystemCall : 1;
u32 hasMemoryTypeRangeRegisters : 1; u32 hasMemoryTypeRangeRegisters : 1;
u32 hasPTEGlobalFlag : 1; u32 hasPTEGlobalFlag : 1;
u32 hasMachineCheckArchitecture : 1; u32 hasMachineCheckArchitecture : 1;
u32 hasConditionalMoveAndCompareInstructions : 1; u32 hasConditionalMoveAndCompareInstructions : 1;
u32 hasFGPageAttributeTable : 1; u32 hasFGPageAttributeTable : 1;
u32 has36bitPageSizeExtension : 1; u32 has36bitPageSizeExtension : 1;
u32 hasProcessorSerialNumber : 1; u32 hasProcessorSerialNumber : 1;
u32 hasCFLUSHInstruction : 1; u32 hasCFLUSHInstruction : 1;
u32 hasDebugStore : 1; u32 hasDebugStore : 1;
u32 hasACPIThermalMonitorAndClockControl : 1; u32 hasACPIThermalMonitorAndClockControl : 1;
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1; u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
u32 hasStreamingSIMDExtensions : 1; u32 hasStreamingSIMDExtensions : 1;
u32 hasStreamingSIMD2Extensions : 1; u32 hasStreamingSIMD2Extensions : 1;
u32 hasSelfSnoop : 1; u32 hasSelfSnoop : 1;
// is TRUE for both multi-core and Hyperthreaded CPUs. // is TRUE for both multi-core and Hyperthreaded CPUs.
u32 hasMultiThreading : 1; u32 hasMultiThreading : 1;
u32 hasThermalMonitor : 1; u32 hasThermalMonitor : 1;
u32 hasIntel64BitArchitecture : 1; u32 hasIntel64BitArchitecture : 1;
u32 hasStreamingSIMD3Extensions : 1; u32 hasStreamingSIMD3Extensions : 1;
u32 hasSupplementalStreamingSIMD3Extensions : 1; u32 hasSupplementalStreamingSIMD3Extensions : 1;
u32 hasStreamingSIMD4Extensions : 1; u32 hasStreamingSIMD4Extensions : 1;
u32 hasStreamingSIMD4Extensions2 : 1; u32 hasStreamingSIMD4Extensions2 : 1;
u32 hasAVX : 1; u32 hasAVX : 1;
u32 hasAVX2 : 1; u32 hasAVX2 : 1;
u32 hasBMI1 : 1; u32 hasBMI1 : 1;
u32 hasBMI2 : 1; u32 hasBMI2 : 1;
u32 hasFMA : 1; u32 hasFMA : 1;
// AMD-specific CPU Features // AMD-specific CPU Features
u32 hasAMD64BitArchitecture : 1; u32 hasAMD64BitArchitecture : 1;
u32 hasStreamingSIMD4ExtensionsA : 1; u32 hasStreamingSIMD4ExtensionsA : 1;
}; };
u64 AllCapabilities; u64 AllCapabilities;
}; };
// Core Counts! // Core Counts!
u32 PhysicalCores; u32 PhysicalCores;
u32 LogicalCores; u32 LogicalCores;
public: public:
x86capabilities(); x86capabilities();
void Identify(); void Identify();
void CountCores(); void CountCores();
wxString GetTypeName() const; wxString GetTypeName() const;
u32 CalculateMHz() const; u32 CalculateMHz() const;
void SIMD_EstablishMXCSRmask(); void SIMD_EstablishMXCSRmask();
protected: protected:
s64 _CPUSpeedHz(u64 time) const; s64 _CPUSpeedHz(u64 time) const;
void CountLogicalCores(); void CountLogicalCores();
}; };
enum SSE_RoundMode { enum SSE_RoundMode
SSE_RoundMode_FIRST = 0, {
SSEround_Nearest = 0, SSE_RoundMode_FIRST = 0,
SSEround_NegInf, SSEround_Nearest = 0,
SSEround_PosInf, SSEround_NegInf,
SSEround_Chop, SSEround_PosInf,
SSE_RoundMode_COUNT SSEround_Chop,
SSE_RoundMode_COUNT
}; };
ImplementEnumOperators(SSE_RoundMode); ImplementEnumOperators(SSE_RoundMode);
// Predeclaration for xIndirect32 // Predeclaration for xIndirect32
namespace x86Emitter { namespace x86Emitter
template <typename T> class xIndirect; {
template <typename T>
class xIndirect;
typedef xIndirect<u32> xIndirect32; typedef xIndirect<u32> xIndirect32;
} } // namespace x86Emitter
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SSE_MXCSR - Control/Status Register (bitfield) // SSE_MXCSR - Control/Status Register (bitfield)
@ -153,52 +157,52 @@ namespace x86Emitter {
// //
union SSE_MXCSR union SSE_MXCSR
{ {
u32 bitmask; u32 bitmask;
struct struct
{ {
u32 u32
InvalidOpFlag : 1, InvalidOpFlag : 1,
DenormalFlag : 1, DenormalFlag : 1,
DivideByZeroFlag : 1, DivideByZeroFlag : 1,
OverflowFlag : 1, OverflowFlag : 1,
UnderflowFlag : 1, UnderflowFlag : 1,
PrecisionFlag : 1, PrecisionFlag : 1,
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on // This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
// SSE1 cpus will result in an invalid instruction exception when executing // SSE1 cpus will result in an invalid instruction exception when executing
// LDMXSCR. // LDMXSCR.
DenormalsAreZero : 1, DenormalsAreZero : 1,
InvalidOpMask : 1, InvalidOpMask : 1,
DenormalMask : 1, DenormalMask : 1,
DivideByZeroMask : 1, DivideByZeroMask : 1,
OverflowMask : 1, OverflowMask : 1,
UnderflowMask : 1, UnderflowMask : 1,
PrecisionMask : 1, PrecisionMask : 1,
RoundingControl : 2, RoundingControl : 2,
FlushToZero : 1; FlushToZero : 1;
}; };
SSE_RoundMode GetRoundMode() const; SSE_RoundMode GetRoundMode() const;
SSE_MXCSR &SetRoundMode(SSE_RoundMode mode); SSE_MXCSR& SetRoundMode(SSE_RoundMode mode);
SSE_MXCSR &ClearExceptionFlags(); SSE_MXCSR& ClearExceptionFlags();
SSE_MXCSR &EnableExceptions(); SSE_MXCSR& EnableExceptions();
SSE_MXCSR &DisableExceptions(); SSE_MXCSR& DisableExceptions();
SSE_MXCSR &ApplyReserveMask(); SSE_MXCSR& ApplyReserveMask();
bool operator==(const SSE_MXCSR &right) const bool operator==(const SSE_MXCSR& right) const
{ {
return bitmask == right.bitmask; return bitmask == right.bitmask;
} }
bool operator!=(const SSE_MXCSR &right) const bool operator!=(const SSE_MXCSR& right) const
{ {
return bitmask != right.bitmask; return bitmask != right.bitmask;
} }
operator x86Emitter::xIndirect32() const; operator x86Emitter::xIndirect32() const;
}; };
extern SSE_MXCSR MXCSR_Mask; extern SSE_MXCSR MXCSR_Mask;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,115 +22,117 @@ using namespace pxSizerFlags;
// pxCheckBox Implementations // pxCheckBox Implementations
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext, int flags) pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext, int flags)
: wxPanelWithHelpers(parent, wxVERTICAL) : wxPanelWithHelpers(parent, wxVERTICAL)
{ {
Init(label, subtext, flags); Init(label, subtext, flags);
} }
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, int flags) pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, int flags)
: wxPanelWithHelpers(parent, wxVERTICAL) : wxPanelWithHelpers(parent, wxVERTICAL)
{ {
Init(label, wxEmptyString, flags); Init(label, wxEmptyString, flags);
} }
void pxCheckBox::Init(const wxString &label, const wxString &subtext, int flags) void pxCheckBox::Init(const wxString& label, const wxString& subtext, int flags)
{ {
m_subtext = NULL; m_subtext = NULL;
m_subPadding = StdPadding * 2; m_subPadding = StdPadding * 2;
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags); m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
*this += m_checkbox | pxSizerFlags::StdExpand(); *this += m_checkbox | pxSizerFlags::StdExpand();
static const int Indentation = 23; static const int Indentation = 23;
if (!subtext.IsEmpty()) { if (!subtext.IsEmpty())
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT); {
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
wxFlexGridSizer &spaced(*new wxFlexGridSizer(3)); wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
spaced.AddGrowableCol(1); spaced.AddGrowableCol(1);
spaced += Indentation; spaced += Indentation;
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand()); m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
//spaced += pxSizerFlags::StdPadding; //spaced += pxSizerFlags::StdPadding;
*this += &spaced | pxExpand; *this += &spaced | pxExpand;
} }
Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId()); Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId());
} }
pxCheckBox &pxCheckBox::SetSubPadding(int pad) pxCheckBox& pxCheckBox::SetSubPadding(int pad)
{ {
m_subPadding = pad; m_subPadding = pad;
if (m_sizerItem_subtext) { if (m_sizerItem_subtext)
m_sizerItem_subtext->SetBorder(m_subPadding); {
Fit(); m_sizerItem_subtext->SetBorder(m_subPadding);
} Fit();
return *this; }
return *this;
} }
// applies the tooltip to both both the checkbox and it's static subtext (if present), and // applies the tooltip to both both the checkbox and it's static subtext (if present), and
// performs word wrapping on platforms that need it (eg mswindows). // performs word wrapping on platforms that need it (eg mswindows).
pxCheckBox &pxCheckBox::SetToolTip(const wxString &tip) pxCheckBox& pxCheckBox::SetToolTip(const wxString& tip)
{ {
pxSetToolTip(m_checkbox, tip); pxSetToolTip(m_checkbox, tip);
pxSetToolTip(m_subtext, tip); pxSetToolTip(m_subtext, tip);
return *this; return *this;
} }
pxCheckBox &pxCheckBox::SetValue(bool val) pxCheckBox& pxCheckBox::SetValue(bool val)
{ {
pxAssert(m_checkbox); pxAssert(m_checkbox);
m_checkbox->SetValue(val); m_checkbox->SetValue(val);
return *this; return *this;
} }
pxCheckBox &pxCheckBox::SetIndeterminate() pxCheckBox& pxCheckBox::SetIndeterminate()
{ {
pxAssert(m_checkbox); pxAssert(m_checkbox);
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED); m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
return *this; return *this;
} }
pxCheckBox &pxCheckBox::SetState(wxCheckBoxState state) pxCheckBox& pxCheckBox::SetState(wxCheckBoxState state)
{ {
pxAssert(m_checkbox); pxAssert(m_checkbox);
m_checkbox->Set3StateValue(state); m_checkbox->Set3StateValue(state);
return *this; return *this;
} }
// Forwards checkbox actions on the internal checkbox (called 'checkpart') to listeners // Forwards checkbox actions on the internal checkbox (called 'checkpart') to listeners
// bound to the pxCheckBox "parent" panel. This helps the pxCheckBox behave more like a // bound to the pxCheckBox "parent" panel. This helps the pxCheckBox behave more like a
// traditional checkbox. // traditional checkbox.
void pxCheckBox::OnCheckpartCommand(wxCommandEvent &evt) void pxCheckBox::OnCheckpartCommand(wxCommandEvent& evt)
{ {
evt.Skip(); evt.Skip();
wxCommandEvent newevt(evt); wxCommandEvent newevt(evt);
newevt.SetEventObject(this); newevt.SetEventObject(this);
newevt.SetId(GetId()); newevt.SetId(GetId());
GetEventHandler()->ProcessEvent(newevt); GetEventHandler()->ProcessEvent(newevt);
} }
void pxCheckBox::OnSubtextClicked(wxCommandEvent &evt) void pxCheckBox::OnSubtextClicked(wxCommandEvent& evt)
{ {
// TODO? // TODO?
// We can enable the ability to allow clicks on the subtext desc/label to toggle // We can enable the ability to allow clicks on the subtext desc/label to toggle
// the checkmark. Not sure if that's desirable. // the checkmark. Not sure if that's desirable.
} }
void operator+=(wxSizer &target, pxCheckBox *src) void operator+=(wxSizer& target, pxCheckBox* src)
{ {
if (src) if (src)
target.Add(src, pxExpand); target.Add(src, pxExpand);
} }
void operator+=(wxSizer &target, pxCheckBox &src) void operator+=(wxSizer& target, pxCheckBox& src)
{ {
target.Add(&src, pxExpand); target.Add(&src, pxExpand);
} }
void operator+=(wxSizer *target, pxCheckBox &src) void operator+=(wxSizer* target, pxCheckBox& src)
{ {
target->Add(&src, pxExpand); target->Add(&src, pxExpand);
} }

View File

@ -29,74 +29,74 @@
class pxCheckBox : public wxPanelWithHelpers class pxCheckBox : public wxPanelWithHelpers
{ {
protected: protected:
wxCheckBox *m_checkbox; wxCheckBox* m_checkbox;
pxStaticText *m_subtext; pxStaticText* m_subtext;
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused. // padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
int m_subPadding; int m_subPadding;
wxSizerItem *m_sizerItem_subtext; wxSizerItem* m_sizerItem_subtext;
public: public:
pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext = wxEmptyString, int flags = wxCHK_2STATE); pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext = wxEmptyString, int flags = wxCHK_2STATE);
pxCheckBox(wxWindow *parent, const wxString &label, int flags); pxCheckBox(wxWindow* parent, const wxString& label, int flags);
virtual ~pxCheckBox() = default; virtual ~pxCheckBox() = default;
bool HasSubText() const { return m_subtext != NULL; } bool HasSubText() const { return m_subtext != NULL; }
const pxStaticText *GetSubText() const { return m_subtext; } const pxStaticText* GetSubText() const { return m_subtext; }
pxCheckBox &SetSubPadding(int pad); pxCheckBox& SetSubPadding(int pad);
pxCheckBox &SetToolTip(const wxString &tip); pxCheckBox& SetToolTip(const wxString& tip);
pxCheckBox &SetValue(bool val); pxCheckBox& SetValue(bool val);
pxCheckBox &SetIndeterminate(); pxCheckBox& SetIndeterminate();
pxCheckBox &SetState(wxCheckBoxState state); pxCheckBox& SetState(wxCheckBoxState state);
wxCheckBoxState GetState() const wxCheckBoxState GetState() const
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue(); return m_checkbox->Get3StateValue();
} }
bool GetValue() const bool GetValue() const
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return m_checkbox->GetValue(); return m_checkbox->GetValue();
} }
bool IsChecked() const bool IsChecked() const
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return m_checkbox->IsChecked(); return m_checkbox->IsChecked();
} }
bool IsIndeterminate() const bool IsIndeterminate() const
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED; return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
} }
operator wxCheckBox &() operator wxCheckBox&()
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return *m_checkbox; return *m_checkbox;
} }
operator const wxCheckBox &() const operator const wxCheckBox&() const
{ {
pxAssert(m_checkbox != NULL); pxAssert(m_checkbox != NULL);
return *m_checkbox; return *m_checkbox;
} }
wxCheckBox *GetWxPtr() { return m_checkbox; } wxCheckBox* GetWxPtr() { return m_checkbox; }
const wxCheckBox *GetWxPtr() const { return m_checkbox; } const wxCheckBox* GetWxPtr() const { return m_checkbox; }
//wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); } //wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); }
protected: protected:
void Init(const wxString &label, const wxString &subtext, int flags); void Init(const wxString& label, const wxString& subtext, int flags);
void OnCheckpartCommand(wxCommandEvent &evt); void OnCheckpartCommand(wxCommandEvent& evt);
void OnSubtextClicked(wxCommandEvent &evt); void OnSubtextClicked(wxCommandEvent& evt);
}; };
extern void operator+=(wxSizer &target, pxCheckBox &src); extern void operator+=(wxSizer& target, pxCheckBox& src);
template <> template <>
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxCheckBox> &src) inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src)
{ {
target.Add(src.window, src.flags); target.Add(src.window, src.flags);
} }

View File

@ -31,36 +31,36 @@ typedef void FnType_Void();
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class SynchronousActionState class SynchronousActionState
{ {
DeclareNoncopyableObject(SynchronousActionState); DeclareNoncopyableObject(SynchronousActionState);
protected: protected:
bool m_posted; bool m_posted;
Threading::Semaphore m_sema; Threading::Semaphore m_sema;
ScopedExcept m_exception; ScopedExcept m_exception;
public: public:
sptr return_value; sptr return_value;
SynchronousActionState() SynchronousActionState()
{ {
m_posted = false; m_posted = false;
return_value = 0; return_value = 0;
} }
virtual ~SynchronousActionState() = default; virtual ~SynchronousActionState() = default;
void SetException(const BaseException &ex); void SetException(const BaseException& ex);
void SetException(BaseException *ex); void SetException(BaseException* ex);
Threading::Semaphore &GetSemaphore() { return m_sema; } Threading::Semaphore& GetSemaphore() { return m_sema; }
const Threading::Semaphore &GetSemaphore() const { return m_sema; } const Threading::Semaphore& GetSemaphore() const { return m_sema; }
void RethrowException() const; void RethrowException() const;
int WaitForResult(); int WaitForResult();
int WaitForResult_NoExceptions(); int WaitForResult_NoExceptions();
void PostResult(int res); void PostResult(int res);
void ClearResult(); void ClearResult();
void PostResult(); void PostResult();
}; };
@ -73,21 +73,21 @@ public:
// //
class pxSimpleEvent : public wxEvent class pxSimpleEvent : public wxEvent
{ {
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
public: public:
explicit pxSimpleEvent(int evtid = 0) explicit pxSimpleEvent(int evtid = 0)
: wxEvent(0, evtid) : wxEvent(0, evtid)
{ {
} }
pxSimpleEvent(wxWindowID winId, int evtid) pxSimpleEvent(wxWindowID winId, int evtid)
: wxEvent(winId, evtid) : wxEvent(winId, evtid)
{ {
} }
pxSimpleEvent(const pxSimpleEvent&) = default; pxSimpleEvent(const pxSimpleEvent&) = default;
virtual wxEvent *Clone() const { return new pxSimpleEvent(*this); } virtual wxEvent* Clone() const { return new pxSimpleEvent(*this); }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -99,41 +99,41 @@ wxDECLARE_EVENT(pxEvt_InvokeAction, pxActionEvent);
class pxActionEvent : public wxEvent class pxActionEvent : public wxEvent
{ {
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
protected: protected:
SynchronousActionState *m_state; SynchronousActionState* m_state;
public: public:
virtual ~pxActionEvent() = default; virtual ~pxActionEvent() = default;
virtual pxActionEvent *Clone() const { return new pxActionEvent(*this); } virtual pxActionEvent* Clone() const { return new pxActionEvent(*this); }
explicit pxActionEvent(SynchronousActionState *sema = NULL, int msgtype = pxEvt_InvokeAction); explicit pxActionEvent(SynchronousActionState* sema = NULL, int msgtype = pxEvt_InvokeAction);
explicit pxActionEvent(SynchronousActionState &sema, int msgtype = pxEvt_InvokeAction); explicit pxActionEvent(SynchronousActionState& sema, int msgtype = pxEvt_InvokeAction);
pxActionEvent(const pxActionEvent &src); pxActionEvent(const pxActionEvent& src);
Threading::Semaphore *GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; } Threading::Semaphore* GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
const SynchronousActionState *GetSyncState() const { return m_state; } const SynchronousActionState* GetSyncState() const { return m_state; }
SynchronousActionState *GetSyncState() { return m_state; } SynchronousActionState* GetSyncState() { return m_state; }
void SetSyncState(SynchronousActionState *obj) { m_state = obj; } void SetSyncState(SynchronousActionState* obj) { m_state = obj; }
void SetSyncState(SynchronousActionState &obj) { m_state = &obj; } void SetSyncState(SynchronousActionState& obj) { m_state = &obj; }
virtual void SetException(BaseException *ex); virtual void SetException(BaseException* ex);
void SetException(const BaseException &ex); void SetException(const BaseException& ex);
virtual void _DoInvokeEvent(); virtual void _DoInvokeEvent();
protected: protected:
// Extending classes should implement this method to perform whatever action it is // Extending classes should implement this method to perform whatever action it is
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI // the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
// thread, and exceptions will be handled automatically. // thread, and exceptions will be handled automatically.
// //
// Exception note: exceptions are passed back to the thread that posted the event // Exception note: exceptions are passed back to the thread that posted the event
// to the queue, when possible. If the calling thread is not blocking for a result // to the queue, when possible. If the calling thread is not blocking for a result
// from this event, then the exception will be posted to the Main/UI thread instead. // from this event, then the exception will be posted to the Main/UI thread instead.
virtual void InvokeEvent() {} virtual void InvokeEvent() {}
}; };
@ -142,27 +142,27 @@ protected:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class pxExceptionEvent : public pxActionEvent class pxExceptionEvent : public pxActionEvent
{ {
typedef pxActionEvent _parent; typedef pxActionEvent _parent;
protected: protected:
BaseException *m_except; BaseException* m_except;
public: public:
pxExceptionEvent(BaseException *ex = NULL) pxExceptionEvent(BaseException* ex = NULL)
{ {
m_except = ex; m_except = ex;
} }
pxExceptionEvent(const BaseException &ex); pxExceptionEvent(const BaseException& ex);
virtual ~pxExceptionEvent() virtual ~pxExceptionEvent()
{ {
} }
virtual pxExceptionEvent *Clone() const { return new pxExceptionEvent(*this); } virtual pxExceptionEvent* Clone() const { return new pxExceptionEvent(*this); }
protected: protected:
void InvokeEvent(); void InvokeEvent();
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -171,29 +171,29 @@ protected:
class pxSynchronousCommandEvent : public wxCommandEvent class pxSynchronousCommandEvent : public wxCommandEvent
{ {
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
protected: protected:
SynchronousActionState *m_sync; SynchronousActionState* m_sync;
wxEventType m_realEvent; wxEventType m_realEvent;
public: public:
virtual ~pxSynchronousCommandEvent() = default; virtual ~pxSynchronousCommandEvent() = default;
virtual pxSynchronousCommandEvent *Clone() const { return new pxSynchronousCommandEvent(*this); } virtual pxSynchronousCommandEvent* Clone() const { return new pxSynchronousCommandEvent(*this); }
pxSynchronousCommandEvent(SynchronousActionState *sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0); pxSynchronousCommandEvent(SynchronousActionState* sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType = wxEVT_NULL, int winid = 0); pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt); pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt);
pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt); pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt);
pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src); pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src);
Threading::Semaphore *GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; } Threading::Semaphore* GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
wxEventType GetRealEventType() const { return m_realEvent; } wxEventType GetRealEventType() const { return m_realEvent; }
void SetException(BaseException *ex); void SetException(BaseException* ex);
void SetException(const BaseException &ex); void SetException(const BaseException& ex);
}; };
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent); wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
@ -203,23 +203,23 @@ wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class BaseMessageBoxEvent : public pxActionEvent class BaseMessageBoxEvent : public pxActionEvent
{ {
typedef pxActionEvent _parent; typedef pxActionEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
protected: protected:
wxString m_Content; wxString m_Content;
public: public:
virtual ~BaseMessageBoxEvent() = default; virtual ~BaseMessageBoxEvent() = default;
virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); } virtual BaseMessageBoxEvent* Clone() const { return new BaseMessageBoxEvent(*this); }
explicit BaseMessageBoxEvent(const wxString &content = wxEmptyString, SynchronousActionState *instdata = NULL); explicit BaseMessageBoxEvent(const wxString& content = wxEmptyString, SynchronousActionState* instdata = NULL);
BaseMessageBoxEvent(const wxString &content, SynchronousActionState &instdata); BaseMessageBoxEvent(const wxString& content, SynchronousActionState& instdata);
BaseMessageBoxEvent(const BaseMessageBoxEvent &event); BaseMessageBoxEvent(const BaseMessageBoxEvent& event);
protected: protected:
virtual void InvokeEvent(); virtual void InvokeEvent();
virtual int _DoDialog() const; virtual int _DoDialog() const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -228,134 +228,134 @@ protected:
class MsgButtons class MsgButtons
{ {
protected: protected:
BITFIELD32() BITFIELD32()
bool bool
m_OK : 1, m_OK : 1,
m_Cancel : 1, m_Cancel : 1,
m_Yes : 1, m_Yes : 1,
m_No : 1, m_No : 1,
m_AllowToAll : 1, m_AllowToAll : 1,
m_Apply : 1, m_Apply : 1,
m_Abort : 1, m_Abort : 1,
m_Retry : 1, m_Retry : 1,
m_Ignore : 1, m_Ignore : 1,
m_Reset : 1, m_Reset : 1,
m_Close : 1; m_Close : 1;
BITFIELD_END BITFIELD_END
wxString m_CustomLabel; wxString m_CustomLabel;
wxString m_CustomLabelId; wxString m_CustomLabelId;
public: public:
MsgButtons() { bitset = 0; } MsgButtons() { bitset = 0; }
MsgButtons &OK() MsgButtons& OK()
{ {
m_OK = true; m_OK = true;
return *this; return *this;
} }
MsgButtons &Cancel() MsgButtons& Cancel()
{ {
m_Cancel = true; m_Cancel = true;
return *this; return *this;
} }
MsgButtons &Apply() MsgButtons& Apply()
{ {
m_Apply = true; m_Apply = true;
return *this; return *this;
} }
MsgButtons &Yes() MsgButtons& Yes()
{ {
m_Yes = true; m_Yes = true;
return *this; return *this;
} }
MsgButtons &No() MsgButtons& No()
{ {
m_No = true; m_No = true;
return *this; return *this;
} }
MsgButtons &ToAll() MsgButtons& ToAll()
{ {
m_AllowToAll = true; m_AllowToAll = true;
return *this; return *this;
} }
MsgButtons &Abort() MsgButtons& Abort()
{ {
m_Abort = true; m_Abort = true;
return *this; return *this;
} }
MsgButtons &Retry() MsgButtons& Retry()
{ {
m_Retry = true; m_Retry = true;
return *this; return *this;
} }
MsgButtons &Ignore() MsgButtons& Ignore()
{ {
m_Ignore = true; m_Ignore = true;
return *this; return *this;
} }
MsgButtons &Reset() MsgButtons& Reset()
{ {
m_Reset = true; m_Reset = true;
return *this; return *this;
} }
MsgButtons &Close() MsgButtons& Close()
{ {
m_Close = true; m_Close = true;
return *this; return *this;
} }
// label - native language label displayed to user // label - native language label displayed to user
// id - raw ASCII identifier used in the config file (do not translate, hence char*) // id - raw ASCII identifier used in the config file (do not translate, hence char*)
MsgButtons &Custom(const wxString &label, const char *id) MsgButtons& Custom(const wxString& label, const char* id)
{ {
m_CustomLabel = label; m_CustomLabel = label;
m_CustomLabelId = fromUTF8(id); m_CustomLabelId = fromUTF8(id);
return *this; return *this;
} }
MsgButtons &OKCancel() MsgButtons& OKCancel()
{ {
m_OK = m_Cancel = true; m_OK = m_Cancel = true;
return *this; return *this;
} }
MsgButtons &YesNo() MsgButtons& YesNo()
{ {
m_Yes = m_No = true; m_Yes = m_No = true;
return *this; return *this;
} }
bool HasOK() const { return m_OK; } bool HasOK() const { return m_OK; }
bool HasCancel() const { return m_Cancel; } bool HasCancel() const { return m_Cancel; }
bool HasApply() const { return m_Apply; } bool HasApply() const { return m_Apply; }
bool HasYes() const { return m_Yes; } bool HasYes() const { return m_Yes; }
bool HasNo() const { return m_No; } bool HasNo() const { return m_No; }
bool AllowsToAll() const { return m_AllowToAll; } bool AllowsToAll() const { return m_AllowToAll; }
bool HasAbort() const { return m_Abort; } bool HasAbort() const { return m_Abort; }
bool HasRetry() const { return m_Retry; } bool HasRetry() const { return m_Retry; }
bool HasIgnore() const { return m_Ignore; } bool HasIgnore() const { return m_Ignore; }
bool HasReset() const { return m_Reset; } bool HasReset() const { return m_Reset; }
bool HasClose() const { return m_Close; } bool HasClose() const { return m_Close; }
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); } bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
const wxString &GetCustomLabel() const { return m_CustomLabel; } const wxString& GetCustomLabel() const { return m_CustomLabel; }
const wxString &GetCustomLabelId() const { return m_CustomLabelId; } const wxString& GetCustomLabelId() const { return m_CustomLabelId; }
bool Allows(wxWindowID id) const; bool Allows(wxWindowID id) const;
void SetBestFocus(wxWindow *dialog) const; void SetBestFocus(wxWindow* dialog) const;
void SetBestFocus(wxWindow &dialog) const; void SetBestFocus(wxWindow& dialog) const;
bool operator==(const MsgButtons &right) const bool operator==(const MsgButtons& right) const
{ {
return OpEqu(bitset); return OpEqu(bitset);
} }
bool operator!=(const MsgButtons &right) const bool operator!=(const MsgButtons& right) const
{ {
return !OpEqu(bitset); return !OpEqu(bitset);
} }
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -378,24 +378,24 @@ public:
// //
class pxMessageBoxEvent : public BaseMessageBoxEvent class pxMessageBoxEvent : public BaseMessageBoxEvent
{ {
typedef BaseMessageBoxEvent _parent; typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
protected: protected:
wxString m_Title; wxString m_Title;
MsgButtons m_Buttons; MsgButtons m_Buttons;
public: public:
virtual ~pxMessageBoxEvent() = default; virtual ~pxMessageBoxEvent() = default;
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); } virtual pxMessageBoxEvent* Clone() const { return new pxMessageBoxEvent(*this); }
pxMessageBoxEvent() {} pxMessageBoxEvent() {}
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState &instdata); pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState& instdata);
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState *instdata = NULL); pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState* instdata = NULL);
pxMessageBoxEvent(const pxMessageBoxEvent &event) = default; pxMessageBoxEvent(const pxMessageBoxEvent& event) = default;
protected: protected:
int _DoDialog() const; int _DoDialog() const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -403,22 +403,22 @@ protected:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class pxAssertionEvent : public BaseMessageBoxEvent class pxAssertionEvent : public BaseMessageBoxEvent
{ {
typedef BaseMessageBoxEvent _parent; typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
protected: protected:
wxString m_Stacktrace; wxString m_Stacktrace;
public: public:
virtual ~pxAssertionEvent() = default; virtual ~pxAssertionEvent() = default;
virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); } virtual pxAssertionEvent* Clone() const { return new pxAssertionEvent(*this); }
pxAssertionEvent(const wxString &content = wxEmptyString, const wxString &trace = wxEmptyString, SynchronousActionState *instdata = NULL); pxAssertionEvent(const wxString& content = wxEmptyString, const wxString& trace = wxEmptyString, SynchronousActionState* instdata = NULL);
pxAssertionEvent(const wxString &content, const wxString &trace, SynchronousActionState &instdata); pxAssertionEvent(const wxString& content, const wxString& trace, SynchronousActionState& instdata);
pxAssertionEvent(const pxAssertionEvent &event) = default; pxAssertionEvent(const pxAssertionEvent& event) = default;
pxAssertionEvent &SetStacktrace(const wxString &trace); pxAssertionEvent& SetStacktrace(const wxString& trace);
protected: protected:
int _DoDialog() const; int _DoDialog() const;
}; };

View File

@ -40,12 +40,12 @@ extern const wxPoint wxDefaultPosition;
namespace Threading namespace Threading
{ {
class Mutex; class Mutex;
class Semaphore; class Semaphore;
class pxThread; class pxThread;
} } // namespace Threading
namespace Exception namespace Exception
{ {
class BaseException; class BaseException;
} }

View File

@ -24,232 +24,239 @@ template class SafeArray<RadioPanelObjects>;
// =========================================================================================== // ===========================================================================================
#define VerifyRealizedState() \ #define VerifyRealizedState() \
pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.") pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.")
void pxRadioPanel::Init(const RadioPanelItem *srcArray, int arrsize) void pxRadioPanel::Init(const RadioPanelItem* srcArray, int arrsize)
{ {
m_DefaultIdx = -1; m_DefaultIdx = -1;
m_IsRealized = false; m_IsRealized = false;
// FIXME: This probably needs to be platform-dependent, and/or based on font size. // FIXME: This probably needs to be platform-dependent, and/or based on font size.
m_Indentation = 23; m_Indentation = 23;
for (int i = 0; i < arrsize; ++i) for (int i = 0; i < arrsize; ++i)
Append(srcArray[i]); Append(srcArray[i]);
} }
pxRadioPanel &pxRadioPanel::Append(const RadioPanelItem &entry) pxRadioPanel& pxRadioPanel::Append(const RadioPanelItem& entry)
{ {
m_buttonStrings.push_back(entry); m_buttonStrings.push_back(entry);
return *this; return *this;
} }
void pxRadioPanel::Reset() void pxRadioPanel::Reset()
{ {
m_IsRealized = false; m_IsRealized = false;
const int numbuttons = m_buttonStrings.size(); const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0) if (numbuttons == 0)
return; return;
for (int i = 0; i < numbuttons; ++i) { for (int i = 0; i < numbuttons; ++i)
safe_delete(m_objects[i].LabelObj); {
safe_delete(m_objects[i].SubTextObj); safe_delete(m_objects[i].LabelObj);
} safe_delete(m_objects[i].SubTextObj);
m_buttonStrings.clear(); }
m_buttonStrings.clear();
} }
void pxRadioPanel::Realize() void pxRadioPanel::Realize()
{ {
const int numbuttons = m_buttonStrings.size(); const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0) if (numbuttons == 0)
return; return;
if (m_IsRealized) if (m_IsRealized)
return; return;
m_IsRealized = true; m_IsRealized = true;
m_objects.MakeRoomFor(numbuttons); m_objects.MakeRoomFor(numbuttons);
// Add all RadioButtons in one pass, and then go back and create all the subtext // Add all RadioButtons in one pass, and then go back and create all the subtext
// objects. This ensures the radio buttons have consecutive tab order IDs, which // objects. This ensures the radio buttons have consecutive tab order IDs, which
// is the "preferred" method when using grouping features of the native window // is the "preferred" method when using grouping features of the native window
// managers (GTK tends to not care either way, but Win32 definitely prefers a // managers (GTK tends to not care either way, but Win32 definitely prefers a
// linear tab order). // linear tab order).
// first object has the group flag set to ensure it's the start of a radio group. // first object has the group flag set to ensure it's the start of a radio group.
m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP); m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
for (int i = 1; i < numbuttons; ++i) for (int i = 1; i < numbuttons; ++i)
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label); m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
for (int i = 0; i < numbuttons; ++i) { for (int i = 0; i < numbuttons; ++i)
m_objects[i].SubTextObj = NULL; {
if (m_buttonStrings[i].SubText.IsEmpty()) m_objects[i].SubTextObj = NULL;
continue; if (m_buttonStrings[i].SubText.IsEmpty())
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT); continue;
} m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
}
pxAssert(GetSizer() != NULL); pxAssert(GetSizer() != NULL);
for (int i = 0; i < numbuttons; ++i) { for (int i = 0; i < numbuttons; ++i)
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand(); {
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
if (pxStaticText *subobj = m_objects[i].SubTextObj) { if (pxStaticText* subobj = m_objects[i].SubTextObj)
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand(); {
*this += 9 + m_padding.GetHeight(); *this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
} *this += 9 + m_padding.GetHeight();
if (!m_buttonStrings[i].ToolTip.IsEmpty()) }
_setToolTipImmediate(i, m_buttonStrings[i].ToolTip); if (!m_buttonStrings[i].ToolTip.IsEmpty())
} _setToolTipImmediate(i, m_buttonStrings[i].ToolTip);
}
_RealizeDefaultOption(); _RealizeDefaultOption();
} }
void pxRadioPanel::_setToolTipImmediate(int idx, const wxString &tip) void pxRadioPanel::_setToolTipImmediate(int idx, const wxString& tip)
{ {
if (wxRadioButton *woot = m_objects[idx].LabelObj) if (wxRadioButton* woot = m_objects[idx].LabelObj)
woot->SetToolTip(tip); woot->SetToolTip(tip);
if (pxStaticText *woot = m_objects[idx].SubTextObj) if (pxStaticText* woot = m_objects[idx].SubTextObj)
woot->SetToolTip(tip); woot->SetToolTip(tip);
} }
// The SetToolTip API provided by this function applies the tooltip to both the radio // The SetToolTip API provided by this function applies the tooltip to both the radio
// button and it's static subtext (if present), and performs word wrapping on platforms // button and it's static subtext (if present), and performs word wrapping on platforms
// that need it (eg mswindows). // that need it (eg mswindows).
pxRadioPanel &pxRadioPanel::SetToolTip(int idx, const wxString &tip) pxRadioPanel& pxRadioPanel::SetToolTip(int idx, const wxString& tip)
{ {
m_buttonStrings[idx].SetToolTip(tip); m_buttonStrings[idx].SetToolTip(tip);
if (m_IsRealized) if (m_IsRealized)
_setToolTipImmediate(idx, tip); _setToolTipImmediate(idx, tip);
return *this; return *this;
} }
pxRadioPanel &pxRadioPanel::SetSelection(int idx) pxRadioPanel& pxRadioPanel::SetSelection(int idx)
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return *this; return *this;
pxAssert(m_objects[idx].LabelObj != NULL); pxAssert(m_objects[idx].LabelObj != NULL);
m_objects[idx].LabelObj->SetValue(true); m_objects[idx].LabelObj->SetValue(true);
return *this; return *this;
} }
void pxRadioPanel::_RealizeDefaultOption() void pxRadioPanel::_RealizeDefaultOption()
{ {
if (m_IsRealized && m_DefaultIdx != -1) { if (m_IsRealized && m_DefaultIdx != -1)
wxFont def(GetFont()); {
def.SetWeight(wxFONTWEIGHT_BOLD); wxFont def(GetFont());
//def.SetStyle( wxFONTSTYLE_ITALIC ); def.SetWeight(wxFONTWEIGHT_BOLD);
m_objects[m_DefaultIdx].LabelObj->SetFont(def); //def.SetStyle( wxFONTSTYLE_ITALIC );
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40)); m_objects[m_DefaultIdx].LabelObj->SetFont(def);
} m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
}
} }
// Highlights (bold) the text of the default radio. // Highlights (bold) the text of the default radio.
// Not intended for restoring default value at later time. // Not intended for restoring default value at later time.
pxRadioPanel &pxRadioPanel::SetDefaultItem(int idx) pxRadioPanel& pxRadioPanel::SetDefaultItem(int idx)
{ {
if (idx == m_DefaultIdx) if (idx == m_DefaultIdx)
return *this; return *this;
if (m_IsRealized && m_DefaultIdx != -1) { if (m_IsRealized && m_DefaultIdx != -1)
wxFont def(GetFont()); {
m_objects[m_DefaultIdx].LabelObj->SetFont(def); wxFont def(GetFont());
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour()); m_objects[m_DefaultIdx].LabelObj->SetFont(def);
} m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
}
m_DefaultIdx = idx; m_DefaultIdx = idx;
_RealizeDefaultOption(); _RealizeDefaultOption();
return *this; return *this;
} }
pxRadioPanel &pxRadioPanel::EnableItem(int idx, bool enable) pxRadioPanel& pxRadioPanel::EnableItem(int idx, bool enable)
{ {
pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items."); pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items.");
if (m_objects[idx].LabelObj) if (m_objects[idx].LabelObj)
m_objects[idx].LabelObj->Enable(enable); m_objects[idx].LabelObj->Enable(enable);
if (m_objects[idx].SubTextObj) if (m_objects[idx].SubTextObj)
m_objects[idx].SubTextObj->Enable(enable); m_objects[idx].SubTextObj->Enable(enable);
return *this; return *this;
} }
const RadioPanelItem &pxRadioPanel::Item(int idx) const const RadioPanelItem& pxRadioPanel::Item(int idx) const
{ {
return m_buttonStrings[idx]; return m_buttonStrings[idx];
} }
RadioPanelItem &pxRadioPanel::Item(int idx) RadioPanelItem& pxRadioPanel::Item(int idx)
{ {
return m_buttonStrings[idx]; return m_buttonStrings[idx];
} }
int pxRadioPanel::GetSelection() const int pxRadioPanel::GetSelection() const
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return 0; return 0;
for (uint i = 0; i < m_buttonStrings.size(); ++i) { for (uint i = 0; i < m_buttonStrings.size(); ++i)
if (wxRadioButton *woot = m_objects[i].LabelObj) {
if (woot->GetValue()) if (wxRadioButton* woot = m_objects[i].LabelObj)
return i; if (woot->GetValue())
} return i;
}
// Technically radio buttons should never allow for a case where none are selected. // Technically radio buttons should never allow for a case where none are selected.
// However it *can* happen on some platforms if the program code doesn't explicitly // However it *can* happen on some platforms if the program code doesn't explicitly
// select one of the members of the group (which is, as far as I'm concerned, a // select one of the members of the group (which is, as far as I'm concerned, a
// programmer error!). so Assert here in such cases, and return 0 as the assumed // programmer error!). so Assert here in such cases, and return 0 as the assumed
// default, so that calling code has a "valid" return code in release builds. // default, so that calling code has a "valid" return code in release builds.
pxFailDev("No valid selection was found in this group!"); pxFailDev("No valid selection was found in this group!");
return 0; return 0;
} }
// Returns the wxWindowID for the currently selected radio button. // Returns the wxWindowID for the currently selected radio button.
wxWindowID pxRadioPanel::GetSelectionId() const wxWindowID pxRadioPanel::GetSelectionId() const
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return 0; return 0;
return m_objects[GetSelection()].LabelObj->GetId(); return m_objects[GetSelection()].LabelObj->GetId();
} }
bool pxRadioPanel::IsSelected(int idx) const bool pxRadioPanel::IsSelected(int idx) const
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return false; return false;
pxAssert(m_objects[idx].LabelObj != NULL); pxAssert(m_objects[idx].LabelObj != NULL);
return m_objects[idx].LabelObj->GetValue(); return m_objects[idx].LabelObj->GetValue();
} }
pxStaticText *pxRadioPanel::GetSubText(int idx) pxStaticText* pxRadioPanel::GetSubText(int idx)
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return NULL; return NULL;
return m_objects[idx].SubTextObj; return m_objects[idx].SubTextObj;
} }
const pxStaticText *pxRadioPanel::GetSubText(int idx) const const pxStaticText* pxRadioPanel::GetSubText(int idx) const
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return NULL; return NULL;
return m_objects[idx].SubTextObj; return m_objects[idx].SubTextObj;
} }
wxRadioButton *pxRadioPanel::GetButton(int idx) wxRadioButton* pxRadioPanel::GetButton(int idx)
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return NULL; return NULL;
return m_objects[idx].LabelObj; return m_objects[idx].LabelObj;
} }
const wxRadioButton *pxRadioPanel::GetButton(int idx) const const wxRadioButton* pxRadioPanel::GetButton(int idx) const
{ {
if (!VerifyRealizedState()) if (!VerifyRealizedState())
return NULL; return NULL;
return m_objects[idx].LabelObj; return m_objects[idx].LabelObj;
} }

View File

@ -25,45 +25,45 @@
struct RadioPanelItem struct RadioPanelItem
{ {
wxString Label; wxString Label;
wxString SubText; wxString SubText;
wxString ToolTip; wxString ToolTip;
int SomeInt; int SomeInt;
void *SomePtr; void* SomePtr;
RadioPanelItem(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString) RadioPanelItem(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
: Label(label) : Label(label)
, SubText(subtext) , SubText(subtext)
, ToolTip(tooltip) , ToolTip(tooltip)
{ {
SomeInt = 0; SomeInt = 0;
SomePtr = NULL; SomePtr = NULL;
} }
RadioPanelItem &SetToolTip(const wxString &tip) RadioPanelItem& SetToolTip(const wxString& tip)
{ {
ToolTip = tip; ToolTip = tip;
return *this; return *this;
} }
RadioPanelItem &SetSubText(const wxString &text) RadioPanelItem& SetSubText(const wxString& text)
{ {
SubText = text; SubText = text;
return *this; return *this;
} }
RadioPanelItem &SetInt(int intval) RadioPanelItem& SetInt(int intval)
{ {
SomeInt = intval; SomeInt = intval;
return *this; return *this;
} }
RadioPanelItem &SetPtr(void *ptrval) RadioPanelItem& SetPtr(void* ptrval)
{ {
SomePtr = ptrval; SomePtr = ptrval;
return *this; return *this;
} }
}; };
@ -71,8 +71,8 @@ struct RadioPanelItem
// wrapped and re-wrapped with multiple calls to OnResize(). // wrapped and re-wrapped with multiple calls to OnResize().
struct RadioPanelObjects struct RadioPanelObjects
{ {
wxRadioButton *LabelObj; wxRadioButton* LabelObj;
pxStaticText *SubTextObj; pxStaticText* SubTextObj;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -91,86 +91,86 @@ struct RadioPanelObjects
class pxRadioPanel : public wxPanelWithHelpers class pxRadioPanel : public wxPanelWithHelpers
{ {
protected: protected:
typedef std::vector<RadioPanelItem> ButtonArray; typedef std::vector<RadioPanelItem> ButtonArray;
typedef SafeArray<RadioPanelObjects> ButtonObjArray; typedef SafeArray<RadioPanelObjects> ButtonObjArray;
ButtonArray m_buttonStrings; ButtonArray m_buttonStrings;
ButtonObjArray m_objects; ButtonObjArray m_objects;
bool m_IsRealized; bool m_IsRealized;
wxSize m_padding; wxSize m_padding;
int m_Indentation; int m_Indentation;
int m_DefaultIdx; // index of the default option (gets specific color/font treatment) int m_DefaultIdx; // index of the default option (gets specific color/font treatment)
public: public:
template <int size> template <int size>
pxRadioPanel(wxWindow *parent, const RadioPanelItem (&src)[size]) pxRadioPanel(wxWindow* parent, const RadioPanelItem (&src)[size])
: wxPanelWithHelpers(parent, wxVERTICAL) : wxPanelWithHelpers(parent, wxVERTICAL)
{ {
Init(src, size); Init(src, size);
} }
pxRadioPanel(wxWindow *parent) pxRadioPanel(wxWindow* parent)
: wxPanelWithHelpers(parent, wxVERTICAL) : wxPanelWithHelpers(parent, wxVERTICAL)
{ {
Init(); Init();
} }
virtual ~pxRadioPanel() = default; virtual ~pxRadioPanel() = default;
void Reset(); void Reset();
void Realize(); void Realize();
pxStaticText *GetSubText(int idx); pxStaticText* GetSubText(int idx);
const pxStaticText *GetSubText(int idx) const; const pxStaticText* GetSubText(int idx) const;
pxRadioPanel &Append(const RadioPanelItem &entry); pxRadioPanel& Append(const RadioPanelItem& entry);
pxRadioPanel &SetToolTip(int idx, const wxString &tip); pxRadioPanel& SetToolTip(int idx, const wxString& tip);
pxRadioPanel &SetSelection(int idx); pxRadioPanel& SetSelection(int idx);
pxRadioPanel &SetDefaultItem(int idx); pxRadioPanel& SetDefaultItem(int idx);
pxRadioPanel &EnableItem(int idx, bool enable = true); pxRadioPanel& EnableItem(int idx, bool enable = true);
const RadioPanelItem &Item(int idx) const; const RadioPanelItem& Item(int idx) const;
RadioPanelItem &Item(int idx); RadioPanelItem& Item(int idx);
int GetSelection() const; int GetSelection() const;
wxWindowID GetSelectionId() const; wxWindowID GetSelectionId() const;
bool IsSelected(int idx) const; bool IsSelected(int idx) const;
const RadioPanelItem &SelectedItem() const { return Item(GetSelection()); } const RadioPanelItem& SelectedItem() const { return Item(GetSelection()); }
RadioPanelItem &SelectedItem() { return Item(GetSelection()); } RadioPanelItem& SelectedItem() { return Item(GetSelection()); }
wxRadioButton *GetButton(int idx); wxRadioButton* GetButton(int idx);
const wxRadioButton *GetButton(int idx) const; const wxRadioButton* GetButton(int idx) const;
int GetPaddingVert() const { return m_padding.GetHeight(); } int GetPaddingVert() const { return m_padding.GetHeight(); }
int GetIndentation() const { return m_Indentation; } int GetIndentation() const { return m_Indentation; }
pxRadioPanel &SetPaddingHoriz(int newpad) pxRadioPanel& SetPaddingHoriz(int newpad)
{ {
m_padding.SetHeight(newpad); m_padding.SetHeight(newpad);
return *this; return *this;
} }
pxRadioPanel &SetIndentation(int newdent) pxRadioPanel& SetIndentation(int newdent)
{ {
m_Indentation = newdent; m_Indentation = newdent;
return *this; return *this;
} }
bool HasSubText(int idx) const bool HasSubText(int idx) const
{ {
return !m_buttonStrings[idx].SubText.IsEmpty(); return !m_buttonStrings[idx].SubText.IsEmpty();
} }
pxRadioPanel &Append(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString) pxRadioPanel& Append(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
{ {
return Append(RadioPanelItem(label, subtext, tooltip)); return Append(RadioPanelItem(label, subtext, tooltip));
} }
protected: protected:
void Init(const RadioPanelItem *srcArray = NULL, int arrsize = 0); void Init(const RadioPanelItem* srcArray = NULL, int arrsize = 0);
void _setToolTipImmediate(int idx, const wxString &tip); void _setToolTipImmediate(int idx, const wxString& tip);
void _RealizeDefaultOption(); void _RealizeDefaultOption();
}; };

View File

@ -20,33 +20,33 @@
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxStaticText (implementations) // pxStaticText (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxStaticText::pxStaticText(wxWindow *parent) pxStaticText::pxStaticText(wxWindow* parent)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER) : _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
{ {
m_align = wxALIGN_CENTRE_HORIZONTAL; m_align = wxALIGN_CENTRE_HORIZONTAL;
m_autowrap = true; m_autowrap = true;
m_wrappedWidth = -1; m_wrappedWidth = -1;
m_heightInLines = 1; m_heightInLines = 1;
SetPaddingDefaults(); SetPaddingDefaults();
} }
pxStaticText::pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align) pxStaticText::pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER) : _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
{ {
m_heightInLines = 1; m_heightInLines = 1;
m_align = align; m_align = align;
SetPaddingDefaults(); SetPaddingDefaults();
Init(label); Init(label);
} }
void pxStaticText::Init(const wxString &label) void pxStaticText::Init(const wxString& label)
{ {
m_autowrap = true; m_autowrap = true;
m_wrappedWidth = -1; m_wrappedWidth = -1;
m_label = label; m_label = label;
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this); Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
} }
// we need to refresh the window after changing its size as the standard // we need to refresh the window after changing its size as the standard
@ -54,328 +54,338 @@ void pxStaticText::Init(const wxString &label)
// the control is expanded to fit -- ie the control's size changes but the position does not) // the control is expanded to fit -- ie the control's size changes but the position does not)
void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags) void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags)
{ {
_parent::DoSetSize(x, y, w, h, sizeFlags); _parent::DoSetSize(x, y, w, h, sizeFlags);
Refresh(); Refresh();
} }
void pxStaticText::SetPaddingDefaults() void pxStaticText::SetPaddingDefaults()
{ {
m_paddingPix_horiz = 7; m_paddingPix_horiz = 7;
m_paddingPix_vert = 1; m_paddingPix_vert = 1;
m_paddingPct_horiz = 0.0f; m_paddingPct_horiz = 0.0f;
m_paddingPct_vert = 0.0f; m_paddingPct_vert = 0.0f;
} }
pxStaticText &pxStaticText::SetMinWidth(int width) pxStaticText& pxStaticText::SetMinWidth(int width)
{ {
SetMinSize(wxSize(width, GetMinHeight())); SetMinSize(wxSize(width, GetMinHeight()));
return *this; return *this;
} }
pxStaticText &pxStaticText::SetMinHeight(int height) pxStaticText& pxStaticText::SetMinHeight(int height)
{ {
SetMinSize(wxSize(GetMinWidth(), height)); SetMinSize(wxSize(GetMinWidth(), height));
return *this; return *this;
} }
pxStaticText &pxStaticText::SetHeight(int lines) pxStaticText& pxStaticText::SetHeight(int lines)
{ {
if (!pxAssert(lines > 0)) if (!pxAssert(lines > 0))
lines = 2; lines = 2;
m_heightInLines = lines; m_heightInLines = lines;
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2); const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
SetMinSize(wxSize(GetMinWidth(), newHeight)); SetMinSize(wxSize(GetMinWidth(), newHeight));
return *this; return *this;
} }
pxStaticText &pxStaticText::Align(wxAlignment align) pxStaticText& pxStaticText::Align(wxAlignment align)
{ {
m_align = align; m_align = align;
return *this; return *this;
} }
pxStaticText &pxStaticText::Bold() pxStaticText& pxStaticText::Bold()
{ {
wxFont bold(GetFont()); wxFont bold(GetFont());
bold.SetWeight(wxFONTWEIGHT_BOLD); bold.SetWeight(wxFONTWEIGHT_BOLD);
SetFont(bold); SetFont(bold);
return *this; return *this;
} }
pxStaticText &pxStaticText::PaddingPixH(int pixels) pxStaticText& pxStaticText::PaddingPixH(int pixels)
{ {
m_paddingPix_horiz = pixels; m_paddingPix_horiz = pixels;
UpdateWrapping(false); UpdateWrapping(false);
Refresh(); Refresh();
return *this; return *this;
} }
pxStaticText &pxStaticText::PaddingPixV(int pixels) pxStaticText& pxStaticText::PaddingPixV(int pixels)
{ {
m_paddingPix_vert = pixels; m_paddingPix_vert = pixels;
Refresh(); Refresh();
return *this; return *this;
} }
pxStaticText &pxStaticText::PaddingPctH(float pct) pxStaticText& pxStaticText::PaddingPctH(float pct)
{ {
pxAssert(pct < 0.5); pxAssert(pct < 0.5);
m_paddingPct_horiz = pct; m_paddingPct_horiz = pct;
UpdateWrapping(false); UpdateWrapping(false);
Refresh(); Refresh();
return *this; return *this;
} }
pxStaticText &pxStaticText::PaddingPctV(float pct) pxStaticText& pxStaticText::PaddingPctV(float pct)
{ {
pxAssert(pct < 0.5); pxAssert(pct < 0.5);
m_paddingPct_vert = pct; m_paddingPct_vert = pct;
Refresh(); Refresh();
return *this; return *this;
} }
pxStaticText &pxStaticText::Unwrapped() pxStaticText& pxStaticText::Unwrapped()
{ {
m_autowrap = false; m_autowrap = false;
UpdateWrapping(false); UpdateWrapping(false);
return *this; return *this;
} }
int pxStaticText::calcPaddingWidth(int newWidth) const int pxStaticText::calcPaddingWidth(int newWidth) const
{ {
return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2); return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2);
} }
int pxStaticText::calcPaddingHeight(int newHeight) const int pxStaticText::calcPaddingHeight(int newHeight) const
{ {
return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2); return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2);
} }
wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const wxSize pxStaticText::GetBestWrappedSize(const wxClientDC& dc) const
{ {
pxAssert(m_autowrap); pxAssert(m_autowrap);
// Find an ideal(-ish) width, based on a search of all parent controls and their // Find an ideal(-ish) width, based on a search of all parent controls and their
// valid Minimum sizes. // valid Minimum sizes.
int idealWidth = wxDefaultCoord; int idealWidth = wxDefaultCoord;
int parentalAdjust = 0; int parentalAdjust = 0;
double parentalFactor = 1.0; double parentalFactor = 1.0;
const wxWindow *millrun = this; const wxWindow* millrun = this;
while (millrun) { while (millrun)
// IMPORTANT : wxWizard changes its min size and then expects everything else {
// to play nice and NOT resize according to the new min size. (wtf stupid) // IMPORTANT : wxWizard changes its min size and then expects everything else
// Anyway, this fixes it -- ignore min size specifier on wxWizard! // to play nice and NOT resize according to the new min size. (wtf stupid)
if (wxIsKindOf(millrun, wxWizard)) // Anyway, this fixes it -- ignore min size specifier on wxWizard!
break; if (wxIsKindOf(millrun, wxWizard))
break;
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor); int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
if (min > 0 && ((idealWidth < 0) || (min < idealWidth))) { if (min > 0 && ((idealWidth < 0) || (min < idealWidth)))
idealWidth = min; {
} idealWidth = min;
}
parentalAdjust += pxSizerFlags::StdPadding * 2; parentalAdjust += pxSizerFlags::StdPadding * 2;
millrun = millrun->GetParent(); millrun = millrun->GetParent();
} }
if (idealWidth <= 0) { if (idealWidth <= 0)
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on {
// the size of the user's display area. // FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
// the size of the user's display area.
idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2); idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2);
} }
return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult()); return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult());
} }
pxStaticText &pxStaticText::WrapAt(int width) pxStaticText& pxStaticText::WrapAt(int width)
{ {
m_autowrap = false; m_autowrap = false;
if ((width <= 1) || (width == m_wrappedWidth)) if ((width <= 1) || (width == m_wrappedWidth))
return *this; return *this;
wxString wrappedLabel; wxString wrappedLabel;
m_wrappedWidth = width; m_wrappedWidth = width;
if (width > 1) if (width > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult(); wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
if (m_wrappedLabel != wrappedLabel) { if (m_wrappedLabel != wrappedLabel)
m_wrappedLabel = wrappedLabel; {
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel); m_wrappedLabel = wrappedLabel;
SetMinSize(wxSize( wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
area.GetWidth() + calcPaddingWidth(area.GetWidth()), SetMinSize(wxSize(
area.GetHeight() + calcPaddingHeight(area.GetHeight()))); area.GetWidth() + calcPaddingWidth(area.GetWidth()),
} area.GetHeight() + calcPaddingHeight(area.GetHeight())));
return *this; }
return *this;
} }
bool pxStaticText::_updateWrapping(bool textChanged) bool pxStaticText::_updateWrapping(bool textChanged)
{ {
if (!m_autowrap) { if (!m_autowrap)
//m_wrappedLabel = wxEmptyString; {
//m_wrappedWidth = -1; //m_wrappedLabel = wxEmptyString;
return false; //m_wrappedWidth = -1;
} return false;
}
wxString wrappedLabel; wxString wrappedLabel;
int newWidth = GetSize().GetWidth(); int newWidth = GetSize().GetWidth();
if (!textChanged && (newWidth == m_wrappedWidth)) if (!textChanged && (newWidth == m_wrappedWidth))
return false; return false;
// Note: during various stages of sizer-calc, width can be 1, 0, or -1. // Note: during various stages of sizer-calc, width can be 1, 0, or -1.
// We ignore wrapping in these cases. (the PaintEvent also checks the wrapping // We ignore wrapping in these cases. (the PaintEvent also checks the wrapping
// and updates it if needed, in case the control's size isn't figured out prior // and updates it if needed, in case the control's size isn't figured out prior
// to being painted). // to being painted).
m_wrappedWidth = newWidth; m_wrappedWidth = newWidth;
if (m_wrappedWidth > 1) if (m_wrappedWidth > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult(); wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
if (m_wrappedLabel == wrappedLabel) if (m_wrappedLabel == wrappedLabel)
return false; return false;
m_wrappedLabel = wrappedLabel; m_wrappedLabel = wrappedLabel;
return true; return true;
} }
void pxStaticText::UpdateWrapping(bool textChanged) void pxStaticText::UpdateWrapping(bool textChanged)
{ {
if (_updateWrapping(textChanged)) if (_updateWrapping(textChanged))
Refresh(); Refresh();
} }
void pxStaticText::SetLabel(const wxString &label) void pxStaticText::SetLabel(const wxString& label)
{ {
const bool labelChanged(label != m_label); const bool labelChanged(label != m_label);
if (labelChanged) { if (labelChanged)
m_label = label; {
Refresh(); m_label = label;
} Refresh();
}
// Always update wrapping, in case window width or something else also changed. // Always update wrapping, in case window width or something else also changed.
UpdateWrapping(labelChanged); UpdateWrapping(labelChanged);
InvalidateBestSize(); InvalidateBestSize();
} }
wxFont pxStaticText::GetFontOk() const wxFont pxStaticText::GetFontOk() const
{ {
wxFont font(GetFont()); wxFont font(GetFont());
if (!font.Ok()) if (!font.Ok())
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
return font; return font;
} }
bool pxStaticText::Enable(bool enabled) bool pxStaticText::Enable(bool enabled)
{ {
if (_parent::Enable(enabled)) { if (_parent::Enable(enabled))
Refresh(); {
return true; Refresh();
} return true;
return false; }
return false;
} }
void pxStaticText::paintEvent(wxPaintEvent &evt) void pxStaticText::paintEvent(wxPaintEvent& evt)
{ {
wxPaintDC dc(this); wxPaintDC dc(this);
const int dcWidth = dc.GetSize().GetWidth(); const int dcWidth = dc.GetSize().GetWidth();
const int dcHeight = dc.GetSize().GetHeight(); const int dcHeight = dc.GetSize().GetHeight();
if (dcWidth < 1) if (dcWidth < 1)
return; return;
dc.SetFont(GetFontOk()); dc.SetFont(GetFontOk());
if (IsEnabled()) if (IsEnabled())
dc.SetTextForeground(GetForegroundColour()); dc.SetTextForeground(GetForegroundColour());
else else
dc.SetTextForeground(*wxLIGHT_GREY); dc.SetTextForeground(*wxLIGHT_GREY);
pxWindowTextWriter writer(dc); pxWindowTextWriter writer(dc);
writer.Align(m_align); writer.Align(m_align);
const wxString &label(m_autowrap ? m_wrappedLabel : m_label); const wxString& label(m_autowrap ? m_wrappedLabel : m_label);
if (m_autowrap) if (m_autowrap)
_updateWrapping(false); _updateWrapping(false);
int tWidth, tHeight; int tWidth, tHeight;
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight); dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
writer.Align(m_align); writer.Align(m_align);
if (m_align & wxALIGN_CENTER_VERTICAL) if (m_align & wxALIGN_CENTER_VERTICAL)
writer.SetY((dcHeight - tHeight) / 2); writer.SetY((dcHeight - tHeight) / 2);
else else
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert); writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
writer.WriteLn(label); // without formatting please. writer.WriteLn(label); // without formatting please.
//dc.SetBrush( *wxTRANSPARENT_BRUSH ); //dc.SetBrush( *wxTRANSPARENT_BRUSH );
//dc.DrawRectangle(wxPoint(), dc.GetSize()); //dc.DrawRectangle(wxPoint(), dc.GetSize());
} }
// Overloaded form wxPanel and friends. // Overloaded form wxPanel and friends.
wxSize pxStaticText::DoGetBestSize() const wxSize pxStaticText::DoGetBestSize() const
{ {
wxClientDC dc(const_cast<pxStaticText *>(this)); wxClientDC dc(const_cast<pxStaticText*>(this));
dc.SetFont(GetFontOk()); dc.SetFont(GetFontOk());
wxSize best; wxSize best;
if (m_autowrap) { if (m_autowrap)
best = GetBestWrappedSize(dc); {
//best.x = wxDefaultCoord; best = GetBestWrappedSize(dc);
} else { //best.x = wxDefaultCoord;
// No autowrapping, so we can force a specific size here! }
best = dc.GetMultiLineTextExtent(GetLabel()); else
best.x += calcPaddingWidth(best.x); {
} // No autowrapping, so we can force a specific size here!
best = dc.GetMultiLineTextExtent(GetLabel());
best.x += calcPaddingWidth(best.x);
}
best.y += calcPaddingHeight(best.y); best.y += calcPaddingHeight(best.y);
CacheBestSize(best); CacheBestSize(best);
return best; return best;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxStaticHeading (implementations) // pxStaticHeading (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxStaticHeading::pxStaticHeading(wxWindow *parent, const wxString &label) pxStaticHeading::pxStaticHeading(wxWindow* parent, const wxString& label)
: _parent(parent) : _parent(parent)
{ {
m_align = wxALIGN_CENTER; m_align = wxALIGN_CENTER;
SetPaddingDefaults(); SetPaddingDefaults();
Init(label); Init(label);
} }
void pxStaticHeading::SetPaddingDefaults() void pxStaticHeading::SetPaddingDefaults()
{ {
m_paddingPix_horiz = 4; m_paddingPix_horiz = 4;
m_paddingPix_vert = 1; m_paddingPix_vert = 1;
m_paddingPct_horiz = 0.08f; m_paddingPct_horiz = 0.08f;
m_paddingPct_vert = 0.0f; m_paddingPct_vert = 0.0f;
} }
void operator+=(wxSizer &target, pxStaticText *src) void operator+=(wxSizer& target, pxStaticText* src)
{ {
if (src) if (src)
target.Add(src, pxExpand); target.Add(src, pxExpand);
} }
void operator+=(wxSizer &target, pxStaticText &src) void operator+=(wxSizer& target, pxStaticText& src)
{ {
target.Add(&src, pxExpand); target.Add(&src, pxExpand);
} }
void operator+=(wxSizer *target, pxStaticText &src) void operator+=(wxSizer* target, pxStaticText& src)
{ {
target->Add(&src, pxExpand); target->Add(&src, pxExpand);
} }

View File

@ -34,92 +34,92 @@
// //
class pxStaticText : public wxControl class pxStaticText : public wxControl
{ {
typedef wxControl _parent; typedef wxControl _parent;
protected: protected:
wxString m_label; wxString m_label;
wxString m_wrappedLabel; wxString m_wrappedLabel;
wxAlignment m_align; wxAlignment m_align;
bool m_autowrap; bool m_autowrap;
int m_wrappedWidth; int m_wrappedWidth;
int m_heightInLines; int m_heightInLines;
int m_paddingPix_horiz; int m_paddingPix_horiz;
int m_paddingPix_vert; int m_paddingPix_vert;
float m_paddingPct_horiz; float m_paddingPct_horiz;
float m_paddingPct_vert; float m_paddingPct_vert;
protected: protected:
explicit pxStaticText(wxWindow *parent = NULL); explicit pxStaticText(wxWindow* parent = NULL);
// wxWindow overloads! // wxWindow overloads!
bool AcceptsFocus() const { return false; } bool AcceptsFocus() const { return false; }
bool HasTransparentBackground() { return true; } bool HasTransparentBackground() { return true; }
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO); void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
public: public:
pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL); pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
pxStaticText(wxWindow *parent, int heightInLines, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL); pxStaticText(wxWindow* parent, int heightInLines, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
virtual ~pxStaticText() = default; virtual ~pxStaticText() = default;
wxFont GetFontOk() const; wxFont GetFontOk() const;
bool Enable(bool enabled = true); bool Enable(bool enabled = true);
virtual void SetLabel(const wxString &label); virtual void SetLabel(const wxString& label);
virtual wxString GetLabel() const { return m_label; } virtual wxString GetLabel() const { return m_label; }
pxStaticText &SetMinWidth(int width); pxStaticText& SetMinWidth(int width);
pxStaticText &SetMinHeight(int height); pxStaticText& SetMinHeight(int height);
pxStaticText &SetHeight(int lines); pxStaticText& SetHeight(int lines);
pxStaticText &Align(wxAlignment align); pxStaticText& Align(wxAlignment align);
pxStaticText &Bold(); pxStaticText& Bold();
pxStaticText &WrapAt(int width); pxStaticText& WrapAt(int width);
pxStaticText &Unwrapped(); pxStaticText& Unwrapped();
pxStaticText &PaddingPixH(int pixels); pxStaticText& PaddingPixH(int pixels);
pxStaticText &PaddingPixV(int pixels); pxStaticText& PaddingPixV(int pixels);
pxStaticText &PaddingPctH(float pct); pxStaticText& PaddingPctH(float pct);
pxStaticText &PaddingPctV(float pct); pxStaticText& PaddingPctV(float pct);
//pxStaticText& DoBestGuessHeight(); //pxStaticText& DoBestGuessHeight();
protected: protected:
void SetPaddingDefaults(); void SetPaddingDefaults();
void Init(const wxString &label); void Init(const wxString& label);
wxSize GetBestWrappedSize(const wxClientDC &dc) const; wxSize GetBestWrappedSize(const wxClientDC& dc) const;
wxSize DoGetBestSize() const; wxSize DoGetBestSize() const;
int calcPaddingWidth(int newWidth) const; int calcPaddingWidth(int newWidth) const;
int calcPaddingHeight(int newHeight) const; int calcPaddingHeight(int newHeight) const;
void paintEvent(wxPaintEvent &evt); void paintEvent(wxPaintEvent& evt);
void UpdateWrapping(bool textChanged); void UpdateWrapping(bool textChanged);
bool _updateWrapping(bool textChanged); bool _updateWrapping(bool textChanged);
}; };
class pxStaticHeading : public pxStaticText class pxStaticHeading : public pxStaticText
{ {
typedef pxStaticText _parent; typedef pxStaticText _parent;
public: public:
pxStaticHeading(wxWindow *parent = NULL, const wxString &label = wxEmptyString); pxStaticHeading(wxWindow* parent = NULL, const wxString& label = wxEmptyString);
pxStaticHeading(wxWindow *parent, int heightInLines, const wxString &label = wxEmptyString); pxStaticHeading(wxWindow* parent, int heightInLines, const wxString& label = wxEmptyString);
virtual ~pxStaticHeading() = default; virtual ~pxStaticHeading() = default;
protected: protected:
void SetPaddingDefaults(); void SetPaddingDefaults();
}; };
extern void operator+=(wxSizer &target, pxStaticText &src); extern void operator+=(wxSizer& target, pxStaticText& src);
template <> template <>
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxStaticText> &src) inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxStaticText>& src)
{ {
target.Add(src.window, src.flags); target.Add(src.window, src.flags);
} }

View File

@ -23,22 +23,22 @@
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxStreamBase (implementations) // pxStreamBase (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxStreamBase::pxStreamBase(const wxString &filename) pxStreamBase::pxStreamBase(const wxString& filename)
: m_filename(filename) : m_filename(filename)
{ {
} }
bool pxStreamBase::IsOk() const bool pxStreamBase::IsOk() const
{ {
wxStreamBase *woot = GetWxStreamBase(); wxStreamBase* woot = GetWxStreamBase();
return woot && woot->IsOk(); return woot && woot->IsOk();
} }
wxFileOffset pxStreamBase::Length() const wxFileOffset pxStreamBase::Length() const
{ {
if (!GetWxStreamBase()) if (!GetWxStreamBase())
return 0; return 0;
return GetWxStreamBase()->GetLength(); return GetWxStreamBase()->GetLength();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -47,115 +47,117 @@ wxFileOffset pxStreamBase::Length() const
// Interface for reading data from a gzip stream. // Interface for reading data from a gzip stream.
// //
pxInputStream::pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input) pxInputStream::pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input)
: pxStreamBase(filename) : pxStreamBase(filename)
, m_stream_in(std::move(input)) , m_stream_in(std::move(input))
{ {
} }
pxInputStream::pxInputStream(const wxString &filename, wxInputStream *input) pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input)
: pxStreamBase(filename) : pxStreamBase(filename)
, m_stream_in(input) , m_stream_in(input)
{ {
} }
wxStreamBase *pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); } wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); }
wxFileOffset pxInputStream::Tell() const wxFileOffset pxInputStream::Tell() const
{ {
return m_stream_in->TellI(); return m_stream_in->TellI();
} }
wxFileOffset pxInputStream::Seek(wxFileOffset ofs, wxSeekMode mode) wxFileOffset pxInputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
{ {
return m_stream_in->SeekI(ofs, mode); return m_stream_in->SeekI(ofs, mode);
} }
void pxInputStream::SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream) void pxInputStream::SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream)
{ {
m_filename = filename; m_filename = filename;
m_stream_in = std::move(stream); m_stream_in = std::move(stream);
} }
void pxInputStream::SetStream(const wxString &filename, wxInputStream *stream) void pxInputStream::SetStream(const wxString& filename, wxInputStream* stream)
{ {
m_filename = filename; m_filename = filename;
m_stream_in = std::unique_ptr<wxInputStream>(stream); m_stream_in = std::unique_ptr<wxInputStream>(stream);
} }
void pxInputStream::Read(void *dest, size_t size) void pxInputStream::Read(void* dest, size_t size)
{ {
m_stream_in->Read(dest, size); m_stream_in->Read(dest, size);
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR) { if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
int err = errno; {
if (!err) int err = errno;
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)"); if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
ScopedExcept ex(Exception::FromErrno(m_filename, err)); ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg()); ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
ex->Rethrow(); ex->Rethrow();
} }
// IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we // IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we
// must always use the explicit check against the number of bytes read to determine // must always use the explicit check against the number of bytes read to determine
// end-of-stream conditions. // end-of-stream conditions.
if ((size_t)m_stream_in->LastRead() < size) if ((size_t)m_stream_in->LastRead() < size)
throw Exception::EndOfStream(m_filename); throw Exception::EndOfStream(m_filename);
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxOutputStream // pxOutputStream
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxOutputStream::pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output) pxOutputStream::pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output)
: pxStreamBase(filename) : pxStreamBase(filename)
, m_stream_out(std::move(output)) , m_stream_out(std::move(output))
{ {
} }
pxOutputStream::pxOutputStream(const wxString &filename, wxOutputStream *output) pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output)
: pxStreamBase(filename) : pxStreamBase(filename)
, m_stream_out(output) , m_stream_out(output)
{ {
} }
wxStreamBase *pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); } wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); }
wxFileOffset pxOutputStream::Tell() const wxFileOffset pxOutputStream::Tell() const
{ {
return m_stream_out->TellO(); return m_stream_out->TellO();
} }
wxFileOffset pxOutputStream::Seek(wxFileOffset ofs, wxSeekMode mode) wxFileOffset pxOutputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
{ {
return m_stream_out->SeekO(ofs, mode); return m_stream_out->SeekO(ofs, mode);
} }
void pxOutputStream::SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream) void pxOutputStream::SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream)
{ {
m_filename = filename; m_filename = filename;
m_stream_out = std::move(stream); m_stream_out = std::move(stream);
} }
void pxOutputStream::SetStream(const wxString &filename, wxOutputStream *stream) void pxOutputStream::SetStream(const wxString& filename, wxOutputStream* stream)
{ {
m_filename = filename; m_filename = filename;
m_stream_out = std::unique_ptr<wxOutputStream>(stream); m_stream_out = std::unique_ptr<wxOutputStream>(stream);
} }
void pxOutputStream::Write(const void *src, size_t size) void pxOutputStream::Write(const void* src, size_t size)
{ {
m_stream_out->Write(src, size); m_stream_out->Write(src, size);
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR) { if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
int err = errno; {
if (!err) int err = errno;
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream."); if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
ScopedExcept ex(Exception::FromErrno(m_filename, err)); ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg()); ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
ex->Rethrow(); ex->Rethrow();
} }
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -163,89 +165,93 @@ void pxOutputStream::Write(const void *src, size_t size)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap. // Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap.
bool pxReadLine(wxInputStream &input, std::string &dest) bool pxReadLine(wxInputStream& input, std::string& dest)
{ {
dest.clear(); dest.clear();
bool isUTF8 = false; bool isUTF8 = false;
while (true) { while (true)
char c; {
input.Read(&c, sizeof(c)); char c;
if (c == 0) input.Read(&c, sizeof(c));
break; if (c == 0)
if (input.Eof()) break;
break; if (input.Eof())
if (c == '\n') break;
break; // eat on UNIX if (c == '\n')
if (c == '\r') { break; // eat on UNIX
input.Read(&c, sizeof(c)); if (c == '\r')
if (c == 0) {
break; input.Read(&c, sizeof(c));
if (input.Eof()) if (c == 0)
break; break;
if (c == '\n') if (input.Eof())
break; break;
if (c == '\n')
break;
input.Ungetch(c); input.Ungetch(c);
break; break;
} }
dest += c; dest += c;
if (c & 0x80) if (c & 0x80)
isUTF8 = true; isUTF8 = true;
} }
return isUTF8; return isUTF8;
} }
void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed) void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed)
{ {
dest.clear(); dest.clear();
if (pxReadLine(input, intermed)) if (pxReadLine(input, intermed))
dest = fromUTF8(intermed.c_str()); dest = fromUTF8(intermed.c_str());
else { else
// Optimized ToAscii conversion. {
// wx3.0 : NOT COMPATIBLE!! (on linux anyway) // Optimized ToAscii conversion.
const char *ascii = intermed.c_str(); // wx3.0 : NOT COMPATIBLE!! (on linux anyway)
while (*ascii != 0) const char* ascii = intermed.c_str();
dest += (wchar_t)(unsigned char)*ascii++; while (*ascii != 0)
} dest += (wchar_t)(unsigned char)*ascii++;
}
} }
void pxReadLine(wxInputStream &input, wxString &dest) void pxReadLine(wxInputStream& input, wxString& dest)
{ {
std::string line; std::string line;
pxReadLine(input, dest, line); pxReadLine(input, dest, line);
} }
wxString pxReadLine(wxInputStream &input) wxString pxReadLine(wxInputStream& input)
{ {
wxString result; wxString result;
pxReadLine(input, result); pxReadLine(input, result);
return result; return result;
} }
void pxWriteLine(wxOutputStream &output) void pxWriteLine(wxOutputStream& output)
{ {
output.Write("\n", 1); output.Write("\n", 1);
} }
void pxWriteLine(wxOutputStream &output, const wxString &text) void pxWriteLine(wxOutputStream& output, const wxString& text)
{ {
if (!text.IsEmpty()) { if (!text.IsEmpty())
pxToUTF8 utf8(text); {
output.Write(utf8, utf8.Length()); pxToUTF8 utf8(text);
} output.Write(utf8, utf8.Length());
pxWriteLine(output); }
pxWriteLine(output);
} }
void pxWriteMultiline(wxOutputStream &output, const wxString &src) void pxWriteMultiline(wxOutputStream& output, const wxString& src)
{ {
if (src.IsEmpty()) if (src.IsEmpty())
return; return;
wxString result(src); wxString result(src);
result.Replace(L"\r\n", L"\n"); result.Replace(L"\r\n", L"\n");
result.Replace(L"\r", L"\n"); result.Replace(L"\r", L"\n");
pxToUTF8 utf8(result); pxToUTF8 utf8(result);
output.Write(utf8, utf8.Length()); output.Write(utf8, utf8.Length());
} }

View File

@ -25,28 +25,28 @@
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class pxStreamBase class pxStreamBase
{ {
DeclareNoncopyableObject(pxStreamBase); DeclareNoncopyableObject(pxStreamBase);
protected: protected:
// Filename of the stream, provided by the creator/caller. This is typically used *only* // Filename of the stream, provided by the creator/caller. This is typically used *only*
// for generating comprehensive error messages when an error occurs (the stream name is // for generating comprehensive error messages when an error occurs (the stream name is
// passed to the exception handlers). // passed to the exception handlers).
wxString m_filename; wxString m_filename;
public: public:
pxStreamBase(const wxString &filename); pxStreamBase(const wxString& filename);
virtual ~pxStreamBase() = default; virtual ~pxStreamBase() = default;
// Implementing classes should return the base wxStream object (usually either a wxInputStream // Implementing classes should return the base wxStream object (usually either a wxInputStream
// or wxOputStream derivative). // or wxOputStream derivative).
virtual wxStreamBase *GetWxStreamBase() const = 0; virtual wxStreamBase* GetWxStreamBase() const = 0;
virtual void Close() = 0; virtual void Close() = 0;
virtual wxFileOffset Tell() const = 0; virtual wxFileOffset Tell() const = 0;
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0; virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
virtual wxFileOffset Length() const; virtual wxFileOffset Length() const;
bool IsOk() const; bool IsOk() const;
wxString GetStreamName() const { return m_filename; } wxString GetStreamName() const { return m_filename; }
}; };
@ -55,33 +55,33 @@ public:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class pxOutputStream : public pxStreamBase class pxOutputStream : public pxStreamBase
{ {
DeclareNoncopyableObject(pxOutputStream); DeclareNoncopyableObject(pxOutputStream);
protected: protected:
std::unique_ptr<wxOutputStream> m_stream_out; std::unique_ptr<wxOutputStream> m_stream_out;
public: public:
pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output); pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output);
pxOutputStream(const wxString &filename, wxOutputStream *output); pxOutputStream(const wxString& filename, wxOutputStream* output);
virtual ~pxOutputStream() = default; virtual ~pxOutputStream() = default;
virtual void Write(const void *data, size_t size); virtual void Write(const void* data, size_t size);
void SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream); void SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream);
void SetStream(const wxString &filename, wxOutputStream *stream); void SetStream(const wxString& filename, wxOutputStream* stream);
void Close() { m_stream_out = nullptr; } void Close() { m_stream_out = nullptr; }
virtual wxStreamBase *GetWxStreamBase() const; virtual wxStreamBase* GetWxStreamBase() const;
template <typename T> template <typename T>
void Write(const T &data) void Write(const T& data)
{ {
Write(&data, sizeof(data)); Write(&data, sizeof(data));
} }
wxFileOffset Tell() const; wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart); wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -89,31 +89,31 @@ public:
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class pxInputStream : public pxStreamBase class pxInputStream : public pxStreamBase
{ {
DeclareNoncopyableObject(pxInputStream); DeclareNoncopyableObject(pxInputStream);
protected: protected:
std::unique_ptr<wxInputStream> m_stream_in; std::unique_ptr<wxInputStream> m_stream_in;
public: public:
pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input); pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input);
pxInputStream(const wxString &filename, wxInputStream *input); pxInputStream(const wxString& filename, wxInputStream* input);
virtual ~pxInputStream() = default; virtual ~pxInputStream() = default;
virtual void Read(void *dest, size_t size); virtual void Read(void* dest, size_t size);
void SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream); void SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream);
void SetStream(const wxString &filename, wxInputStream *stream); void SetStream(const wxString& filename, wxInputStream* stream);
void Close() { m_stream_in = nullptr; } void Close() { m_stream_in = nullptr; }
virtual wxStreamBase *GetWxStreamBase() const; virtual wxStreamBase* GetWxStreamBase() const;
template <typename T> template <typename T>
void Read(T &dest) void Read(T& dest)
{ {
Read(&dest, sizeof(dest)); Read(&dest, sizeof(dest));
} }
wxFileOffset Tell() const; wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart); wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
}; };

View File

@ -25,12 +25,12 @@ bool pxIsEnglish(int id)
// pxExpandMsg -- an Iconized Text Translator // pxExpandMsg -- an Iconized Text Translator
// Was replaced by a standard implementation of wxGetTranslation // Was replaced by a standard implementation of wxGetTranslation
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
const wxChar *__fastcall pxExpandMsg(const wxChar *message) const wxChar* __fastcall pxExpandMsg(const wxChar* message)
{ {
return wxGetTranslation(message).wc_str(); return wxGetTranslation(message).wc_str();
} }
const wxChar *__fastcall pxGetTranslation(const wxChar *message) const wxChar* __fastcall pxGetTranslation(const wxChar* message)
{ {
return wxGetTranslation(message).wc_str(); return wxGetTranslation(message).wc_str();
} }

View File

@ -20,137 +20,140 @@
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxWindowTextWriter Implementations // pxWindowTextWriter Implementations
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxWindowTextWriter::pxWindowTextWriter(wxDC &dc) pxWindowTextWriter::pxWindowTextWriter(wxDC& dc)
: m_dc(dc) : m_dc(dc)
{ {
m_curpos = wxPoint(); m_curpos = wxPoint();
m_align = wxALIGN_CENTER; m_align = wxALIGN_CENTER;
m_leading = 0; m_leading = 0;
OnFontChanged(); OnFontChanged();
} }
void pxWindowTextWriter::OnFontChanged() void pxWindowTextWriter::OnFontChanged()
{ {
} }
pxWindowTextWriter &pxWindowTextWriter::SetWeight(wxFontWeight weight) pxWindowTextWriter& pxWindowTextWriter::SetWeight(wxFontWeight weight)
{ {
wxFont curfont(m_dc.GetFont()); wxFont curfont(m_dc.GetFont());
curfont.SetWeight(weight); curfont.SetWeight(weight);
m_dc.SetFont(curfont); m_dc.SetFont(curfont);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::SetStyle(wxFontStyle style) pxWindowTextWriter& pxWindowTextWriter::SetStyle(wxFontStyle style)
{ {
wxFont curfont(m_dc.GetFont()); wxFont curfont(m_dc.GetFont());
curfont.SetStyle(style); curfont.SetStyle(style);
m_dc.SetFont(curfont); m_dc.SetFont(curfont);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::Normal() pxWindowTextWriter& pxWindowTextWriter::Normal()
{ {
wxFont curfont(m_dc.GetFont()); wxFont curfont(m_dc.GetFont());
curfont.SetStyle(wxFONTSTYLE_NORMAL); curfont.SetStyle(wxFONTSTYLE_NORMAL);
curfont.SetWeight(wxFONTWEIGHT_NORMAL); curfont.SetWeight(wxFONTWEIGHT_NORMAL);
m_dc.SetFont(curfont); m_dc.SetFont(curfont);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::SetPos(const wxPoint &pos) pxWindowTextWriter& pxWindowTextWriter::SetPos(const wxPoint& pos)
{ {
m_curpos = pos; m_curpos = pos;
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::MovePos(const wxSize &delta) pxWindowTextWriter& pxWindowTextWriter::MovePos(const wxSize& delta)
{ {
m_curpos += delta; m_curpos += delta;
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::SetY(int ypos) pxWindowTextWriter& pxWindowTextWriter::SetY(int ypos)
{ {
m_curpos.y = ypos; m_curpos.y = ypos;
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::MoveY(int ydelta) pxWindowTextWriter& pxWindowTextWriter::MoveY(int ydelta)
{ {
m_curpos.y += ydelta; m_curpos.y += ydelta;
return *this; return *this;
} }
void pxWindowTextWriter::_DoWriteLn(const wxString &msg) void pxWindowTextWriter::_DoWriteLn(const wxString& msg)
{ {
int tWidth, tHeight; int tWidth, tHeight;
m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight); m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight);
wxPoint dispos(m_curpos); wxPoint dispos(m_curpos);
if (m_align & wxALIGN_CENTER_HORIZONTAL) { if (m_align & wxALIGN_CENTER_HORIZONTAL)
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2; {
} else if (m_align & wxALIGN_RIGHT) { dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
dispos.x = m_dc.GetSize().GetWidth() - tWidth; }
} else if (m_align & wxALIGN_RIGHT)
{
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
}
m_dc.DrawText(msg, dispos); m_dc.DrawText(msg, dispos);
m_curpos.y += tHeight + m_leading; m_curpos.y += tHeight + m_leading;
} }
// Splits incoming multi-line strings into pieces, and dispatches each line individually // Splits incoming multi-line strings into pieces, and dispatches each line individually
// to the text writer. // to the text writer.
void pxWindowTextWriter::_DoWrite(const wxChar *msg) void pxWindowTextWriter::_DoWrite(const wxChar* msg)
{ {
pxAssert(msg); pxAssert(msg);
wxArrayString parts; wxArrayString parts;
SplitString(parts, msg, L'\n'); SplitString(parts, msg, L'\n');
for (size_t i = 0; i < parts.GetCount(); ++i) for (size_t i = 0; i < parts.GetCount(); ++i)
_DoWriteLn(parts[i]); _DoWriteLn(parts[i]);
} }
pxWindowTextWriter &pxWindowTextWriter::SetFont(const wxFont &font) pxWindowTextWriter& pxWindowTextWriter::SetFont(const wxFont& font)
{ {
m_dc.SetFont(font); m_dc.SetFont(font);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::Align(const wxAlignment &align) pxWindowTextWriter& pxWindowTextWriter::Align(const wxAlignment& align)
{ {
m_align = align; m_align = align;
m_curpos.x = 0; m_curpos.x = 0;
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::WriteLn() pxWindowTextWriter& pxWindowTextWriter::WriteLn()
{ {
_DoWriteLn(L""); _DoWriteLn(L"");
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxChar *fmt) pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxChar* fmt)
{ {
_DoWrite(fmt); _DoWrite(fmt);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::FormatLn(const wxChar *fmt, ...) pxWindowTextWriter& pxWindowTextWriter::FormatLn(const wxChar* fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
_DoWrite(pxsFmtV(fmt, args)); _DoWrite(pxsFmtV(fmt, args));
va_end(args); va_end(args);
return *this; return *this;
} }
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxString fmt) pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxString fmt)
{ {
_DoWrite(fmt.wc_str()); _DoWrite(fmt.wc_str());
return *this; return *this;
} }

View File

@ -27,21 +27,21 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxSimpleEvent, wxEvent);
ConsoleLogSource_App::ConsoleLogSource_App() ConsoleLogSource_App::ConsoleLogSource_App()
{ {
static const TraceLogDescriptor myDesc = static const TraceLogDescriptor myDesc =
{ {
L"AppEvents", L"App Events", L"AppEvents", L"App Events",
pxLt("Includes idle event processing and some other uncommon event usages.")}; pxLt("Includes idle event processing and some other uncommon event usages.")};
m_Descriptor = &myDesc; m_Descriptor = &myDesc;
} }
ConsoleLogSource_App pxConLog_App; ConsoleLogSource_App pxConLog_App;
void BaseDeletableObject::DoDeletion() void BaseDeletableObject::DoDeletion()
{ {
wxAppWithHelpers *app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers); wxAppWithHelpers* app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
pxAssert(app != NULL); pxAssert(app != NULL);
app->DeleteObject(*this); app->DeleteObject(*this);
} }
@ -49,64 +49,67 @@ void BaseDeletableObject::DoDeletion()
// SynchronousActionState Implementations // SynchronousActionState Implementations
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
void SynchronousActionState::SetException(const BaseException &ex) void SynchronousActionState::SetException(const BaseException& ex)
{ {
m_exception = ScopedExcept(ex.Clone()); m_exception = ScopedExcept(ex.Clone());
} }
void SynchronousActionState::SetException(BaseException *ex) void SynchronousActionState::SetException(BaseException* ex)
{ {
if (!m_posted) { if (!m_posted)
m_exception = ScopedExcept(ex); {
} else if (wxTheApp) { m_exception = ScopedExcept(ex);
// transport the exception to the main thread, since the message is fully }
// asynchronous, or has already entered an asynchronous state. Message is sent else if (wxTheApp)
// as a non-blocking action since proper handling of user errors on async messages {
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog // transport the exception to the main thread, since the message is fully
// box to the user. // asynchronous, or has already entered an asynchronous state. Message is sent
// as a non-blocking action since proper handling of user errors on async messages
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
// box to the user.
pxExceptionEvent ev(ex); pxExceptionEvent ev(ex);
wxTheApp->AddPendingEvent(ev); wxTheApp->AddPendingEvent(ev);
} }
} }
void SynchronousActionState::RethrowException() const void SynchronousActionState::RethrowException() const
{ {
if (m_exception) if (m_exception)
m_exception->Rethrow(); m_exception->Rethrow();
} }
int SynchronousActionState::WaitForResult() int SynchronousActionState::WaitForResult()
{ {
m_sema.WaitNoCancel(); m_sema.WaitNoCancel();
RethrowException(); RethrowException();
return return_value; return return_value;
} }
int SynchronousActionState::WaitForResult_NoExceptions() int SynchronousActionState::WaitForResult_NoExceptions()
{ {
m_sema.WaitNoCancel(); m_sema.WaitNoCancel();
return return_value; return return_value;
} }
void SynchronousActionState::PostResult(int res) void SynchronousActionState::PostResult(int res)
{ {
return_value = res; return_value = res;
PostResult(); PostResult();
} }
void SynchronousActionState::ClearResult() void SynchronousActionState::ClearResult()
{ {
m_posted = false; m_posted = false;
m_exception = NULL; m_exception = NULL;
} }
void SynchronousActionState::PostResult() void SynchronousActionState::PostResult()
{ {
if (m_posted) if (m_posted)
return; return;
m_posted = true; m_posted = true;
m_sema.Post(); m_sema.Post();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -115,40 +118,41 @@ void SynchronousActionState::PostResult()
wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent);
pxActionEvent::pxActionEvent(SynchronousActionState *sema, int msgtype) pxActionEvent::pxActionEvent(SynchronousActionState* sema, int msgtype)
: wxEvent(0, msgtype) : wxEvent(0, msgtype)
{ {
m_state = sema; m_state = sema;
} }
pxActionEvent::pxActionEvent(SynchronousActionState &sema, int msgtype) pxActionEvent::pxActionEvent(SynchronousActionState& sema, int msgtype)
: wxEvent(0, msgtype) : wxEvent(0, msgtype)
{ {
m_state = &sema; m_state = &sema;
} }
pxActionEvent::pxActionEvent(const pxActionEvent &src) pxActionEvent::pxActionEvent(const pxActionEvent& src)
: wxEvent(src) : wxEvent(src)
{ {
m_state = src.m_state; m_state = src.m_state;
} }
void pxActionEvent::SetException(const BaseException &ex) void pxActionEvent::SetException(const BaseException& ex)
{ {
SetException(ex.Clone()); SetException(ex.Clone());
} }
void pxActionEvent::SetException(BaseException *ex) void pxActionEvent::SetException(BaseException* ex)
{ {
const wxString &prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName())); const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
ex->DiagMsg() = prefix + ex->DiagMsg(); ex->DiagMsg() = prefix + ex->DiagMsg();
if (!m_state) { if (!m_state)
ScopedExcept exptr(ex); // auto-delete it after handling. {
ex->Rethrow(); ScopedExcept exptr(ex); // auto-delete it after handling.
} ex->Rethrow();
}
m_state->SetException(ex); m_state->SetException(ex);
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -156,58 +160,59 @@ void pxActionEvent::SetException(BaseException *ex)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(pxSynchronousCommandEvent, wxCommandEvent); wxIMPLEMENT_DYNAMIC_CLASS(pxSynchronousCommandEvent, wxCommandEvent);
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, wxEventType commandType, int winid) pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand, winid) : wxCommandEvent(pxEvt_SynchronousCommand, winid)
{ {
m_sync = sema; m_sync = sema;
m_realEvent = commandType; m_realEvent = commandType;
} }
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType, int winid) pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand) : wxCommandEvent(pxEvt_SynchronousCommand)
{ {
m_sync = &sema; m_sync = &sema;
m_realEvent = commandType; m_realEvent = commandType;
} }
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt) pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt)
: wxCommandEvent(evt) : wxCommandEvent(evt)
{ {
m_sync = sema; m_sync = sema;
m_realEvent = evt.GetEventType(); m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand); SetEventType(pxEvt_SynchronousCommand);
} }
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt) pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt)
: wxCommandEvent(evt) : wxCommandEvent(evt)
{ {
m_sync = &sema; m_sync = &sema;
m_realEvent = evt.GetEventType(); m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand); SetEventType(pxEvt_SynchronousCommand);
} }
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src) pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src)
: wxCommandEvent(src) : wxCommandEvent(src)
{ {
m_sync = src.m_sync; m_sync = src.m_sync;
m_realEvent = src.m_realEvent; m_realEvent = src.m_realEvent;
} }
void pxSynchronousCommandEvent::SetException(const BaseException &ex) void pxSynchronousCommandEvent::SetException(const BaseException& ex)
{ {
if (!m_sync) if (!m_sync)
ex.Rethrow(); ex.Rethrow();
m_sync->SetException(ex); m_sync->SetException(ex);
} }
void pxSynchronousCommandEvent::SetException(BaseException *ex) void pxSynchronousCommandEvent::SetException(BaseException* ex)
{ {
if (!m_sync) { if (!m_sync)
ScopedExcept exptr(ex); // auto-delete it after handling. {
ex->Rethrow(); ScopedExcept exptr(ex); // auto-delete it after handling.
} ex->Rethrow();
}
m_sync->SetException(ex); m_sync->SetException(ex);
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -219,46 +224,46 @@ void pxSynchronousCommandEvent::SetException(BaseException *ex)
// //
class pxRpcEvent : public pxActionEvent class pxRpcEvent : public pxActionEvent
{ {
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent); wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
typedef pxActionEvent _parent; typedef pxActionEvent _parent;
protected: protected:
void (*m_Method)(); void (*m_Method)();
public: public:
virtual ~pxRpcEvent() = default; virtual ~pxRpcEvent() = default;
virtual pxRpcEvent *Clone() const { return new pxRpcEvent(*this); } virtual pxRpcEvent* Clone() const { return new pxRpcEvent(*this); }
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState *sema = NULL) explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState* sema = NULL)
: pxActionEvent(sema) : pxActionEvent(sema)
{ {
m_Method = method; m_Method = method;
} }
explicit pxRpcEvent(void (*method)(), SynchronousActionState &sema) explicit pxRpcEvent(void (*method)(), SynchronousActionState& sema)
: pxActionEvent(sema) : pxActionEvent(sema)
{ {
m_Method = method; m_Method = method;
} }
pxRpcEvent(const pxRpcEvent &src) pxRpcEvent(const pxRpcEvent& src)
: pxActionEvent(src) : pxActionEvent(src)
{ {
m_Method = src.m_Method; m_Method = src.m_Method;
} }
void SetMethod(void (*method)()) void SetMethod(void (*method)())
{ {
m_Method = method; m_Method = method;
} }
protected: protected:
void InvokeEvent() void InvokeEvent()
{ {
if (m_Method) if (m_Method)
m_Method(); m_Method();
} }
}; };
wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent); wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
@ -266,16 +271,16 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// pxExceptionEvent implementations // pxExceptionEvent implementations
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
pxExceptionEvent::pxExceptionEvent(const BaseException &ex) pxExceptionEvent::pxExceptionEvent(const BaseException& ex)
{ {
m_except = ex.Clone(); m_except = ex.Clone();
} }
void pxExceptionEvent::InvokeEvent() void pxExceptionEvent::InvokeEvent()
{ {
ScopedExcept deleteMe(m_except); ScopedExcept deleteMe(m_except);
if (deleteMe) if (deleteMe)
deleteMe->Rethrow(); deleteMe->Rethrow();
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -291,17 +296,17 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxAppWithHelpers, wxApp);
// Posts a method to the main thread; non-blocking. Post occurs even when called from the // Posts a method to the main thread; non-blocking. Post occurs even when called from the
// main thread. // main thread.
void wxAppWithHelpers::PostMethod(FnType_Void *method) void wxAppWithHelpers::PostMethod(FnType_Void* method)
{ {
PostEvent(pxRpcEvent(method)); PostEvent(pxRpcEvent(method));
} }
// Posts a method to the main thread; non-blocking. Post occurs even when called from the // Posts a method to the main thread; non-blocking. Post occurs even when called from the
// main thread. // main thread.
void wxAppWithHelpers::PostIdleMethod(FnType_Void *method) void wxAppWithHelpers::PostIdleMethod(FnType_Void* method)
{ {
pxRpcEvent evt(method); pxRpcEvent evt(method);
AddIdleEvent(evt); AddIdleEvent(evt);
} }
// Invokes the specified void method, or posts the method to the main thread if the calling // Invokes the specified void method, or posts the method to the main thread if the calling
@ -316,16 +321,16 @@ void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
// TRUE if the method was invoked. // TRUE if the method was invoked.
// //
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method) bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void* method)
{ {
if (wxThread::IsMain()) if (wxThread::IsMain())
return false; return false;
SynchronousActionState sync; SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync)); PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult(); sync.WaitForResult();
return true; return true;
} }
// Invokes the specified void method, or posts the method to the main thread if the calling // Invokes the specified void method, or posts the method to the main thread if the calling
@ -339,93 +344,98 @@ bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!) // FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
// TRUE if the method was posted. // TRUE if the method was posted.
// //
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void *method) bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void* method)
{ {
if (wxThread::IsMain()) if (wxThread::IsMain())
return false; return false;
PostEvent(pxRpcEvent(method)); PostEvent(pxRpcEvent(method));
return true; return true;
} }
void wxAppWithHelpers::ProcessMethod(FnType_Void *method) void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
{ {
if (wxThread::IsMain()) { if (wxThread::IsMain())
method(); {
return; method();
} return;
}
SynchronousActionState sync; SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync)); PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult(); sync.WaitForResult();
} }
void wxAppWithHelpers::PostEvent(const wxEvent &evt) void wxAppWithHelpers::PostEvent(const wxEvent& evt)
{ {
// Const Cast is OK! // Const Cast is OK!
// Truth is, AddPendingEvent should be a const-qualified parameter, as // Truth is, AddPendingEvent should be a const-qualified parameter, as
// it makes an immediate clone copy of the event -- but wxWidgets // it makes an immediate clone copy of the event -- but wxWidgets
// fails again in structured C/C++ design design. So I'm forcing it as such // fails again in structured C/C++ design design. So I'm forcing it as such
// here. -- air // here. -- air
_parent::AddPendingEvent(const_cast<wxEvent &>(evt)); _parent::AddPendingEvent(const_cast<wxEvent&>(evt));
} }
bool wxAppWithHelpers::ProcessEvent(wxEvent &evt) bool wxAppWithHelpers::ProcessEvent(wxEvent& evt)
{ {
// Note: We can't do an automatic blocking post of the message here, because wxWidgets // Note: We can't do an automatic blocking post of the message here, because wxWidgets
// isn't really designed for it (some events return data to the caller via the event // isn't really designed for it (some events return data to the caller via the event
// struct, and posting the event would require a temporary clone, where changes would // struct, and posting the event would require a temporary clone, where changes would
// be lost). // be lost).
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
return _parent::ProcessEvent(evt); return _parent::ProcessEvent(evt);
} }
bool wxAppWithHelpers::ProcessEvent(wxEvent *evt) bool wxAppWithHelpers::ProcessEvent(wxEvent* evt)
{ {
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
std::unique_ptr<wxEvent> deleteMe(evt); std::unique_ptr<wxEvent> deleteMe(evt);
return _parent::ProcessEvent(*deleteMe); return _parent::ProcessEvent(*deleteMe);
} }
bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt) bool wxAppWithHelpers::ProcessEvent(pxActionEvent& evt)
{ {
if (wxThread::IsMain()) if (wxThread::IsMain())
return _parent::ProcessEvent(evt); return _parent::ProcessEvent(evt);
else { else
SynchronousActionState sync; {
evt.SetSyncState(sync); SynchronousActionState sync;
AddPendingEvent(evt); evt.SetSyncState(sync);
sync.WaitForResult(); AddPendingEvent(evt);
return true; sync.WaitForResult();
} return true;
}
} }
bool wxAppWithHelpers::ProcessEvent(pxActionEvent *evt) bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
{ {
if (wxThread::IsMain()) { if (wxThread::IsMain())
std::unique_ptr<wxEvent> deleteMe(evt); {
return _parent::ProcessEvent(*deleteMe); std::unique_ptr<wxEvent> deleteMe(evt);
} else { return _parent::ProcessEvent(*deleteMe);
SynchronousActionState sync; }
evt->SetSyncState(sync); else
AddPendingEvent(*evt); {
sync.WaitForResult(); SynchronousActionState sync;
return true; evt->SetSyncState(sync);
} AddPendingEvent(*evt);
sync.WaitForResult();
return true;
}
} }
void wxAppWithHelpers::CleanUp() void wxAppWithHelpers::CleanUp()
{ {
// I'm pretty sure the message pump is dead by now, which means we need to run through // I'm pretty sure the message pump is dead by now, which means we need to run through
// idle event list by hand and process the pending Deletion messages (all others can be // idle event list by hand and process the pending Deletion messages (all others can be
// ignored -- it's only deletions we want handled, and really we *could* ignore those too // ignored -- it's only deletions we want handled, and really we *could* ignore those too
// but I like to be tidy. -- air // but I like to be tidy. -- air
//IdleEventDispatcher( "CleanUp" ); //IdleEventDispatcher( "CleanUp" );
//DeletionDispatcher(); //DeletionDispatcher();
_parent::CleanUp(); _parent::CleanUp();
} }
// Executes the event with exception handling. If the event throws an exception, the exception // Executes the event with exception handling. If the event throws an exception, the exception
@ -434,211 +444,227 @@ void wxAppWithHelpers::CleanUp()
// should overload InvokeEvent() instead. // should overload InvokeEvent() instead.
void pxActionEvent::_DoInvokeEvent() void pxActionEvent::_DoInvokeEvent()
{ {
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
try { try
InvokeEvent(); {
} catch (BaseException &ex) { InvokeEvent();
SetException(ex); }
} catch (std::runtime_error &ex) { catch (BaseException& ex)
SetException(new Exception::RuntimeError(ex)); {
} SetException(ex);
}
catch (std::runtime_error& ex)
{
SetException(new Exception::RuntimeError(ex));
}
if (m_state) if (m_state)
m_state->PostResult(); m_state->PostResult();
} }
void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent &evt) void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent& evt)
{ {
AffinityAssert_AllowFrom_MainUI(); AffinityAssert_AllowFrom_MainUI();
pxAppLog.Write(L"(App) Executing command event synchronously..."); pxAppLog.Write(L"(App) Executing command event synchronously...");
evt.SetEventType(evt.GetRealEventType()); evt.SetEventType(evt.GetRealEventType());
try { try
ProcessEvent(evt); {
} catch (BaseException &ex) { ProcessEvent(evt);
evt.SetException(ex); }
} catch (std::runtime_error &ex) { catch (BaseException& ex)
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName())); {
} evt.SetException(ex);
}
catch (std::runtime_error& ex)
{
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
}
if (Semaphore *sema = evt.GetSemaphore()) if (Semaphore* sema = evt.GetSemaphore())
sema->Post(); sema->Post();
} }
void wxAppWithHelpers::AddIdleEvent(const wxEvent &evt) void wxAppWithHelpers::AddIdleEvent(const wxEvent& evt)
{ {
ScopedLock lock(m_IdleEventMutex); ScopedLock lock(m_IdleEventMutex);
if (m_IdleEventQueue.empty()) if (m_IdleEventQueue.empty())
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer)); PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
m_IdleEventQueue.push_back(evt.Clone()); m_IdleEventQueue.push_back(evt.Clone());
} }
void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent &evt) void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent& evt)
{ {
ScopedLock lock(m_IdleEventMutex); ScopedLock lock(m_IdleEventMutex);
if (!m_IdleEventQueue.empty()) if (!m_IdleEventQueue.empty())
m_IdleEventTimer.Start(100, true); m_IdleEventTimer.Start(100, true);
} }
void wxAppWithHelpers::IdleEventDispatcher(const wxChar *action) void wxAppWithHelpers::IdleEventDispatcher(const wxChar* action)
{ {
// Recursion is possible thanks to modal dialogs being issued from the idle event handler. // Recursion is possible thanks to modal dialogs being issued from the idle event handler.
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator // (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
// on each pass) // on each pass)
//static int __guard=0; //static int __guard=0;
//RecursionGuard guard(__guard); //RecursionGuard guard(__guard);
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return; //if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
wxEventList postponed; wxEventList postponed;
wxEventList::iterator node; wxEventList::iterator node;
ScopedLock lock(m_IdleEventMutex); ScopedLock lock(m_IdleEventMutex);
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end()) { while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end())
std::unique_ptr<wxEvent> deleteMe(*node); {
m_IdleEventQueue.erase(node); std::unique_ptr<wxEvent> deleteMe(*node);
m_IdleEventQueue.erase(node);
lock.Release(); lock.Release();
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread)) { if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread))
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot {
// be deleted because those mutex/sema objects will become invalid and cause the pending // Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
// thread to crash. So we disallow deletions when those waits are in action, and continue // be deleted because those mutex/sema objects will become invalid and cause the pending
// to postpone the deletion of the thread until such time that it is safe. // thread to crash. So we disallow deletions when those waits are in action, and continue
// to postpone the deletion of the thread until such time that it is safe.
pxThreadLog.Write(((pxThread *)((wxCommandEvent *)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency."); pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
postponed.push_back(deleteMe.release()); postponed.push_back(deleteMe.release());
} else { }
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName()); else
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent {
} pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
lock.Acquire(); ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
} }
lock.Acquire();
}
m_IdleEventQueue = postponed; m_IdleEventQueue = postponed;
if (!m_IdleEventQueue.empty()) if (!m_IdleEventQueue.empty())
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size()); pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
} }
void wxAppWithHelpers::OnIdleEvent(wxIdleEvent &evt) void wxAppWithHelpers::OnIdleEvent(wxIdleEvent& evt)
{ {
m_IdleEventTimer.Stop(); m_IdleEventTimer.Stop();
IdleEventDispatcher(); IdleEventDispatcher();
} }
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent &evt) void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent& evt)
{ {
IdleEventDispatcher(L"[Timeout]"); IdleEventDispatcher(L"[Timeout]");
} }
void wxAppWithHelpers::Ping() void wxAppWithHelpers::Ping()
{ {
pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested."); pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested.");
SynchronousActionState sync; SynchronousActionState sync;
pxActionEvent evt(sync); pxActionEvent evt(sync);
AddIdleEvent(evt); AddIdleEvent(evt);
sync.WaitForResult(); sync.WaitForResult();
} }
void wxAppWithHelpers::PostCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam) void wxAppWithHelpers::PostCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
{ {
wxCommandEvent evt(evtType); wxCommandEvent evt(evtType);
evt.SetClientData(clientData); evt.SetClientData(clientData);
evt.SetInt(intParam); evt.SetInt(intParam);
evt.SetExtraLong(longParam); evt.SetExtraLong(longParam);
evt.SetString(stringParam); evt.SetString(stringParam);
AddPendingEvent(evt); AddPendingEvent(evt);
} }
void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString &stringParam) void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
{ {
PostCommand(NULL, evtType, intParam, longParam, stringParam); PostCommand(NULL, evtType, intParam, longParam, stringParam);
} }
sptr wxAppWithHelpers::ProcessCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam) sptr wxAppWithHelpers::ProcessCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
{ {
SynchronousActionState sync; SynchronousActionState sync;
pxSynchronousCommandEvent evt(sync, evtType); pxSynchronousCommandEvent evt(sync, evtType);
evt.SetClientData(clientData); evt.SetClientData(clientData);
evt.SetInt(intParam); evt.SetInt(intParam);
evt.SetExtraLong(longParam); evt.SetExtraLong(longParam);
evt.SetString(stringParam); evt.SetString(stringParam);
AddPendingEvent(evt); AddPendingEvent(evt);
sync.WaitForResult(); sync.WaitForResult();
return sync.return_value; return sync.return_value;
} }
sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString &stringParam) sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
{ {
return ProcessCommand(NULL, evtType, intParam, longParam, stringParam); return ProcessCommand(NULL, evtType, intParam, longParam, stringParam);
} }
void wxAppWithHelpers::PostAction(const pxActionEvent &evt) void wxAppWithHelpers::PostAction(const pxActionEvent& evt)
{ {
PostEvent(evt); PostEvent(evt);
} }
void wxAppWithHelpers::ProcessAction(pxActionEvent &evt) void wxAppWithHelpers::ProcessAction(pxActionEvent& evt)
{ {
if (!wxThread::IsMain()) { if (!wxThread::IsMain())
SynchronousActionState sync; {
evt.SetSyncState(sync); SynchronousActionState sync;
AddPendingEvent(evt); evt.SetSyncState(sync);
sync.WaitForResult(); AddPendingEvent(evt);
} else sync.WaitForResult();
evt._DoInvokeEvent(); }
else
evt._DoInvokeEvent();
} }
void wxAppWithHelpers::DeleteObject(BaseDeletableObject &obj) void wxAppWithHelpers::DeleteObject(BaseDeletableObject& obj)
{ {
pxAssert(!obj.IsBeingDeleted()); pxAssert(!obj.IsBeingDeleted());
wxCommandEvent evt(pxEvt_DeleteObject); wxCommandEvent evt(pxEvt_DeleteObject);
evt.SetClientData((void *)&obj); evt.SetClientData((void*)&obj);
AddIdleEvent(evt); AddIdleEvent(evt);
} }
void wxAppWithHelpers::DeleteThread(pxThread &obj) void wxAppWithHelpers::DeleteThread(pxThread& obj)
{ {
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion..."); pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
wxCommandEvent evt(pxEvt_DeleteThread); wxCommandEvent evt(pxEvt_DeleteThread);
evt.SetClientData((void *)&obj); evt.SetClientData((void*)&obj);
AddIdleEvent(evt); AddIdleEvent(evt);
} }
bool wxAppWithHelpers::OnInit() bool wxAppWithHelpers::OnInit()
{ {
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this); Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this); Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this); Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this);
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this); Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this);
Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this); Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this); Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this);
Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId()); Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId());
return _parent::OnInit(); return _parent::OnInit();
} }
void wxAppWithHelpers::OnInvokeAction(pxActionEvent &evt) void wxAppWithHelpers::OnInvokeAction(pxActionEvent& evt)
{ {
evt._DoInvokeEvent(); // wow this is easy! evt._DoInvokeEvent(); // wow this is easy!
} }
void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt) void wxAppWithHelpers::OnDeleteObject(wxCommandEvent& evt)
{ {
if (evt.GetClientData() == NULL) if (evt.GetClientData() == NULL)
return; return;
delete (BaseDeletableObject *)evt.GetClientData(); delete (BaseDeletableObject*)evt.GetClientData();
} }
// In theory we create a Pcsx2App object which inherit from wxAppWithHelpers, // In theory we create a Pcsx2App object which inherit from wxAppWithHelpers,
@ -648,35 +674,36 @@ void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt)
// be called first. This constructor will build some wx objects (here wxTimer) // be called first. This constructor will build some wx objects (here wxTimer)
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be // that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
// called instead // called instead
wxAppTraits *wxAppWithHelpers::CreateTraits() wxAppTraits* wxAppWithHelpers::CreateTraits()
{ {
return new Pcsx2AppTraits; return new Pcsx2AppTraits;
} }
// Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI. // Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
// (thus we have a fairly automatic threaded exception system!) // (thus we have a fairly automatic threaded exception system!)
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent &evt) void wxAppWithHelpers::OnDeleteThread(wxCommandEvent& evt)
{ {
std::unique_ptr<pxThread> thr((pxThread *)evt.GetClientData()); std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
if (!thr) { if (!thr)
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored)."); {
return; pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
} return;
}
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str()); pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
thr->RethrowException(); thr->RethrowException();
} }
wxAppWithHelpers::wxAppWithHelpers() wxAppWithHelpers::wxAppWithHelpers()
: m_IdleEventTimer(this) : m_IdleEventTimer(this)
{ {
#ifdef __WXMSW__ #ifdef __WXMSW__
// This variable assignment ensures that MSVC links in the TLS setup stubs even in // This variable assignment ensures that MSVC links in the TLS setup stubs even in
// full optimization builds. Without it, DLLs that use TLS won't work because the // full optimization builds. Without it, DLLs that use TLS won't work because the
// FS segment register won't have been initialized by the main exe, due to tls_insurance // FS segment register won't have been initialized by the main exe, due to tls_insurance
// being optimized away >_< --air // being optimized away >_< --air
static thread_local int tls_insurance = 0; static thread_local int tls_insurance = 0;
tls_insurance = 1; tls_insurance = 1;
#endif #endif
} }

View File

@ -32,10 +32,10 @@ class pxSynchronousCommandEvent;
class ConsoleLogSource_App : public ConsoleLogSource class ConsoleLogSource_App : public ConsoleLogSource
{ {
typedef ConsoleLogSource _parent; typedef ConsoleLogSource _parent;
public: public:
ConsoleLogSource_App(); ConsoleLogSource_App();
}; };
extern ConsoleLogSource_App pxConLog_App; extern ConsoleLogSource_App pxConLog_App;
@ -49,97 +49,97 @@ extern ConsoleLogSource_App pxConLog_App;
class ModalButtonPanel : public wxPanelWithHelpers class ModalButtonPanel : public wxPanelWithHelpers
{ {
public: public:
ModalButtonPanel(wxWindow *window, const MsgButtons &buttons); ModalButtonPanel(wxWindow* window, const MsgButtons& buttons);
virtual ~ModalButtonPanel() = default; virtual ~ModalButtonPanel() = default;
virtual void AddActionButton(wxWindowID id); virtual void AddActionButton(wxWindowID id);
virtual void AddCustomButton(wxWindowID id, const wxString &label); virtual void AddCustomButton(wxWindowID id, const wxString& label);
virtual void OnActionButtonClicked(wxCommandEvent &evt); virtual void OnActionButtonClicked(wxCommandEvent& evt);
}; };
typedef std::list<wxEvent *> wxEventList; typedef std::list<wxEvent*> wxEventList;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// wxAppWithHelpers // wxAppWithHelpers
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class wxAppWithHelpers : public wxApp class wxAppWithHelpers : public wxApp
{ {
typedef wxApp _parent; typedef wxApp _parent;
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers); wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
protected: protected:
wxEventList m_IdleEventQueue; wxEventList m_IdleEventQueue;
Threading::MutexRecursive m_IdleEventMutex; Threading::MutexRecursive m_IdleEventMutex;
wxTimer m_IdleEventTimer; wxTimer m_IdleEventTimer;
public: public:
wxAppWithHelpers(); wxAppWithHelpers();
virtual ~wxAppWithHelpers() {} virtual ~wxAppWithHelpers() {}
wxAppTraits *CreateTraits(); wxAppTraits* CreateTraits();
void CleanUp(); void CleanUp();
void DeleteObject(BaseDeletableObject &obj); void DeleteObject(BaseDeletableObject& obj);
void DeleteObject(BaseDeletableObject *obj) void DeleteObject(BaseDeletableObject* obj)
{ {
if (obj == NULL) if (obj == NULL)
return; return;
DeleteObject(*obj); DeleteObject(*obj);
} }
void DeleteThread(Threading::pxThread &obj); void DeleteThread(Threading::pxThread& obj);
void DeleteThread(Threading::pxThread *obj) void DeleteThread(Threading::pxThread* obj)
{ {
if (obj == NULL) if (obj == NULL)
return; return;
DeleteThread(*obj); DeleteThread(*obj);
} }
void PostCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString); void PostCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString); void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
void PostMethod(FnType_Void *method); void PostMethod(FnType_Void* method);
void PostIdleMethod(FnType_Void *method); void PostIdleMethod(FnType_Void* method);
void ProcessMethod(FnType_Void *method); void ProcessMethod(FnType_Void* method);
bool Rpc_TryInvoke(FnType_Void *method); bool Rpc_TryInvoke(FnType_Void* method);
bool Rpc_TryInvokeAsync(FnType_Void *method); bool Rpc_TryInvokeAsync(FnType_Void* method);
sptr ProcessCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString); sptr ProcessCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString); sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
void ProcessAction(pxActionEvent &evt); void ProcessAction(pxActionEvent& evt);
void PostAction(const pxActionEvent &evt); void PostAction(const pxActionEvent& evt);
void Ping(); void Ping();
bool OnInit(); bool OnInit();
//int OnExit(); //int OnExit();
void AddIdleEvent(const wxEvent &evt); void AddIdleEvent(const wxEvent& evt);
void PostEvent(const wxEvent &evt); void PostEvent(const wxEvent& evt);
bool ProcessEvent(wxEvent &evt); bool ProcessEvent(wxEvent& evt);
bool ProcessEvent(wxEvent *evt); bool ProcessEvent(wxEvent* evt);
bool ProcessEvent(pxActionEvent &evt); bool ProcessEvent(pxActionEvent& evt);
bool ProcessEvent(pxActionEvent *evt); bool ProcessEvent(pxActionEvent* evt);
protected: protected:
void IdleEventDispatcher(const wxChar *action = wxEmptyString); void IdleEventDispatcher(const wxChar* action = wxEmptyString);
void OnIdleEvent(wxIdleEvent &evt); void OnIdleEvent(wxIdleEvent& evt);
void OnStartIdleEventTimer(wxCommandEvent &evt); void OnStartIdleEventTimer(wxCommandEvent& evt);
void OnIdleEventTimeout(wxTimerEvent &evt); void OnIdleEventTimeout(wxTimerEvent& evt);
void OnDeleteObject(wxCommandEvent &evt); void OnDeleteObject(wxCommandEvent& evt);
void OnDeleteThread(wxCommandEvent &evt); void OnDeleteThread(wxCommandEvent& evt);
void OnSynchronousCommand(pxSynchronousCommandEvent &evt); void OnSynchronousCommand(pxSynchronousCommandEvent& evt);
void OnInvokeAction(pxActionEvent &evt); void OnInvokeAction(pxActionEvent& evt);
}; };
namespace Msgbox namespace Msgbox
{ {
extern int ShowModal(BaseMessageBoxEvent &evt); extern int ShowModal(BaseMessageBoxEvent& evt);
extern int ShowModal(const wxString &title, const wxString &content, const MsgButtons &buttons); extern int ShowModal(const wxString& title, const wxString& content, const MsgButtons& buttons);
} } // namespace Msgbox

View File

@ -26,11 +26,11 @@
// which require wxCore, see wxGuiTools.h // which require wxCore, see wxGuiTools.h
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
extern void pxExplore(const wxString &path); extern void pxExplore(const wxString& path);
extern void pxExplore(const char *path); extern void pxExplore(const char* path);
extern void pxLaunch(const wxString &path); extern void pxLaunch(const wxString& path);
extern void pxLaunch(const char *path); extern void pxLaunch(const char* path);
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// wxDoNotLogInThisScope // wxDoNotLogInThisScope
@ -44,28 +44,28 @@ extern void pxLaunch(const char *path);
// //
class wxDoNotLogInThisScope class wxDoNotLogInThisScope
{ {
DeclareNoncopyableObject(wxDoNotLogInThisScope); DeclareNoncopyableObject(wxDoNotLogInThisScope);
protected: protected:
bool m_prev; bool m_prev;
public: public:
wxDoNotLogInThisScope() wxDoNotLogInThisScope()
{ {
m_prev = wxLog::EnableLogging(false); m_prev = wxLog::EnableLogging(false);
} }
virtual ~wxDoNotLogInThisScope() virtual ~wxDoNotLogInThisScope()
{ {
wxLog::EnableLogging(m_prev); wxLog::EnableLogging(m_prev);
} }
}; };
extern wxString pxReadLine(wxInputStream &input); extern wxString pxReadLine(wxInputStream& input);
extern void pxReadLine(wxInputStream &input, wxString &dest); extern void pxReadLine(wxInputStream& input, wxString& dest);
extern void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed); extern void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed);
extern bool pxReadLine(wxInputStream &input, std::string &dest); extern bool pxReadLine(wxInputStream& input, std::string& dest);
extern void pxWriteLine(wxOutputStream &output); extern void pxWriteLine(wxOutputStream& output);
extern void pxWriteLine(wxOutputStream &output, const wxString &text); extern void pxWriteLine(wxOutputStream& output, const wxString& text);
extern void pxWriteMultiline(wxOutputStream &output, const wxString &src); extern void pxWriteMultiline(wxOutputStream& output, const wxString& src);

View File

@ -22,171 +22,173 @@
#include <wx/display.h> #include <wx/display.h>
const pxAlignmentType const pxAlignmentType
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
pxCenter = pxCentre, pxCenter = pxCentre,
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
pxAlignLeft = {pxAlignmentType::Left}, pxAlignLeft = {pxAlignmentType::Left},
pxAlignRight = {pxAlignmentType::Right}, pxAlignRight = {pxAlignmentType::Right},
pxAlignTop = {pxAlignmentType::Top}, pxAlignTop = {pxAlignmentType::Top},
pxAlignBottom = {pxAlignmentType::Bottom}; pxAlignBottom = {pxAlignmentType::Bottom};
const pxStretchType const pxStretchType
pxShrink = {pxStretchType::Shrink}, pxShrink = {pxStretchType::Shrink},
pxExpand = {pxStretchType::Expand}, pxExpand = {pxStretchType::Expand},
pxShaped = {pxStretchType::Shaped}, pxShaped = {pxStretchType::Shaped},
pxReserveHidden = {pxStretchType::ReserveHidden}, pxReserveHidden = {pxStretchType::ReserveHidden},
pxFixedMinimum = {pxStretchType::FixedMinimum}; pxFixedMinimum = {pxStretchType::FixedMinimum};
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
{ {
switch (intval) { switch (intval)
case Centre: {
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL); case Centre:
break; flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
break;
case Middle: case Middle:
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL); flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
break; break;
case Left: case Left:
flags.Left(); flags.Left();
break; break;
case Right: case Right:
flags.Right(); flags.Right();
break; break;
case Top: case Top:
flags.Top(); flags.Top();
break; break;
case Bottom: case Bottom:
flags.Bottom(); flags.Bottom();
break; break;
} }
return flags; return flags;
} }
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
{ {
switch (intval) { switch (intval)
case Shrink: {
//pxFail( "wxSHRINK is an ignored stretch flag." ); case Shrink:
break; //pxFail( "wxSHRINK is an ignored stretch flag." );
break;
case Expand: case Expand:
flags.Expand(); flags.Expand();
break; break;
case Shaped: case Shaped:
flags.Shaped(); flags.Shaped();
break; break;
case ReserveHidden: case ReserveHidden:
flags.ReserveSpaceEvenIfHidden(); flags.ReserveSpaceEvenIfHidden();
break; break;
case FixedMinimum: case FixedMinimum:
flags.FixedMinSize(); flags.FixedMinSize();
break; break;
//case Tile: //case Tile:
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." ); // pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
//break; //break;
} }
return flags; return flags;
} }
wxSizerFlags operator&(const wxSizerFlags &_flgs, const wxSizerFlags &_flgs2) wxSizerFlags operator&(const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2)
{ {
//return align.Apply( _flgs ); //return align.Apply( _flgs );
wxSizerFlags retval; wxSizerFlags retval;
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags()); uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
retval.Align(allflags & wxALIGN_MASK); retval.Align(allflags & wxALIGN_MASK);
if (allflags & wxEXPAND) if (allflags & wxEXPAND)
retval.Expand(); retval.Expand();
if (allflags & wxSHAPED) if (allflags & wxSHAPED)
retval.Shaped(); retval.Shaped();
if (allflags & wxFIXED_MINSIZE) if (allflags & wxFIXED_MINSIZE)
retval.FixedMinSize(); retval.FixedMinSize();
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN) if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
retval.ReserveSpaceEvenIfHidden(); retval.ReserveSpaceEvenIfHidden();
// Compounding borders is probably a fair approach: // Compounding borders is probably a fair approach:
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels()); retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
// Compounding proportions works as well, I figure. // Compounding proportions works as well, I figure.
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion()); retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
return retval; return retval;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Reference/Handle versions! // Reference/Handle versions!
void operator+=(wxSizer &target, wxWindow *src) void operator+=(wxSizer& target, wxWindow* src)
{ {
target.Add(src); target.Add(src);
} }
void operator+=(wxSizer &target, wxSizer *src) void operator+=(wxSizer& target, wxSizer* src)
{ {
target.Add(src); target.Add(src);
} }
void operator+=(wxSizer &target, wxWindow &src) void operator+=(wxSizer& target, wxWindow& src)
{ {
target.Add(&src); target.Add(&src);
} }
void operator+=(wxSizer &target, wxSizer &src) void operator+=(wxSizer& target, wxSizer& src)
{ {
target.Add(&src); target.Add(&src);
} }
void operator+=(wxSizer &target, int spacer) void operator+=(wxSizer& target, int spacer)
{ {
target.AddSpacer(spacer); target.AddSpacer(spacer);
} }
void operator+=(wxSizer &target, const pxStretchSpacer &spacer) void operator+=(wxSizer& target, const pxStretchSpacer& spacer)
{ {
target.AddStretchSpacer(spacer.proportion); target.AddStretchSpacer(spacer.proportion);
} }
void operator+=(wxWindow &target, int spacer) void operator+=(wxWindow& target, int spacer)
{ {
if (!pxAssert(target.GetSizer() != NULL)) if (!pxAssert(target.GetSizer() != NULL))
return; return;
target.GetSizer()->AddSpacer(spacer); target.GetSizer()->AddSpacer(spacer);
} }
void operator+=(wxWindow &target, const pxStretchSpacer &spacer) void operator+=(wxWindow& target, const pxStretchSpacer& spacer)
{ {
if (!pxAssert(target.GetSizer() != NULL)) if (!pxAssert(target.GetSizer() != NULL))
return; return;
target.GetSizer()->AddStretchSpacer(spacer.proportion); target.GetSizer()->AddStretchSpacer(spacer.proportion);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Pointer versions! (note that C++ requires one of the two operator params be a // Pointer versions! (note that C++ requires one of the two operator params be a
// "poper" object type (non-pointer), so that's why there's only a couple of these. // "poper" object type (non-pointer), so that's why there's only a couple of these.
void operator+=(wxSizer *target, wxWindow &src) void operator+=(wxSizer* target, wxWindow& src)
{ {
if (!pxAssert(target != NULL)) if (!pxAssert(target != NULL))
return; return;
target->Add(&src); target->Add(&src);
} }
void operator+=(wxSizer *target, wxSizer &src) void operator+=(wxSizer* target, wxSizer& src)
{ {
if (!pxAssert(target != NULL)) if (!pxAssert(target != NULL))
return; return;
target->Add(&src); target->Add(&src);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -194,23 +196,23 @@ void operator+=(wxSizer *target, wxSizer &src)
// Returns FALSE if the window position is considered invalid, which means that it's title // Returns FALSE if the window position is considered invalid, which means that it's title
// bar is most likely not easily grabble. Such a window should be moved to a valid or // bar is most likely not easily grabble. Such a window should be moved to a valid or
// default position. // default position.
bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos) bool pxIsValidWindowPosition(const wxWindow& window, const wxPoint& windowPos)
{ {
// The height of the window is only revlevant to the height of a title bar, which is // The height of the window is only revlevant to the height of a title bar, which is
// all we need visible for the user to be able to drag the window into view. But // all we need visible for the user to be able to drag the window into view. But
// there's no way to get that info from wx, so we'll just have to guesstimate... // there's no way to get that info from wx, so we'll just have to guesstimate...
const wxSize sizeMatters(window.GetSize().GetWidth(), 32); const wxSize sizeMatters(window.GetSize().GetWidth(), 32);
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++) for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
{ {
const auto rect = wxDisplay(i).GetGeometry(); const auto rect = wxDisplay(i).GetGeometry();
if (rect.Contains(wxRect(windowPos, sizeMatters))) if (rect.Contains(wxRect(windowPos, sizeMatters)))
return true; return true;
} }
return false; return false;
} }
// Retrieves the area of the screen, which can be used to enforce a valid zone for // Retrieves the area of the screen, which can be used to enforce a valid zone for
@ -218,7 +220,7 @@ bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos)
// is the resolution of the desktop). // is the resolution of the desktop).
wxRect wxGetDisplayArea() wxRect wxGetDisplayArea()
{ {
return wxRect(wxPoint(), wxGetDisplaySize()); return wxRect(wxPoint(), wxGetDisplaySize());
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -234,17 +236,17 @@ wxRect wxGetDisplayArea()
// //
wxSizerFlags pxSizerFlags::StdSpace() wxSizerFlags pxSizerFlags::StdSpace()
{ {
return wxSizerFlags().Border(wxALL, StdPadding); return wxSizerFlags().Border(wxALL, StdPadding);
} }
wxSizerFlags pxSizerFlags::StdCenter() wxSizerFlags pxSizerFlags::StdCenter()
{ {
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder(); return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
} }
wxSizerFlags pxSizerFlags::StdExpand() wxSizerFlags pxSizerFlags::StdExpand()
{ {
return StdSpace().Expand(); return StdSpace().Expand();
} }
// A good sizer flags setting for top-level static boxes or top-level picture boxes. // A good sizer flags setting for top-level static boxes or top-level picture boxes.
@ -252,7 +254,7 @@ wxSizerFlags pxSizerFlags::StdExpand()
// manually by using a spacer. // manually by using a spacer.
wxSizerFlags pxSizerFlags::TopLevelBox() wxSizerFlags pxSizerFlags::TopLevelBox()
{ {
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand(); return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand();
} }
// Flags intended for use on grouped StaticBox controls. These flags are ideal for // Flags intended for use on grouped StaticBox controls. These flags are ideal for
@ -261,9 +263,9 @@ wxSizerFlags pxSizerFlags::TopLevelBox()
// "tight"). // "tight").
wxSizerFlags pxSizerFlags::SubGroup() wxSizerFlags pxSizerFlags::SubGroup()
{ {
// Groups look better with a slightly smaller margin than standard. // Groups look better with a slightly smaller margin than standard.
// (basically this accounts for the group's frame) // (basically this accounts for the group's frame)
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand(); return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
} }
// This force-aligns the std button sizer to the right, where (at least) us win32 platform // This force-aligns the std button sizer to the right, where (at least) us win32 platform
@ -271,20 +273,20 @@ wxSizerFlags pxSizerFlags::SubGroup()
// just because it's *not* where win32 sticks it. Too bad! // just because it's *not* where win32 sticks it. Too bad!
wxSizerFlags pxSizerFlags::StdButton() wxSizerFlags pxSizerFlags::StdButton()
{ {
return pxBorder().Align(wxALIGN_RIGHT); return pxBorder().Align(wxALIGN_RIGHT);
} }
wxSizerFlags pxSizerFlags::Checkbox() wxSizerFlags pxSizerFlags::Checkbox()
{ {
return StdExpand(); return StdExpand();
} }
void pxSizerFlags::SetBestPadding() void pxSizerFlags::SetBestPadding()
{ {
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864) if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
StdPadding = 4; StdPadding = 4;
else else
StdPadding = 1; StdPadding = 1;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -293,44 +295,44 @@ void pxSizerFlags::SetBestPadding()
static bool is_cjk_char(const uint ch) static bool is_cjk_char(const uint ch)
{ {
/** /**
* You can check these range at http://unicode.org/charts/ * You can check these range at http://unicode.org/charts/
* see the "East Asian Scripts" part. * see the "East Asian Scripts" part.
* Notice that not all characters in that part is still in use today, so don't list them all here. * Notice that not all characters in that part is still in use today, so don't list them all here.
*/ */
// FIXME: add range from Japanese-specific and Korean-specific section if you know the // FIXME: add range from Japanese-specific and Korean-specific section if you know the
// characters are used today. // characters are used today.
if (ch < 0x2e80) if (ch < 0x2e80)
return false; // shortcut for common non-CJK return false; // shortcut for common non-CJK
return return
// Han Ideographs: all except Supplement // Han Ideographs: all except Supplement
(ch >= 0x4e00 && ch < 0x9fcf) || (ch >= 0x4e00 && ch < 0x9fcf) ||
(ch >= 0x3400 && ch < 0x4dbf) || (ch >= 0x3400 && ch < 0x4dbf) ||
(ch >= 0x20000 && ch < 0x2a6df) || (ch >= 0x20000 && ch < 0x2a6df) ||
(ch >= 0xf900 && ch < 0xfaff) || (ch >= 0xf900 && ch < 0xfaff) ||
(ch >= 0x3190 && ch < 0x319f) || (ch >= 0x3190 && ch < 0x319f) ||
// Radicals: all except Ideographic Description // Radicals: all except Ideographic Description
(ch >= 0x2e80 && ch < 0x2eff) || (ch >= 0x2e80 && ch < 0x2eff) ||
(ch >= 0x2f00 && ch < 0x2fdf) || (ch >= 0x2f00 && ch < 0x2fdf) ||
(ch >= 0x31c0 && ch < 0x31ef) || (ch >= 0x31c0 && ch < 0x31ef) ||
// Chinese-specific: Bopomofo // Chinese-specific: Bopomofo
(ch >= 0x3000 && ch < 0x303f) || (ch >= 0x3000 && ch < 0x303f) ||
// Japanese-specific: Halfwidth Katakana // Japanese-specific: Halfwidth Katakana
(ch >= 0xff00 && ch < 0xffef) || (ch >= 0xff00 && ch < 0xffef) ||
// Japanese-specific: Hiragana, Katakana // Japanese-specific: Hiragana, Katakana
(ch >= 0x3040 && ch <= 0x309f) || (ch >= 0x3040 && ch <= 0x309f) ||
(ch >= 0x30a0 && ch <= 0x30ff) || (ch >= 0x30a0 && ch <= 0x30ff) ||
// Korean-specific: Hangul Syllables, Halfwidth Jamo // Korean-specific: Hangul Syllables, Halfwidth Jamo
(ch >= 0xac00 && ch < 0xd7af) || (ch >= 0xac00 && ch < 0xd7af) ||
(ch >= 0xff00 && ch < 0xffef); (ch >= 0xff00 && ch < 0xffef);
} }
/* /*
@ -350,7 +352,7 @@ static bool is_cjk_char(const uint ch)
*/ */
static bool no_break_after(const uint ch) static bool no_break_after(const uint ch)
{ {
// clang-format off // clang-format off
switch (ch) { switch (ch) {
/** /**
* don't break after these Japanese/Chinese characters * don't break after these Japanese/Chinese characters
@ -366,14 +368,14 @@ static bool no_break_after(const uint ch)
return true; return true;
} }
// clang-format on // clang-format on
return false; return false;
} }
static bool no_break_before(const uint ch) static bool no_break_before(const uint ch)
{ {
// clang-format off // clang-format off
switch (ch) { switch (ch) {
/** /**
* don't break before these Japanese characters * don't break before these Japanese characters
@ -403,84 +405,94 @@ static bool no_break_before(const uint ch)
return true; return true;
} }
// clang-format on // clang-format on
return false; return false;
} }
pxTextWrapperBase &pxTextWrapperBase::Wrap(const wxWindow &win, const wxString &text, int widthMax) pxTextWrapperBase& pxTextWrapperBase::Wrap(const wxWindow& win, const wxString& text, int widthMax)
{ {
if (text.empty()) if (text.empty())
return *this; return *this;
bool wasWrapped = false; bool wasWrapped = false;
wxString line; wxString line;
line.reserve(text.length() + 12); line.reserve(text.length() + 12);
wxString::const_iterator lastSpace = text.end(); wxString::const_iterator lastSpace = text.end();
wxString::const_iterator lineStart = text.begin(); wxString::const_iterator lineStart = text.begin();
for (wxString::const_iterator p = lineStart;; ++p) { for (wxString::const_iterator p = lineStart;; ++p)
if (IsStartOfNewLine()) { {
OnNewLine(); if (IsStartOfNewLine())
{
OnNewLine();
lastSpace = text.end(); lastSpace = text.end();
lineStart = p; lineStart = p;
if (wasWrapped) if (wasWrapped)
line = m_indent; line = m_indent;
else else
line.clear(); line.clear();
} }
if (p == text.end() || *p == L'\n') { if (p == text.end() || *p == L'\n')
wasWrapped = false; {
DoOutputLine(line); wasWrapped = false;
DoOutputLine(line);
if (p == text.end()) if (p == text.end())
break; break;
} else { // not EOL }
if (is_cjk_char(*p)) { else
if (!no_break_before(*p)) { { // not EOL
if (p == lineStart || !no_break_after(*(p - 1))) if (is_cjk_char(*p))
lastSpace = p; {
} if (!no_break_before(*p))
} else if (*p == L' ' || *p == L',' || *p == L'/') {
lastSpace = p; if (p == lineStart || !no_break_after(*(p - 1)))
lastSpace = p;
}
}
else if (*p == L' ' || *p == L',' || *p == L'/')
lastSpace = p;
line += *p; line += *p;
if (widthMax >= 0 && lastSpace != text.end()) { if (widthMax >= 0 && lastSpace != text.end())
int width; {
win.GetTextExtent(line, &width, NULL); int width;
win.GetTextExtent(line, &width, NULL);
if (width > widthMax) { if (width > widthMax)
wasWrapped = true; {
wasWrapped = true;
// remove the last word from this line // remove the last word from this line
line.erase(lastSpace - lineStart, p + 1 - lineStart); line.erase(lastSpace - lineStart, p + 1 - lineStart);
DoOutputLine(line); DoOutputLine(line);
// go back to the last word of this line which we didn't // go back to the last word of this line which we didn't
// output yet // output yet
p = lastSpace; p = lastSpace;
if (*p != L' ') if (*p != L' ')
p--; p--;
} }
} }
//else: no wrapping at all or impossible to wrap //else: no wrapping at all or impossible to wrap
} }
} }
return *this; return *this;
} }
void pxTextWrapperBase::DoOutputLine(const wxString &line) void pxTextWrapperBase::DoOutputLine(const wxString& line)
{ {
OnOutputLine(line); OnOutputLine(line);
m_linecount++; m_linecount++;
m_eol = true; m_eol = true;
} }
// this function is a destructive inspector: when it returns true it also // this function is a destructive inspector: when it returns true it also
@ -488,34 +500,34 @@ void pxTextWrapperBase::DoOutputLine(const wxString &line)
// more // more
bool pxTextWrapperBase::IsStartOfNewLine() bool pxTextWrapperBase::IsStartOfNewLine()
{ {
if (!m_eol) if (!m_eol)
return false; return false;
m_eol = false; m_eol = false;
return true; return true;
} }
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow &win, const wxString &text, int widthMax) pxTextWrapper& pxTextWrapper::Wrap(const wxWindow& win, const wxString& text, int widthMax)
{ {
_parent::Wrap(win, text, widthMax); _parent::Wrap(win, text, widthMax);
return *this; return *this;
} }
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow *win, const wxString &text, int widthMax) pxTextWrapper& pxTextWrapper::Wrap(const wxWindow* win, const wxString& text, int widthMax)
{ {
if (win) if (win)
_parent::Wrap(*win, text, widthMax); _parent::Wrap(*win, text, widthMax);
return *this; return *this;
} }
void pxTextWrapper::OnOutputLine(const wxString &line) void pxTextWrapper::OnOutputLine(const wxString& line)
{ {
m_text += line; m_text += line;
} }
void pxTextWrapper::OnNewLine() void pxTextWrapper::OnNewLine()
{ {
m_text += L'\n'; m_text += L'\n';
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -527,67 +539,69 @@ BusyCursorType ScopedBusyCursor::m_defBusyType;
ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype) ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype)
{ {
pxAssert(wxTheApp != NULL); pxAssert(wxTheApp != NULL);
BusyCursorType curtype = Cursor_NotBusy; BusyCursorType curtype = Cursor_NotBusy;
if (!m_cursorStack.empty()) if (!m_cursorStack.empty())
curtype = m_cursorStack.top(); curtype = m_cursorStack.top();
if (curtype < busytype) if (curtype < busytype)
SetManualBusyCursor(curtype = busytype); SetManualBusyCursor(curtype = busytype);
m_cursorStack.push(curtype); m_cursorStack.push(curtype);
} }
ScopedBusyCursor::~ScopedBusyCursor() ScopedBusyCursor::~ScopedBusyCursor()
{ {
if (!pxAssert(wxTheApp != NULL)) if (!pxAssert(wxTheApp != NULL))
return; return;
if (!pxAssert(!m_cursorStack.empty())) { if (!pxAssert(!m_cursorStack.empty()))
SetManualBusyCursor(m_defBusyType); {
return; SetManualBusyCursor(m_defBusyType);
} return;
}
BusyCursorType curtype = m_cursorStack.top(); BusyCursorType curtype = m_cursorStack.top();
m_cursorStack.pop(); m_cursorStack.pop();
if (m_cursorStack.empty()) if (m_cursorStack.empty())
SetManualBusyCursor(m_defBusyType); SetManualBusyCursor(m_defBusyType);
else if (m_cursorStack.top() != curtype) else if (m_cursorStack.top() != curtype)
SetManualBusyCursor(m_cursorStack.top()); SetManualBusyCursor(m_cursorStack.top());
} }
void ScopedBusyCursor::SetDefault(BusyCursorType busytype) void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
{ {
if (busytype == m_defBusyType) if (busytype == m_defBusyType)
return; return;
m_defBusyType = busytype; m_defBusyType = busytype;
if (m_cursorStack.empty()) if (m_cursorStack.empty())
SetManualBusyCursor(busytype); SetManualBusyCursor(busytype);
} }
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype) void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
{ {
switch (busytype) { switch (busytype)
case Cursor_NotBusy: {
wxSetCursor(wxNullCursor); case Cursor_NotBusy:
break; wxSetCursor(wxNullCursor);
case Cursor_KindaBusy: break;
wxSetCursor(StockCursors.GetArrowWait()); case Cursor_KindaBusy:
break; wxSetCursor(StockCursors.GetArrowWait());
case Cursor_ReallyBusy: break;
wxSetCursor(*wxHOURGLASS_CURSOR); case Cursor_ReallyBusy:
break; wxSetCursor(*wxHOURGLASS_CURSOR);
} break;
}
} }
const wxCursor &MoreStockCursors::GetArrowWait() const wxCursor& MoreStockCursors::GetArrowWait()
{ {
if (!m_arrowWait) if (!m_arrowWait)
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT); m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
return *m_arrowWait; return *m_arrowWait;
} }
MoreStockCursors StockCursors; MoreStockCursors StockCursors;
@ -599,39 +613,39 @@ MoreStockCursors StockCursors;
// extends the tooltip time to the maximum possible. GTK seems to have indefinite // extends the tooltip time to the maximum possible. GTK seems to have indefinite
// tooltips, I don't know about OS X. // tooltips, I don't know about OS X.
void pxSetToolTip(wxWindow *wind, const wxString &src) void pxSetToolTip(wxWindow* wind, const wxString& src)
{ {
if (wind == NULL) if (wind == NULL)
return; // Silently ignore nulls return; // Silently ignore nulls
wind->SetToolTip(src); wind->SetToolTip(src);
// Make tooltips show for as long as possible on Windows. Linux (GTK) can // Make tooltips show for as long as possible on Windows. Linux (GTK) can
// show tooltips indefinitely. // show tooltips indefinitely.
#ifdef __WXMSW__ #ifdef __WXMSW__
wind->GetToolTip()->SetAutoPop(32767); wind->GetToolTip()->SetAutoPop(32767);
#endif #endif
} }
void pxSetToolTip(wxWindow &wind, const wxString &src) void pxSetToolTip(wxWindow& wind, const wxString& src)
{ {
pxSetToolTip(&wind, src); pxSetToolTip(&wind, src);
} }
wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline) wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline)
{ {
return wxFont( return wxFont(
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
#ifdef __WXMSW__ #ifdef __WXMSW__
, ,
L"Lucida Console" // better than courier new (win32 only) L"Lucida Console" // better than courier new (win32 only)
#endif #endif
); );
} }
wxString pxGetAppName() wxString pxGetAppName()
{ {
pxAssert(wxTheApp); pxAssert(wxTheApp);
return wxTheApp->GetAppName(); return wxTheApp->GetAppName();
} }

Some files were not shown because too many files have changed in this diff Show More