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/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
return aligned_alloc(align, size);
return aligned_alloc(align, size);
#else
void *result = 0;
posix_memalign(&result, align, size);
return result;
void* result = 0;
posix_memalign(&result, align, size);
return result;
#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) {
memcpy(newbuf, handle, std::min(old_size, new_size));
_aligned_free(handle);
}
return newbuf;
if (newbuf != NULL && handle != NULL)
{
memcpy(newbuf, handle, std::min(old_size, new_size));
_aligned_free(handle);
}
return newbuf;
}
__fi void _aligned_free(void *pmem)
__fi void _aligned_free(void* pmem)
{
free(pmem);
free(pmem);
}
#endif

View File

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

View File

@ -27,7 +27,7 @@
#endif
#ifndef wxNullChar
#define wxNullChar ((wxChar *)NULL)
#define wxNullChar ((wxChar*)NULL)
#endif
// 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
{
const wxChar *srcfile;
const FnChar_t *function;
const wxChar *condition;
int line;
const wxChar* srcfile;
const FnChar_t* function;
const wxChar* condition;
int line;
DiagnosticOrigin(const wxChar *_file, int _line, const FnChar_t *_func, const wxChar *_cond = NULL)
: srcfile(_file)
, function(_func)
, condition(_cond)
, line(_line)
{
}
DiagnosticOrigin(const wxChar* _file, int _line, const FnChar_t* _func, const wxChar* _cond = NULL)
: srcfile(_file)
, function(_func)
, condition(_cond)
, 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
// 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 *pxDoAssert;
extern pxDoAssertFnType* pxDoAssert;
// ----------------------------------------------------------------------------------------
// pxAssert / pxAssertDev
@ -159,11 +159,14 @@ extern pxDoAssertFnType *pxDoAssert;
#define pxAssumeDev(cond, msg) (__assume(cond))
#define pxFail(msg) \
do { \
} while (0)
do \
{ \
} while (0)
#define pxFailDev(msg) \
do { \
} while (0)
do \
{ \
} while (0)
#endif
@ -177,18 +180,18 @@ extern pxDoAssertFnType *pxDoAssert;
// IndexBoundsCheckDev.
#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), \
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), \
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), \
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
@ -201,9 +204,10 @@ extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
// * In debug/devel builds the default case will cause an assertion.
//
#ifndef jNO_DEFAULT
#define jNO_DEFAULT \
default: { \
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
break; \
}
#define jNO_DEFAULT \
default: \
{ \
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
break; \
}
#endif

View File

@ -15,62 +15,64 @@
#include "common/CheckedStaticBox.h"
CheckedStaticBox::CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title)
: wxPanelWithHelpers(parent, wxVERTICAL)
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
CheckedStaticBox::CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title)
: wxPanelWithHelpers(parent, wxVERTICAL)
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
{
*this += ThisToggle;
*this += ThisSizer | pxExpand;
*this += ThisToggle;
*this += ThisSizer | pxExpand;
// Ensure that the right-side of the static group box isn't too cozy:
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
// Ensure that the right-side of the static group box isn't too cozy:
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)
// 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());
evt.Skip();
SetValue(evt.IsChecked());
evt.Skip();
}
// Sets the main checkbox status, and enables/disables all child controls
// bound to the StaticBox accordingly.
void CheckedStaticBox::SetValue(bool val)
{
wxWindowList &list = GetChildren();
wxWindowList& list = GetChildren();
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
wxWindow *current = *iter;
if (current != &ThisToggle)
current->Enable(IsEnabled() && val);
}
ThisToggle.SetValue(val);
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
{
wxWindow* current = *iter;
if (current != &ThisToggle)
current->Enable(IsEnabled() && val);
}
ThisToggle.SetValue(val);
}
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
// the enable request are true. If not, disable them!
bool CheckedStaticBox::Enable(bool enable)
{
if (!_parent::Enable(enable))
return false;
if (!_parent::Enable(enable))
return false;
bool val = enable && ThisToggle.GetValue();
wxWindowList &list = GetChildren();
bool val = enable && ThisToggle.GetValue();
wxWindowList& list = GetChildren();
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
wxWindow *current = *iter;
if (current != &ThisToggle)
current->Enable(val);
}
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
{
wxWindow* current = *iter;
if (current != &ThisToggle)
current->Enable(val);
}
return true;
return true;
}

View File

@ -19,19 +19,19 @@
class CheckedStaticBox : public wxPanelWithHelpers
{
typedef wxPanelWithHelpers _parent;
typedef wxPanelWithHelpers _parent;
public:
wxBoxSizer &ThisSizer; // Boxsizer which holds all child items.
wxCheckBox &ThisToggle; // toggle which can enable/disable all child controls
wxBoxSizer& ThisSizer; // Boxsizer which holds all child items.
wxCheckBox& ThisToggle; // toggle which can enable/disable all child controls
public:
CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title = wxEmptyString);
CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title = wxEmptyString);
void SetValue(bool val);
bool GetValue() const;
bool Enable(bool enable = true);
void SetValue(bool val);
bool GetValue() const;
bool Enable(bool enable = true);
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);
#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
@ -41,33 +41,33 @@ void Console_SetStdout(FILE *fp)
// 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
// 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(
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
(writer.DoSetColor != NULL),
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
pxAssertDev(
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
(writer.DoSetColor != NULL),
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
Console = writer;
DevConWriter = writer;
Console = writer;
DevConWriter = writer;
#ifdef PCSX2_DEBUG
DbgCon = writer;
DbgCon = writer;
#endif
}
// Writes text to the Visual Studio Output window (Microsoft Windows only).
// 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__)
static bool hasDebugger = wxIsDebuggerRunning();
if (hasDebugger)
OutputDebugString(text);
static bool hasDebugger = wxIsDebuggerRunning();
if (hasDebugger)
OutputDebugString(text);
#else
fputs(text.utf8_str(), stdout_fp);
fflush(stdout_fp);
fputs(text.utf8_str(), stdout_fp);
fflush(stdout_fp);
#endif
}
@ -76,23 +76,23 @@ void MSW_OutputDebugString(const wxString &text)
// 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_Newline() {}
static void __concall ConsoleNull_DoWrite(const wxString &fmt) {}
static void __concall ConsoleNull_DoWriteLn(const wxString &fmt) {}
static void __concall ConsoleNull_DoWrite(const wxString& fmt) {}
static void __concall ConsoleNull_DoWriteLn(const wxString& fmt) {}
const IConsoleWriter ConsoleWriter_Null =
{
ConsoleNull_DoWrite,
ConsoleNull_DoWriteLn,
ConsoleNull_DoSetColor,
{
ConsoleNull_DoWrite,
ConsoleNull_DoWriteLn,
ConsoleNull_DoSetColor,
ConsoleNull_DoWrite,
ConsoleNull_Newline,
ConsoleNull_SetTitle,
ConsoleNull_DoWrite,
ConsoleNull_Newline,
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__)
static __fi const char *GetLinuxConsoleColor(ConsoleColors color)
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
{
switch (color) {
case Color_Black:
case Color_StrongBlack:
return "\033[30m\033[1m";
switch (color)
{
case Color_Black:
case Color_StrongBlack:
return "\033[30m\033[1m";
case Color_Red:
return "\033[31m";
case Color_StrongRed:
return "\033[31m\033[1m";
case Color_Red:
return "\033[31m";
case Color_StrongRed:
return "\033[31m\033[1m";
case Color_Green:
return "\033[32m";
case Color_StrongGreen:
return "\033[32m\033[1m";
case Color_Green:
return "\033[32m";
case Color_StrongGreen:
return "\033[32m\033[1m";
case Color_Yellow:
return "\033[33m";
case Color_StrongYellow:
return "\033[33m\033[1m";
case Color_Yellow:
return "\033[33m";
case Color_StrongYellow:
return "\033[33m\033[1m";
case Color_Blue:
return "\033[34m";
case Color_StrongBlue:
return "\033[34m\033[1m";
case Color_Blue:
return "\033[34m";
case Color_StrongBlue:
return "\033[34m\033[1m";
// No orange, so use magenta.
case Color_Orange:
case Color_Magenta:
return "\033[35m";
case Color_StrongOrange:
case Color_StrongMagenta:
return "\033[35m\033[1m";
// No orange, so use magenta.
case Color_Orange:
case Color_Magenta:
return "\033[35m";
case Color_StrongOrange:
case Color_StrongMagenta:
return "\033[35m\033[1m";
case Color_Cyan:
return "\033[36m";
case Color_StrongCyan:
return "\033[36m\033[1m";
case Color_Cyan:
return "\033[36m";
case Color_StrongCyan:
return "\033[36m\033[1m";
// Use 'white' instead of grey.
case Color_Gray:
case Color_White:
return "\033[37m";
case Color_StrongGray:
case Color_StrongWhite:
return "\033[37m\033[1m";
// Use 'white' instead of grey.
case Color_Gray:
case Color_White:
return "\033[37m";
case Color_StrongGray:
case Color_StrongWhite:
return "\033[37m\033[1m";
// On some other value being passed, clear any formatting.
case Color_Default:
default:
return "\033[0m";
}
// On some other value being passed, clear any formatting.
case Color_Default:
default:
return "\033[0m";
}
}
#endif
// 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.
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()
{
MSW_OutputDebugString(L"\n");
MSW_OutputDebugString(L"\n");
}
static void __concall ConsoleStdout_DoSetColor(ConsoleColors color)
{
#if defined(__unix__)
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
fflush(stdout_fp);
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
fflush(stdout_fp);
#endif
}
static void __concall ConsoleStdout_SetTitle(const wxString &title)
static void __concall ConsoleStdout_SetTitle(const wxString& title)
{
#if defined(__unix__)
fputs("\033]0;", stdout_fp);
fputs(title.utf8_str(), stdout_fp);
fputs("\007", stdout_fp);
fputs("\033]0;", stdout_fp);
fputs(title.utf8_str(), stdout_fp);
fputs("\007", stdout_fp);
#endif
}
const IConsoleWriter ConsoleWriter_Stdout =
{
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
ConsoleStdout_DoWriteLn,
ConsoleStdout_DoSetColor,
{
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
ConsoleStdout_DoWriteLn,
ConsoleStdout_DoSetColor,
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
ConsoleStdout_Newline,
ConsoleStdout_SetTitle,
0, // instance-level indentation (should always be 0)
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
ConsoleStdout_Newline,
ConsoleStdout_SetTitle,
0, // instance-level indentation (should always be 0)
};
// --------------------------------------------------------------------------------------
// 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 =
{
ConsoleAssert_DoWrite,
ConsoleAssert_DoWriteLn,
ConsoleNull_DoSetColor,
{
ConsoleAssert_DoWrite,
ConsoleAssert_DoWriteLn,
ConsoleNull_DoSetColor,
ConsoleNull_DoWrite,
ConsoleNull_Newline,
ConsoleNull_SetTitle,
ConsoleNull_DoWrite,
ConsoleNull_Newline,
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
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
// 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;
if (indent == 0)
return src;
const int indent = glob_indent + _imm_indentation;
if (indent == 0)
return src;
wxString result(src);
const wxString indentStr(L'\t', indent);
result.Replace(L"\n", L"\n" + indentStr);
return indentStr + result;
wxString result(src);
const wxString indentStr(L'\t', indent);
result.Replace(L"\n", L"\n" + indentStr);
return indentStr + result;
}
// 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
// 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;
pxAssert(conlog_Indent >= 0);
return *this;
conlog_Indent += tabcount;
pxAssert(conlog_Indent >= 0);
return *this;
}
IConsoleWriter IConsoleWriter::Indent(int tabcount) const
{
IConsoleWriter retval = *this;
retval._imm_indentation = tabcount;
return retval;
IConsoleWriter retval = *this;
retval._imm_indentation = tabcount;
return retval;
}
// Changes the active console color.
// This color will be unset by calls to colored text methods
// 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. ;)
if (color == Color_Current)
return *this;
// Ignore current color requests since, well, the current color is already set. ;)
if (color == Color_Current)
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)
DoSetColor(conlog_Color = color);
if (conlog_Color != color)
DoSetColor(conlog_Color = color);
return *this;
return *this;
}
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)
const IConsoleWriter &IConsoleWriter::ClearColor() const
const IConsoleWriter& IConsoleWriter::ClearColor() const
{
if (conlog_Color != DefaultConsoleColor)
DoSetColor(conlog_Color = DefaultConsoleColor);
if (conlog_Color != DefaultConsoleColor)
DoSetColor(conlog_Color = DefaultConsoleColor);
return *this;
return *this;
}
// --------------------------------------------------------------------------------------
// 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));
return false;
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
return false;
}
bool IConsoleWriter::WriteLn(const char *fmt, ...) const
bool IConsoleWriter::WriteLn(const char* fmt, ...) const
{
va_list args;
va_start(args, fmt);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, args);
va_end(args);
return false;
return false;
}
// --------------------------------------------------------------------------------------
// 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));
return false;
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
return false;
}
bool IConsoleWriter::WriteLn(const wxChar *fmt, ...) const
bool IConsoleWriter::WriteLn(const wxChar* fmt, ...) const
{
va_list args;
va_start(args, fmt);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt, 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_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt, 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
{
va_list args;
va_start(args, fmt);
FormatV(fmt.wx_str(), args);
va_end(args);
va_list args;
va_start(args, fmt);
FormatV(fmt.wx_str(), args);
va_end(args);
return false;
return false;
}
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const
{
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt.wx_str(), args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(color);
FormatV(fmt.wx_str(), args);
va_end(args);
return false;
return false;
}
bool IConsoleWriter::Error(const wxString fmt, ...) const
{
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt.wx_str(), args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongRed);
FormatV(fmt.wx_str(), args);
va_end(args);
return false;
return false;
}
bool IConsoleWriter::Warning(const wxString fmt, ...) const
{
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt.wx_str(), args);
va_end(args);
va_list args;
va_start(args, fmt);
ConsoleColorScope cs(Color_StrongOrange);
FormatV(fmt.wx_str(), args);
va_end(args);
return false;
return false;
}
@ -458,70 +459,73 @@ bool IConsoleWriter::Warning(const wxString fmt, ...) const
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
{
m_IsScoped = false;
m_newcolor = newcolor;
EnterScope();
m_IsScoped = false;
m_newcolor = newcolor;
EnterScope();
}
ConsoleColorScope::~ConsoleColorScope()
{
LeaveScope();
LeaveScope();
}
void ConsoleColorScope::EnterScope()
{
if (!m_IsScoped) {
m_old_color = Console.GetColor();
Console.SetColor(m_newcolor);
m_IsScoped = true;
}
if (!m_IsScoped)
{
m_old_color = Console.GetColor();
Console.SetColor(m_newcolor);
m_IsScoped = true;
}
}
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)
{
m_IsScoped = false;
m_amount = tabs;
EnterScope();
m_IsScoped = false;
m_amount = tabs;
EnterScope();
}
ConsoleIndentScope::~ConsoleIndentScope()
{
try {
LeaveScope();
}
DESTRUCTOR_CATCHALL
try
{
LeaveScope();
}
DESTRUCTOR_CATCHALL
}
void ConsoleIndentScope::EnterScope()
{
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
}
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)
{
m_old_color = Console.GetColor();
Console.SetIndent(m_tabsize = indent);
Console.SetColor(newcolor);
m_old_color = Console.GetColor();
Console.SetIndent(m_tabsize = indent);
Console.SetColor(newcolor);
}
ConsoleAttrScope::~ConsoleAttrScope()
{
try {
Console.SetColor(m_old_color);
Console.SetIndent(-m_tabsize);
}
DESTRUCTOR_CATCHALL
try
{
Console.SetColor(m_old_color);
Console.SetIndent(-m_tabsize);
}
DESTRUCTOR_CATCHALL
}
@ -552,31 +556,31 @@ NullConsoleWriter NullCon = {};
// Writes to the console using the specified color. This overrides the default color setting
// 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);
DoWrite(pxsFmtV(fmt, list).c_str());
return false;
ConsoleColorScope cs(color);
DoWrite(pxsFmtV(fmt, list).c_str());
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);
DoWrite(pxsFmtV(fmt, list).c_str());
return false;
ConsoleColorScope cs(color);
DoWrite(pxsFmtV(fmt, list).c_str());
return false;
}
// 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
// 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);
return false;
WriteV(DefaultColor, fmt, list);
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);
return false;
WriteV(DefaultColor, fmt, list);
return false;
}

View File

@ -15,40 +15,41 @@
#pragma once
#include "StringHelpers.h"
#include "common/StringHelpers.h"
enum ConsoleColors {
Color_Current = -1,
enum ConsoleColors
{
Color_Current = -1,
Color_Default = 0,
Color_Default = 0,
Color_Black,
Color_Green,
Color_Red,
Color_Blue,
Color_Magenta,
Color_Orange,
Color_Gray,
Color_Black,
Color_Green,
Color_Red,
Color_Blue,
Color_Magenta,
Color_Orange,
Color_Gray,
Color_Cyan, // 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_Cyan, // 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
// Strong text *may* result in mis-aligned text in the console, depending on the
// font and the platform, so use these with caution.
Color_StrongBlack,
Color_StrongRed, // intended for errors
Color_StrongGreen, // intended for infrequent state information
Color_StrongBlue, // intended for block headings
Color_StrongMagenta,
Color_StrongOrange, // intended for warnings
Color_StrongGray,
// Strong text *may* result in mis-aligned text in the console, depending on the
// font and the platform, so use these with caution.
Color_StrongBlack,
Color_StrongRed, // intended for errors
Color_StrongGreen, // intended for infrequent state information
Color_StrongBlue, // intended for block headings
Color_StrongMagenta,
Color_StrongOrange, // intended for warnings
Color_StrongGray,
Color_StrongCyan,
Color_StrongYellow,
Color_StrongWhite,
Color_StrongCyan,
Color_StrongYellow,
Color_StrongWhite,
ConsoleColors_Count
ConsoleColors_Count
};
static const ConsoleColors DefaultConsoleColor = Color_Default;
@ -70,60 +71,60 @@ static const ConsoleColors DefaultConsoleColor = Color_Default;
//
struct IConsoleWriter
{
// 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.
void(__concall *WriteRaw)(const wxString &fmt);
// 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.
void(__concall* WriteRaw)(const wxString& fmt);
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
// formatting.
void(__concall *DoWriteLn)(const wxString &fmt);
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
// formatting.
void(__concall* DoWriteLn)(const wxString& fmt);
// SetColor implementation for internal use only.
void(__concall *DoSetColor)(ConsoleColors color);
// SetColor implementation for internal use only.
void(__concall* DoSetColor)(ConsoleColors color);
// 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.
// (This avoids circular/recursive stdio output)
void(__concall *DoWriteFromStdout)(const wxString &fmt);
// 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.
// (This avoids circular/recursive stdio output)
void(__concall* DoWriteFromStdout)(const wxString& fmt);
void(__concall *Newline)();
void(__concall *SetTitle)(const wxString &title);
void(__concall* Newline)();
void(__concall* SetTitle)(const wxString& title);
// internal value for indentation of individual lines. Use the Indent() member to invoke.
int _imm_indentation;
// internal value for indentation of individual lines. Use the Indent() member to invoke.
int _imm_indentation;
// For internal use only.
wxString _addIndentation(const wxString &src, int glob_indent) const;
// For internal use only.
wxString _addIndentation(const wxString& src, int glob_indent) const;
// ----------------------------------------------------------------------------
// Public members; call these to print stuff to console!
//
// 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.
// ----------------------------------------------------------------------------
// Public members; call these to print stuff to console!
//
// 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.
ConsoleColors GetColor() const;
const IConsoleWriter &SetColor(ConsoleColors color) const;
const IConsoleWriter &ClearColor() const;
const IConsoleWriter &SetIndent(int tabcount = 1) const;
ConsoleColors GetColor() const;
const IConsoleWriter& SetColor(ConsoleColors color) const;
const IConsoleWriter& ClearColor() 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 WriteLn(ConsoleColors color, const char *fmt, ...) const;
bool WriteLn(const char *fmt, ...) const;
bool Error(const char *fmt, ...) const;
bool Warning(const char *fmt, ...) const;
bool FormatV(const char* fmt, va_list args) const;
bool WriteLn(ConsoleColors color, const char* fmt, ...) const;
bool WriteLn(const char* fmt, ...) const;
bool Error(const char* fmt, ...) const;
bool Warning(const char* fmt, ...) const;
bool FormatV(const wxChar *fmt, va_list args) const;
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const;
bool WriteLn(const wxChar *fmt, ...) const;
bool Error(const wxChar *fmt, ...) const;
bool Warning(const wxChar *fmt, ...) const;
bool FormatV(const wxChar* fmt, va_list args) const;
bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const;
bool WriteLn(const wxChar* fmt, ...) const;
bool Error(const wxChar* fmt, ...) const;
bool Warning(const wxChar* fmt, ...) const;
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
bool WriteLn(const wxString fmt, ...) const;
bool Error(const wxString fmt, ...) const;
bool Warning(const wxString fmt, ...) const;
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
bool WriteLn(const wxString fmt, ...) const;
bool Error(const wxString fmt, ...) const;
bool Warning(const wxString fmt, ...) const;
};
// --------------------------------------------------------------------------------------
@ -133,37 +134,37 @@ struct IConsoleWriter
//
struct NullConsoleWriter
{
void WriteRaw(const wxString &fmt) {}
void DoWriteLn(const wxString &fmt) {}
void DoSetColor(ConsoleColors color) {}
void DoWriteFromStdout(const wxString &fmt) {}
void Newline() {}
void SetTitle(const wxString &title) {}
void WriteRaw(const wxString& fmt) {}
void DoWriteLn(const wxString& fmt) {}
void DoSetColor(ConsoleColors color) {}
void DoWriteFromStdout(const wxString& fmt) {}
void Newline() {}
void SetTitle(const wxString& title) {}
ConsoleColors GetColor() const { return Color_Current; }
const NullConsoleWriter &SetColor(ConsoleColors color) const { return *this; }
const NullConsoleWriter &ClearColor() const { return *this; }
const NullConsoleWriter &SetIndent(int tabcount = 1) const { return *this; }
ConsoleColors GetColor() const { return Color_Current; }
const NullConsoleWriter& SetColor(ConsoleColors color) const { return *this; }
const NullConsoleWriter& ClearColor() 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 WriteLn(ConsoleColors color, const char *fmt, ...) const { return false; }
bool WriteLn(const char *fmt, ...) const { return false; }
bool Error(const char *fmt, ...) const { return false; }
bool Warning(const char *fmt, ...) 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(const char* fmt, ...) const { return false; }
bool Error(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 WriteLn(ConsoleColors color, const wxChar *fmt, ...) const { return false; }
bool WriteLn(const wxChar *fmt, ...) const { return false; }
bool Error(const wxChar *fmt, ...) const { return false; }
bool Warning(const wxChar *fmt, ...) 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(const wxChar* fmt, ...) const { return false; }
bool Error(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(const wxString fmt, ...) const { return false; }
bool Error(const wxString fmt, ...) const { return false; }
bool Warning(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 Error(const wxString fmt, ...) const { return false; }
bool Warning(const wxString fmt, ...) const { return false; }
};
// --------------------------------------------------------------------------------------
@ -179,19 +180,19 @@ struct NullConsoleWriter
//
class ConsoleIndentScope
{
DeclareNoncopyableObject(ConsoleIndentScope);
DeclareNoncopyableObject(ConsoleIndentScope);
protected:
int m_amount;
bool m_IsScoped;
int m_amount;
bool m_IsScoped;
public:
// 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.
ConsoleIndentScope(int tabs = 1);
virtual ~ConsoleIndentScope();
void EnterScope();
void LeaveScope();
// 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.
ConsoleIndentScope(int tabs = 1);
virtual ~ConsoleIndentScope();
void EnterScope();
void LeaveScope();
};
// --------------------------------------------------------------------------------------
@ -199,18 +200,18 @@ public:
// --------------------------------------------------------------------------------------
class ConsoleColorScope
{
DeclareNoncopyableObject(ConsoleColorScope);
DeclareNoncopyableObject(ConsoleColorScope);
protected:
ConsoleColors m_newcolor;
ConsoleColors m_old_color;
bool m_IsScoped;
ConsoleColors m_newcolor;
ConsoleColors m_old_color;
bool m_IsScoped;
public:
ConsoleColorScope(ConsoleColors newcolor);
virtual ~ConsoleColorScope();
void EnterScope();
void LeaveScope();
ConsoleColorScope(ConsoleColors newcolor);
virtual ~ConsoleColorScope();
void EnterScope();
void LeaveScope();
};
// --------------------------------------------------------------------------------------
@ -220,23 +221,23 @@ public:
//
class ConsoleAttrScope
{
DeclareNoncopyableObject(ConsoleAttrScope);
DeclareNoncopyableObject(ConsoleAttrScope);
protected:
ConsoleColors m_old_color;
int m_tabsize;
ConsoleColors m_old_color;
int m_tabsize;
public:
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
virtual ~ConsoleAttrScope();
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
virtual ~ConsoleAttrScope();
};
extern IConsoleWriter Console;
#if defined(__unix__) || defined(__APPLE__)
extern void Console_SetStdout(FILE *fp);
extern void Console_SetStdout(FILE* fp);
#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_Stdout;
@ -250,7 +251,7 @@ extern bool DevConWriterEnabled;
#ifdef PCSX2_DEVBUILD
#define DevCon DevConWriter
#else
#define DevCon DevConWriterEnabled &&DevConWriter
#define DevCon DevConWriterEnabled&& DevConWriter
#endif
#ifdef PCSX2_DEBUG

View File

@ -25,7 +25,7 @@
#include "common/Pcsx2Types.h"
#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
// the OS because of its BSD/Mach heritage. Helpfully, most of this code
@ -39,23 +39,25 @@
// failure (not supported by the operating system).
u64 GetPhysicalMemory()
{
static u64 mem = 0;
static u64 mem = 0;
// 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
// ensured by atomic operations with full-barriers (usually compiled
// down to XCHG on x86).
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) {
u64 getmem = 0;
size_t len = sizeof(getmem);
int mib[] = {CTL_HW, HW_MEMSIZE};
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) {
perror("sysctl:");
}
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
}
// 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
// ensured by atomic operations with full-barriers (usually compiled
// down to XCHG on x86).
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0)
{
u64 getmem = 0;
size_t len = sizeof(getmem);
int mib[] = {CTL_HW, HW_MEMSIZE};
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0)
{
perror("sysctl:");
}
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
}
return mem;
return mem;
}
void InitCPUTicks()
@ -72,26 +74,28 @@ void InitCPUTicks()
// GetTickFrequency() to maintain good precision.
u64 GetTickFrequency()
{
static u64 freq = 0;
static u64 freq = 0;
// by the time denom is not 0, the structure will have been fully
// updated and no more atomic accesses are necessary.
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) {
mach_timebase_info_data_t info;
// by the time denom is not 0, the structure will have been fully
// updated and no more atomic accesses are necessary.
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0)
{
mach_timebase_info_data_t info;
// 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
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
// which means GetCPUTicks is just nanoseconds).
if (mach_timebase_info(&info) != KERN_SUCCESS) {
abort();
}
// 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
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
// which means GetCPUTicks is just nanoseconds).
if (mach_timebase_info(&info) != KERN_SUCCESS)
{
abort();
}
// store the calculated value atomically
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
}
// store the calculated value atomically
__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
@ -100,53 +104,55 @@ u64 GetTickFrequency()
// nanoseconds.
u64 GetCPUTicks()
{
return mach_absolute_time();
return mach_absolute_time();
}
wxString GetOSVersionString()
{
wxString version;
static int initialized = 0;
wxString version;
static int initialized = 0;
// fetch the OS description only once (thread-safely)
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) {
char type[32] = {0};
char release[32] = {0};
char arch[32] = {0};
// fetch the OS description only once (thread-safely)
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0)
{
char type[32] = {0};
char release[32] = {0};
char arch[32] = {0};
#define SYSCTL_GET(var, base, name) \
do { \
int mib[] = {base, name}; \
size_t len = sizeof(var); \
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
} while (0)
#define SYSCTL_GET(var, base, name) \
do \
{ \
int mib[] = {base, name}; \
size_t len = sizeof(var); \
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
} while (0)
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
#undef SYSCTL_KERN
// I know strcat is not good, but stpcpy is not universally
// available yet.
char buf[128] = {0};
strcat(buf, type);
strcat(buf, " ");
strcat(buf, release);
strcat(buf, " ");
strcat(buf, arch);
// I know strcat is not good, but stpcpy is not universally
// available yet.
char buf[128] = {0};
strcat(buf, type);
strcat(buf, " ");
strcat(buf, release);
strcat(buf, " ");
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)
{
// no-op
// no-op
}
#endif

View File

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

View File

@ -29,27 +29,27 @@
__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
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()
{
// If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required).
__asm__("pause");
// If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required).
__asm__("pause");
}
__forceinline void Threading::EnableHiresScheduler()
{
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
// implemented yet though (and not sure if useful for pcsx2).
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
// implemented yet though (and not sure if useful for pcsx2).
}
__forceinline void Threading::DisableHiresScheduler()
{
// see EnableHiresScheduler()
// see EnableHiresScheduler()
}
// 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.
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
// microseconds, returns 0 on failure
static u64 getthreadtime(thread_port_t thread)
{
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info;
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
(thread_info_t)&info, &count);
if (kr != KERN_SUCCESS) {
return 0;
}
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
(thread_info_t)&info, &count);
if (kr != KERN_SUCCESS)
{
return 0;
}
// add system and user time
return (u64)info.user_time.seconds * (u64)1e6 +
(u64)info.user_time.microseconds +
(u64)info.system_time.seconds * (u64)1e6 +
(u64)info.system_time.microseconds;
// add system and user time
return (u64)info.user_time.seconds * (u64)1e6 +
(u64)info.user_time.microseconds +
(u64)info.system_time.seconds * (u64)1e6 +
(u64)info.system_time.microseconds;
}
// 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.
u64 Threading::GetThreadCpuTime()
{
// we could also use mach_thread_self() and mach_port_deallocate(), but
// that calls upon mach traps (kinda like system calls). Unless I missed
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
// to be user-space instead. In contract,
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
return us * 10ULL;
// we could also use mach_thread_self() and mach_port_deallocate(), but
// that calls upon mach traps (kinda like system calls). Unless I missed
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
// to be user-space instead. In contract,
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
return us * 10ULL;
}
u64 Threading::pxThread::GetCpuTime() const
{
// 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
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
if (!m_native_id) {
return 0;
}
// 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
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
if (!m_native_id)
{
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()
{
m_native_id = (uptr)mach_thread_self();
m_native_id = (uptr)mach_thread_self();
}
void Threading::pxThread::_platform_specific_OnCleanupInThread()
{
// cleanup of handles that were upened in
// _platform_specific_OnStartInThread
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
// cleanup of handles that were upened in
// _platform_specific_OnStartInThread
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
}
// 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

View File

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

View File

@ -25,8 +25,8 @@
class IEmbeddedImage
{
public:
virtual const wxImage &Get() = 0;
virtual wxImage Scale(int width, int height) = 0;
virtual const wxImage& Get() = 0;
virtual wxImage Scale(int width, int height) = 0;
};
//////////////////////////////////////////////////////////////////////////////////////////
@ -42,79 +42,80 @@ template <typename ImageType>
class EmbeddedImage : public IEmbeddedImage
{
protected:
wxImage m_Image;
const wxSize m_ResampleTo;
wxImage m_Image;
const wxSize m_ResampleTo;
protected:
// ------------------------------------------------------------------------
// Internal function used to ensure the image is loaded before returning the image
// handle (called from all methods that return an image handle).
//
void _loadImage()
{
if (!m_Image.Ok()) {
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
m_Image.LoadFile(joe, ImageType::GetFormat());
// ------------------------------------------------------------------------
// Internal function used to ensure the image is loaded before returning the image
// handle (called from all methods that return an image handle).
//
void _loadImage()
{
if (!m_Image.Ok())
{
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()))
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
}
}
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);
}
}
public:
EmbeddedImage()
: m_Image()
, m_ResampleTo(wxDefaultSize)
{
}
EmbeddedImage()
: m_Image()
, m_ResampleTo(wxDefaultSize)
{
}
// ------------------------------------------------------------------------
// Constructor for creating an embedded image that gets resampled to the specified size when
// loaded.
//
// 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-
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
// results.
//
EmbeddedImage(int newWidth, int newHeight)
: m_Image()
, m_ResampleTo(newWidth, newHeight)
{
}
// ------------------------------------------------------------------------
// Constructor for creating an embedded image that gets resampled to the specified size when
// loaded.
//
// 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-
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
// results.
//
EmbeddedImage(int newWidth, int newHeight)
: m_Image()
, m_ResampleTo(newWidth, newHeight)
{
}
// ------------------------------------------------------------------------
// 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
// 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
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
//
const wxImage &Get()
{
_loadImage();
return m_Image;
}
// ------------------------------------------------------------------------
// 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
// 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
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
//
const wxImage& Get()
{
_loadImage();
return m_Image;
}
wxIcon GetIcon()
{
wxIcon retval;
retval.CopyFromBitmap(Get());
return retval;
}
wxIcon GetIcon()
{
wxIcon retval;
retval.CopyFromBitmap(Get());
return retval;
}
// ------------------------------------------------------------------------
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
// is left unmodified).
//
// ------------------------------------------------------------------------
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
// is left unmodified).
//
wxImage Scale(int width, int height)
{
_loadImage();
// Not strictly necessary - wxWidgets does the dimensions check anyway.
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
else
return m_Image;
}
wxImage Scale(int width, int height)
{
_loadImage();
// Not strictly necessary - wxWidgets does the dimensions check anyway.
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
else
return m_Image;
}
};

View File

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

View File

@ -20,79 +20,92 @@
using Threading::ScopedLock;
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.
if (IsDebugBuild) {
ListenerIterator iter = m_listeners.begin();
while (iter != m_listeners.end()) {
if ((*iter) == &listener)
return iter;
++iter;
}
}
return _AddFast_without_lock(listener);
// Check for duplicates before adding the event.
if (IsDebugBuild)
{
ListenerIterator iter = m_listeners.begin();
while (iter != m_listeners.end())
{
if ((*iter) == &listener)
return iter;
++iter;
}
}
return _AddFast_without_lock(listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(ListenerType &listener)
void EventSource<ListenerType>::Remove(ListenerType& listener)
{
ScopedLock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.remove(&listener);
ScopedLock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.remove(&listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(const ListenerIterator &listenerHandle)
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
{
ScopedLock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.erase(listenerHandle);
ScopedLock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.erase(listenerHandle);
}
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_listeners.push_front(&listener);
return m_listeners.begin();
m_cache_valid = false;
m_listeners.push_front(&listener);
return m_listeners.begin();
}
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) {
try {
(*iter)->DispatchEvent(evtparams);
} catch (Exception::RuntimeError &ex) {
if (IsDevBuild) {
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
} else {
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
}
} 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;
}
while (iter != iend)
{
try
{
(*iter)->DispatchEvent(evtparams);
}
catch (Exception::RuntimeError& ex)
{
if (IsDevBuild)
{
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
}
else
{
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
}
}
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>
void EventSource<ListenerType>::Dispatch(const EvtParams &evtparams)
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
{
if (!m_cache_valid) {
m_cache_copy = m_listeners;
m_cache_valid = true;
}
if (!m_cache_valid)
{
m_cache_copy = m_listeners;
m_cache_valid = true;
}
if (m_cache_copy.empty())
return;
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
if (m_cache_copy.empty())
return;
_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.
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
// 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)
message.Write(" Function: %s\n", function);
if (function != NULL)
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)
message.Write(L" Condition: %ls\n", condition);
if (condition != NULL)
message.Write(L" Condition: %ls\n", condition);
if (msg != NULL)
message.Write(L" Message: %ls\n", msg);
if (msg != NULL)
message.Write(L" Message: %ls\n", msg);
return message;
return message;
}
@ -71,191 +71,196 @@ wxString DiagnosticOrigin::ToString(const wxChar *msg) const
void pxTrap()
{
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
__debugbreak();
__debugbreak();
#elif defined(__WXMAC__) && !defined(__DARWIN__)
#if __powerc
Debugger();
Debugger();
#else
SysBreak();
SysBreak();
#endif
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
Debugger();
Debugger();
#elif defined(__UNIX__)
raise(SIGTRAP);
raise(SIGTRAP);
#else
// TODO
#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() );
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
pxTrap();
return false;
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
pxTrap();
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
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
// 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.
RecursionGuard guard(s_assert_guard);
if (guard.Counter > 2) {
return pxTrap();
}
RecursionGuard guard(s_assert_guard);
if (guard.Counter > 2)
{
return pxTrap();
}
// 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
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
// PCSX2 itself is compiled in debug mode (assertions enabled).
// 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
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
// PCSX2 itself is compiled in debug mode (assertions enabled).
bool trapit;
bool trapit;
if (pxDoAssert == NULL) {
// Note: Format uses MSVC's syntax for output window hotlinking.
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
} else {
trapit = pxDoAssert(origin, msg.wc_str());
}
if (pxDoAssert == NULL)
{
// Note: Format uses MSVC's syntax for output window hotlinking.
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
}
else
{
trapit = pxDoAssert(origin, msg.wc_str());
}
if (trapit) {
pxTrap();
}
if (trapit)
{
pxTrap();
}
}
// --------------------------------------------------------------------------------------
// 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("");
return SetDiagMsg(msg_diag);
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
return SetDiagMsg(msg_diag);
}
BaseException &BaseException::SetDiagMsg(const wxString &msg_diag)
BaseException& BaseException::SetDiagMsg(const wxString& msg_diag)
{
m_message_diag = msg_diag;
return *this;
m_message_diag = msg_diag;
return *this;
}
BaseException &BaseException::SetUserMsg(const wxString &msg_user)
BaseException& BaseException::SetUserMsg(const wxString& msg_user)
{
m_message_user = msg_user;
return *this;
m_message_user = msg_user;
return *this;
}
wxString BaseException::FormatDiagnosticMessage() const
{
return m_message_diag;
return m_message_diag;
}
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::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",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
WX_STR(fromUTF8(ex.what()))));
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
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",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
WX_STR(fromUTF8(ex.what()))));
SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
WX_STR(fromUTF8(ex.what()))));
}
// --------------------------------------------------------------------------------------
// Exception::OutOfMemory (implementations)
// --------------------------------------------------------------------------------------
Exception::OutOfMemory::OutOfMemory(const wxString &allocdesc)
Exception::OutOfMemory::OutOfMemory(const wxString& allocdesc)
{
AllocDescription = allocdesc;
AllocDescription = allocdesc;
}
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
{
FastFormatUnicode retmsg;
retmsg.Write(L"Out of memory");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
FastFormatUnicode retmsg;
retmsg.Write(L"Out of memory");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
return retmsg;
return retmsg;
}
wxString Exception::OutOfMemory::FormatDisplayMessage() const
{
FastFormatUnicode retmsg;
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
FastFormatUnicode retmsg;
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
if (!m_message_user.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
if (!m_message_user.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
return retmsg;
return retmsg;
}
// --------------------------------------------------------------------------------------
// Exception::VirtualMemoryMapConflict (implementations)
// --------------------------------------------------------------------------------------
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString &allocdesc)
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString& 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.");
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.");
}
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
{
FastFormatUnicode retmsg;
retmsg.Write(L"Virtual memory map failed");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
FastFormatUnicode retmsg;
retmsg.Write(L"Virtual memory map failed");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
return retmsg;
return retmsg;
}
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
{
FastFormatUnicode retmsg;
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."));
FastFormatUnicode retmsg;
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."));
if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
return retmsg;
return retmsg;
}
// ------------------------------------------------------------------------
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
{
return L"Action canceled: " + m_message_diag;
return L"Action canceled: " + m_message_diag;
}
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
{
FastFormatUnicode retval;
_formatDiagMsg(retval);
return retval;
FastFormatUnicode retval;
_formatDiagMsg(retval);
return retval;
}
wxString Exception::BadStream::FormatDisplayMessage() const
{
FastFormatUnicode retval;
_formatUserMsg(retval);
return retval;
FastFormatUnicode retval;
_formatUserMsg(retval);
return retval;
}
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode &dest) const
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode& dest) const
{
dest.Write(L"Path: ");
if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName));
else
dest.Write(L"[Unnamed or unknown]");
dest.Write(L"Path: ");
if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName));
else
dest.Write(L"[Unnamed or unknown]");
if (!m_message_diag.IsEmpty())
dest.Write(L"\n%s", WX_STR(m_message_diag));
if (!m_message_diag.IsEmpty())
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: "));
if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName));
else
dest.Write(_("[Unnamed or unknown]"));
dest.Write(_("Path: "));
if (!StreamName.IsEmpty())
dest.Write(L"%s", WX_STR(StreamName));
else
dest.Write(_("[Unnamed or unknown]"));
if (!m_message_user.IsEmpty())
dest.Write(L"\n%s", WX_STR(m_message_user));
if (!m_message_user.IsEmpty())
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
{
FastFormatUnicode retval;
retval.Write("File could not be created.");
_formatDiagMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write("File could not be created.");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("A file could not be created."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write(_("A file could not be created."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
@ -324,19 +329,19 @@ wxString Exception::CannotCreateStream::FormatDisplayMessage() const
// --------------------------------------------------------------------------------------
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("File not found.\n");
_formatDiagMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write("File not found.\n");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::FileNotFound::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("File not found."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write(_("File not found."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
@ -344,19 +349,19 @@ wxString Exception::FileNotFound::FormatDisplayMessage() const
// --------------------------------------------------------------------------------------
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("Permission denied to file.\n");
_formatDiagMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write("Permission denied to file.\n");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::AccessDenied::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
@ -364,19 +369,19 @@ wxString Exception::AccessDenied::FormatDisplayMessage() const
// --------------------------------------------------------------------------------------
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("Unexpected end of file or stream.\n");
_formatDiagMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write("Unexpected end of file or stream.\n");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::EndOfStream::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
FastFormatUnicode retval;
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
retval.Write("\n");
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
@ -385,34 +390,35 @@ wxString Exception::EndOfStream::FormatDisplayMessage() const
// Translates an Errno code into an exception.
// 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) {
case EINVAL:
pxFailDev(L"Invalid argument");
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
switch (errcode)
{
case EINVAL:
pxFailDev(L"Invalid argument");
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
case EACCES: // Access denied!
return new Exception::AccessDenied(streamname);
case EACCES: // Access denied!
return new Exception::AccessDenied(streamname);
case EMFILE: // Too many open files!
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EMFILE: // Too many open files!
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EEXIST:
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
case EEXIST:
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
case ENOENT: // File not found!
return new Exception::FileNotFound(streamname);
case ENOENT: // File not found!
return new Exception::FileNotFound(streamname);
case EPIPE:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
case EPIPE:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
case EBADF:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
case EBADF:
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
default:
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
}
default:
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.
//
// Note: Console can also fire an Exception::OutOfMemory
#define __DESTRUCTOR_CATCHALL(funcname) \
catch (BaseException & ex) \
{ \
try { \
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
Console.Error(ex.FormatDiagnosticMessage()); \
} catch (...) { \
fprintf(stderr, "ERROR: (out of memory?)\n"); \
} \
} \
catch (std::exception & ex) \
{ \
try { \
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
Console.Error(ex.what()); \
} catch (...) { \
fprintf(stderr, "ERROR: (out of memory?)\n"); \
} \
} \
catch (...) \
{ \
/* Unreachable code */ \
}
#define __DESTRUCTOR_CATCHALL(funcname) \
catch (BaseException & ex) \
{ \
try \
{ \
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
Console.Error(ex.FormatDiagnosticMessage()); \
} \
catch (...) \
{ \
fprintf(stderr, "ERROR: (out of memory?)\n"); \
} \
} \
catch (std::exception & ex) \
{ \
try \
{ \
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
Console.Error(ex.what()); \
} \
catch (...) \
{ \
fprintf(stderr, "ERROR: (out of memory?)\n"); \
} \
} \
catch (...) \
{ \
/* Unreachable code */ \
}
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
namespace Exception
{
class BaseException;
class BaseException;
int MakeNewType();
BaseException *FromErrno(const wxString &streamname, int errcode);
int MakeNewType();
BaseException* FromErrno(const wxString& streamname, int errcode);
// --------------------------------------------------------------------------------------
// BaseException
// --------------------------------------------------------------------------------------
// 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
// 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.
// Use Exception::RuntimeError instead for generic exceptions.
//
// Because exceptions are the (only!) really useful example of multiple inheritance,
// 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
// is, by design, a lot of fail, especially when class initializers are mixed in.
//
// [TODO] : Add an InnerException component, and Clone() facility.
//
class BaseException
{
protected:
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!
// --------------------------------------------------------------------------------------
// BaseException
// --------------------------------------------------------------------------------------
// 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
// 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.
// Use Exception::RuntimeError instead for generic exceptions.
//
// Because exceptions are the (only!) really useful example of multiple inheritance,
// 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
// is, by design, a lot of fail, especially when class initializers are mixed in.
//
// [TODO] : Add an InnerException component, and Clone() facility.
//
class BaseException
{
protected:
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!
public:
virtual ~BaseException() = default;
public:
virtual ~BaseException() = default;
const wxString &DiagMsg() const { return m_message_diag; }
const wxString &UserMsg() const { return m_message_user; }
const wxString& DiagMsg() const { return m_message_diag; }
const wxString& UserMsg() const { return m_message_user; }
wxString &DiagMsg() { return m_message_diag; }
wxString &UserMsg() { return m_message_user; }
wxString& DiagMsg() { return m_message_diag; }
wxString& UserMsg() { return m_message_user; }
BaseException &SetBothMsgs(const wxChar *msg_diag);
BaseException &SetDiagMsg(const wxString &msg_diag);
BaseException &SetUserMsg(const wxString &msg_user);
BaseException& SetBothMsgs(const wxChar* msg_diag);
BaseException& SetDiagMsg(const wxString& msg_diag);
BaseException& SetUserMsg(const wxString& msg_user);
// Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace.
virtual wxString FormatDiagnosticMessage() const;
// Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace.
virtual wxString FormatDiagnosticMessage() const;
// Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such.
virtual wxString FormatDisplayMessage() const;
// Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such.
virtual wxString FormatDisplayMessage() const;
virtual void Rethrow() const = 0;
virtual BaseException *Clone() const = 0;
};
virtual void Rethrow() const = 0;
virtual BaseException* Clone() const = 0;
};
typedef std::unique_ptr<BaseException> ScopedExcept;
typedef std::unique_ptr<BaseException> ScopedExcept;
// --------------------------------------------------------------------------------------
// Ps2Generic Exception
// --------------------------------------------------------------------------------------
// 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
// catch block hierarchies to handle them (if needed).
//
// Translation Note: Currently these exceptions are never translated. English/diagnostic
// format only. :)
//
class Ps2Generic
{
protected:
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
// --------------------------------------------------------------------------------------
// Ps2Generic Exception
// --------------------------------------------------------------------------------------
// 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
// catch block hierarchies to handle them (if needed).
//
// Translation Note: Currently these exceptions are never translated. English/diagnostic
// format only. :)
//
class Ps2Generic
{
protected:
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
public:
virtual ~Ps2Generic() = default;
public:
virtual ~Ps2Generic() = default;
virtual u32 GetPc() const = 0;
virtual bool IsDelaySlot() const = 0;
virtual wxString &Message() { return m_message; }
virtual u32 GetPc() const = 0;
virtual bool IsDelaySlot() const = 0;
virtual wxString& Message() { return m_message; }
virtual void Rethrow() const = 0;
virtual Ps2Generic *Clone() const = 0;
};
virtual void Rethrow() const = 0;
virtual Ps2Generic* Clone() const = 0;
};
// Some helper macros for defining the standard constructors of internationalized constructors
// Parameters:
@ -157,240 +163,254 @@ public:
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
//
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
private: \
typedef parent _parent; \
\
public: \
virtual ~classname() = default; \
virtual void Rethrow() const { throw * this; } \
virtual classname *Clone() const { return new classname(*this); }
private: \
typedef parent _parent; \
\
public: \
virtual ~classname() = default; \
\
virtual void Rethrow() const \
{ \
throw *this; \
} \
\
virtual classname* Clone() const \
{ \
return new classname(*this); \
}
#define DEFINE_EXCEPTION_MESSAGES(classname) \
public: \
classname &SetBothMsgs(const wxChar *msg_diag) \
{ \
BaseException::SetBothMsgs(msg_diag); \
return *this; \
} \
classname &SetDiagMsg(const wxString &msg_diag) \
{ \
m_message_diag = msg_diag; \
return *this; \
} \
classname &SetUserMsg(const wxString &msg_user) \
{ \
m_message_user = msg_user; \
return *this; \
}
#define DEFINE_EXCEPTION_MESSAGES(classname) \
public: \
classname& SetBothMsgs(const wxChar* msg_diag) \
{ \
BaseException::SetBothMsgs(msg_diag); \
return *this; \
} \
\
classname& SetDiagMsg(const wxString& msg_diag) \
{ \
m_message_diag = msg_diag; \
return *this; \
} \
\
classname& SetUserMsg(const wxString& msg_user) \
{ \
m_message_user = msg_user; \
return *this; \
}
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
classname() { SetDiagMsg(message); } \
DEFINE_EXCEPTION_MESSAGES(classname)
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
classname() \
{ \
SetDiagMsg(message); \
} \
DEFINE_EXCEPTION_MESSAGES(classname)
// ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits!
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits!
// ---------------------------------------------------------------------------------------
class RuntimeError : public BaseException
{
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
class RuntimeError : public BaseException
{
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
public:
bool IsSilent;
public:
bool IsSilent;
RuntimeError() { IsSilent = false; }
RuntimeError(const std::runtime_error &ex, const wxString &prefix = wxEmptyString);
RuntimeError(const std::exception &ex, const wxString &prefix = wxEmptyString);
};
RuntimeError() { IsSilent = false; }
RuntimeError(const std::runtime_error& 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
// --------------------------------------------------------------------------------------
// 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
// log, and resumes messages queue processing).
//
// 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.
class CancelEvent : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given."))
// --------------------------------------------------------------------------------------
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
// --------------------------------------------------------------------------------------
// 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
// log, and resumes messages queue processing).
//
// 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.
class CancelEvent : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, pxLt("No reason given."))
public:
explicit CancelEvent(const wxString &logmsg)
{
m_message_diag = logmsg;
// overridden message formatters only use the diagnostic version...
}
public:
explicit CancelEvent(const wxString& logmsg)
{
m_message_diag = logmsg;
// overridden message formatters only use the diagnostic version...
}
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
// ---------------------------------------------------------------------------------------
// OutOfMemory
// ---------------------------------------------------------------------------------------
// 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
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
// where %s is filled in with the block name.
//
// The user string is not custom-formatted, and should contain *NO* %s tags.
//
class OutOfMemory : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString)
// ---------------------------------------------------------------------------------------
// OutOfMemory
// ---------------------------------------------------------------------------------------
// 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
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
// where %s is filled in with the block name.
//
// The user string is not custom-formatted, and should contain *NO* %s tags.
//
class OutOfMemory : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, wxEmptyString)
public:
wxString AllocDescription;
public:
wxString AllocDescription;
public:
OutOfMemory(const wxString &allocdesc);
public:
OutOfMemory(const wxString& allocdesc);
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
class ParseError : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
};
class ParseError : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
};
// ---------------------------------------------------------------------------------------
// Hardware/OS Exceptions:
// HardwareDeficiency / VirtualMemoryMapConflict
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// Hardware/OS Exceptions:
// HardwareDeficiency / VirtualMemoryMapConflict
// ---------------------------------------------------------------------------------------
// 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
// we'd really like to have access to.
class VirtualMemoryMapConflict : public OutOfMemory
{
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString)
// 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
// we'd really like to have access to.
class VirtualMemoryMapConflict : public OutOfMemory
{
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, wxEmptyString)
VirtualMemoryMapConflict(const wxString &allocdesc);
VirtualMemoryMapConflict(const wxString& allocdesc);
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
class HardwareDeficiency : public RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
};
class HardwareDeficiency : public RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
};
// ---------------------------------------------------------------------------------------
// Streaming (file) Exceptions:
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// Streaming (file) Exceptions:
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// ---------------------------------------------------------------------------------------
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
virtual classname &SetStreamName(const wxString &name) \
{ \
StreamName = name; \
return *this; \
} \
virtual classname &SetStreamName(const char *name) \
{ \
StreamName = fromUTF8(name); \
return *this; \
}
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
virtual classname& SetStreamName(const wxString& name) \
{ \
StreamName = name; \
return *this; \
} \
\
virtual classname& SetStreamName(const char* name) \
{ \
StreamName = fromUTF8(name); \
return *this; \
}
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
classname(const wxString &filename) \
{ \
StreamName = filename; \
} \
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
classname(const wxString& filename) \
{ \
StreamName = filename; \
} \
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
// 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
// data after the stream was successfully opened.
//
class BadStream : public RuntimeError
{
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
// 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
// data after the stream was successfully opened.
//
class BadStream : public RuntimeError
{
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
public:
wxString StreamName; // name of the stream (if applicable)
public:
wxString StreamName; // name of the stream (if applicable)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
protected:
void _formatDiagMsg(FastFormatUnicode &dest) const;
void _formatUserMsg(FastFormatUnicode &dest) const;
};
protected:
void _formatDiagMsg(FastFormatUnicode& dest) const;
void _formatUserMsg(FastFormatUnicode& dest) const;
};
// A generic exception for odd-ball stream creation errors.
//
class CannotCreateStream : public BadStream
{
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
// A generic exception for odd-ball stream creation errors.
//
class CannotCreateStream : public BadStream
{
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
// Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid)
//
class FileNotFound : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
// Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid)
//
class FileNotFound : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
class AccessDenied : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
class AccessDenied : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
// EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks.
//
class EndOfStream : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
// EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks.
//
class EndOfStream : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
#ifdef __WXMSW__
// --------------------------------------------------------------------------------------
// Exception::WinApiError
// --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(WinApiError)
// --------------------------------------------------------------------------------------
// Exception::WinApiError
// --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(WinApiError)
public:
int ErrorId;
public:
int ErrorId;
public:
WinApiError();
public:
WinApiError();
wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
#endif
}
} // namespace Exception
using Exception::BaseException;
using Exception::ScopedExcept;

View File

@ -33,88 +33,88 @@ template class SafeAlignedArray<u8, 16>;
// system deadlock.
static const int MaxFormattedStringLength = 0x80000;
static
#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
void
format_that_ascii_mess(CharBufferType &buffer, uint writepos, const char *fmt, va_list argptr)
{
va_list args;
while (true) {
int size = buffer.GetLength();
va_list args;
while (true)
{
int size = buffer.GetLength();
va_copy(args, argptr);
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
va_end(args);
va_copy(args, argptr);
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
va_end(args);
// some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so
// always do it manually
buffer[size - 1] = '\0';
// some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so
// always do it manually
buffer[size - 1] = '\0';
if (size >= MaxFormattedStringLength)
break;
if (size >= MaxFormattedStringLength)
break;
// vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98)
// vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98)
if (len < 0)
len = size + (size / 4);
if (len < 0)
len = size + (size / 4);
len += writepos;
if (len < size)
break;
buffer.Resize(len + 128);
};
len += writepos;
if (len < size)
break;
buffer.Resize(len + 128);
};
// 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.
// 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.
}
// returns the length of the formatted string, in characters (wxChars).
static
#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
uint
format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr)
{
va_list args;
while (true) {
int size = buffer.GetLength() / sizeof(wxChar);
va_list args;
while (true)
{
int size = buffer.GetLength() / sizeof(wxChar);
va_copy(args, argptr);
int len = wxVsnprintf((wxChar *)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
va_end(args);
va_copy(args, argptr);
int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
va_end(args);
// some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so
// always do it manually
((wxChar *)buffer.GetPtr())[size - 1] = L'\0';
// some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so
// always do it manually
((wxChar*)buffer.GetPtr())[size - 1] = L'\0';
if (size >= MaxFormattedStringLength)
return size - 1;
if (size >= MaxFormattedStringLength)
return size - 1;
// vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98)
// vsnprintf() may return either -1 (traditional Unix behavior) or the
// total number of characters which would have been written if the
// buffer were large enough (newer standards such as Unix98)
if (len < 0)
len = size + (size / 4);
if (len < 0)
len = size + (size / 4);
len += writepos;
if (len < size)
return len;
buffer.Resize((len + 128) * sizeof(wxChar));
};
len += writepos;
if (len < size)
return len;
buffer.Resize((len + 128) * sizeof(wxChar));
};
// 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.
// 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.
pxAssume(false);
return 0; // unreachable.
pxAssume(false);
return 0; // unreachable.
}
// --------------------------------------------------------------------------------------
@ -127,124 +127,124 @@ static
// this class nicely in its current state. --air
FastFormatUnicode::FastFormatUnicode()
: m_dest(2048)
: m_dest(2048)
{
Clear();
Clear();
}
void FastFormatUnicode::Clear()
{
m_Length = 0;
((wxChar *)m_dest.GetPtr())[0] = 0;
m_Length = 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 convLen = converted.Length();
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
memcpy(&((wxChar *)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
m_Length += convLen;
const uint inspos = m_Length;
const uint convLen = converted.Length();
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
memcpy(&((wxChar*)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
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);
return *this;
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
return *this;
}
FastFormatUnicode &FastFormatUnicode::Write(const char *fmt, ...)
FastFormatUnicode& FastFormatUnicode::Write(const char* fmt, ...)
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
}
FastFormatUnicode &FastFormatUnicode::Write(const wxChar *fmt, ...)
FastFormatUnicode& FastFormatUnicode::Write(const wxChar* fmt, ...)
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
}
FastFormatUnicode &FastFormatUnicode::Write(const wxString fmt, ...)
FastFormatUnicode& FastFormatUnicode::Write(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
WriteV(fmt.wx_str(), list);
va_end(list);
return *this;
va_list list;
va_start(list, fmt);
WriteV(fmt.wx_str(), list);
va_end(list);
return *this;
}
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();
for (uint i = 0; i < m_Length; ++i, ++ch)
*ch = (wxChar)wxToupper(*ch);
wxChar* ch = (wxChar*)m_dest.GetPtr();
for (uint i = 0; i < m_Length; ++i, ++ch)
*ch = (wxChar)wxToupper(*ch);
return *this;
return *this;
}
FastFormatUnicode &FastFormatUnicode::ToLower()
FastFormatUnicode& FastFormatUnicode::ToLower()
{
wxChar *ch = (wxChar *)m_dest.GetPtr();
for (uint i = 0; i < m_Length; ++i, ++ch)
*ch = (wxChar)wxTolower(*ch);
wxChar* ch = (wxChar*)m_dest.GetPtr();
for (uint i = 0; i < m_Length; ++i, ++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)));
return *this;
Write(L"%s", WX_STR(fromUTF8(psz)));
return *this;
}
wxString &operator+=(wxString &str1, const FastFormatUnicode &str2)
wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
{
str1.Append(str2.c_str(), str2.Length());
return str1;
str1.Append(str2.c_str(), str2.Length());
return str1;
}
wxString operator+(const wxString &str1, const FastFormatUnicode &str2)
wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
{
wxString s = str1;
s += str2;
return s;
wxString s = str1;
s += str2;
return s;
}
wxString operator+(const wxChar *str1, const FastFormatUnicode &str2)
wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
{
wxString s = str1;
s += str2;
return s;
wxString s = str1;
s += str2;
return s;
}
wxString operator+(const FastFormatUnicode &str1, const wxString &str2)
wxString operator+(const FastFormatUnicode& str1, const wxString& str2)
{
wxString s = str1;
s += str2;
return s;
wxString s = str1;
s += str2;
return s;
}
wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
wxString operator+(const FastFormatUnicode& str1, const wxChar* str2)
{
wxString s = str1;
s += str2;
return s;
wxString s = str1;
s += str2;
return s;
}
@ -252,38 +252,38 @@ wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
// FastFormatAscii (implementations)
// --------------------------------------------------------------------------------------
FastFormatAscii::FastFormatAscii()
: m_dest(2048)
: m_dest(2048)
{
Clear();
Clear();
}
void FastFormatAscii::Clear()
{
m_dest.GetPtr()[0] = 0;
m_dest.GetPtr()[0] = 0;
}
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);
return *this;
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
return *this;
}
FastFormatAscii &FastFormatAscii::Write(const char *fmt, ...)
FastFormatAscii& FastFormatAscii::Write(const char* fmt, ...)
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return *this;
}
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.
//
#define BITFIELD32() \
union \
{ \
u32 bitset; \
struct \
{
union \
{ \
u32 bitset; \
struct \
{
#define BITFIELD_END \
} \
; \
} \
;
}; \
};
// ----------------------------------------------------------------------------------------
@ -52,20 +50,20 @@
class RecursionGuard
{
public:
int &Counter;
int& Counter;
RecursionGuard(int &counter)
: Counter(counter)
{
++Counter;
}
RecursionGuard(int& counter)
: Counter(counter)
{
++Counter;
}
virtual ~RecursionGuard()
{
--Counter;
}
virtual ~RecursionGuard()
{
--Counter;
}
bool IsReentrant() const { return Counter > 1; }
bool IsReentrant() const { return Counter > 1; }
};
// --------------------------------------------------------------------------------------
@ -74,30 +72,30 @@ public:
class IActionInvocation
{
public:
virtual ~IActionInvocation() = default;
virtual void InvokeAction() = 0;
virtual ~IActionInvocation() = default;
virtual void InvokeAction() = 0;
};
class ICloneable
{
public:
virtual ICloneable *Clone() const = 0;
virtual ICloneable* Clone() const = 0;
};
class IDeletableObject
{
public:
virtual ~IDeletableObject() = default;
virtual ~IDeletableObject() = default;
virtual void DeleteSelf() = 0;
virtual bool IsBeingDeleted() = 0;
virtual void DeleteSelf() = 0;
virtual bool IsBeingDeleted() = 0;
protected:
// 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
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?).
virtual void DoDeletion() = 0;
// 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
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?).
virtual void DoDeletion() = 0;
};
// --------------------------------------------------------------------------------------
@ -126,26 +124,26 @@ protected:
class BaseDeletableObject : public virtual IDeletableObject
{
protected:
std::atomic<bool> m_IsBeingDeleted;
std::atomic<bool> m_IsBeingDeleted;
public:
BaseDeletableObject();
virtual ~BaseDeletableObject();
BaseDeletableObject();
virtual ~BaseDeletableObject();
void DeleteSelf();
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
void DeleteSelf();
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
// 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
// the object could get deleted twice if two threads try to schedule it at the same time.
bool MarkForDeletion();
// 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
// the object could get deleted twice if two threads try to schedule it at the same time.
bool MarkForDeletion();
protected:
// 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
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?).
virtual void DoDeletion();
// 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
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?).
virtual void DoDeletion();
};
// --------------------------------------------------------------------------------------
@ -154,76 +152,76 @@ protected:
class PageProtectionMode
{
protected:
bool m_read;
bool m_write;
bool m_exec;
bool m_read;
bool m_write;
bool m_exec;
public:
PageProtectionMode()
{
All(false);
}
PageProtectionMode()
{
All(false);
}
PageProtectionMode &Read(bool allow = true)
{
m_read = allow;
return *this;
}
PageProtectionMode& Read(bool allow = true)
{
m_read = allow;
return *this;
}
PageProtectionMode &Write(bool allow = true)
{
m_write = allow;
return *this;
}
PageProtectionMode& Write(bool allow = true)
{
m_write = allow;
return *this;
}
PageProtectionMode &Execute(bool allow = true)
{
m_exec = allow;
return *this;
}
PageProtectionMode& Execute(bool allow = true)
{
m_exec = allow;
return *this;
}
PageProtectionMode &All(bool allow = true)
{
m_read = m_write = m_exec = allow;
return *this;
}
PageProtectionMode& All(bool allow = true)
{
m_read = m_write = m_exec = allow;
return *this;
}
bool CanRead() const { return m_read; }
bool CanWrite() const { return m_write; }
bool CanExecute() const { return m_exec && m_read; }
bool IsNone() const { return !m_read && !m_write; }
bool CanRead() const { return m_read; }
bool CanWrite() const { return m_write; }
bool CanExecute() const { return m_exec && m_read; }
bool IsNone() const { return !m_read && !m_write; }
wxString ToString() const;
wxString ToString() const;
};
static __fi PageProtectionMode PageAccess_None()
{
return PageProtectionMode();
return PageProtectionMode();
}
static __fi PageProtectionMode PageAccess_ReadOnly()
{
return PageProtectionMode().Read();
return PageProtectionMode().Read();
}
static __fi PageProtectionMode PageAccess_WriteOnly()
{
return PageProtectionMode().Write();
return PageProtectionMode().Write();
}
static __fi PageProtectionMode PageAccess_ReadWrite()
{
return PageAccess_ReadOnly().Write();
return PageAccess_ReadOnly().Write();
}
static __fi PageProtectionMode PageAccess_ExecOnly()
{
return PageAccess_ReadOnly().Execute();
return PageAccess_ReadOnly().Execute();
}
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)
namespace HostSys
{
void *MmapReserve(uptr base, size_t size);
bool MmapCommit(uptr base, size_t size, const PageProtectionMode &mode);
void MmapReset(uptr base, size_t size);
void* MmapReserve(uptr base, size_t size);
bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
void MmapReset(uptr base, size_t size);
void *MmapReservePtr(void *base, size_t size);
bool MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode);
void MmapResetPtr(void *base, size_t size);
void* MmapReservePtr(void* base, size_t size);
bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
void MmapResetPtr(void* base, size_t size);
// Maps a block of memory for use as a recompiled code buffer.
// Returns NULL on allocation failure.
extern void *Mmap(uptr base, size_t size);
// Maps a block of memory for use as a recompiled code buffer.
// Returns NULL on allocation failure.
extern void* Mmap(uptr base, size_t size);
// Unmaps a block allocated by SysMmap
extern void Munmap(uptr base, size_t size);
// Unmaps a block allocated by SysMmap
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>
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode &mode)
{
MemProtect(arr, size, mode);
}
}
template <uint size>
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode& mode)
{
MemProtect(arr, size, mode);
}
} // namespace HostSys
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
#define SafeSysMunmap(ptr, size) \
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
extern void InitCPUTicks();
extern u64 GetTickFrequency();

View File

@ -23,393 +23,404 @@ const wxRect wxDefaultRect(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDef
wxDirName g_fullBaseDirName = wxDirName(L"");
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;
while (*enumArray != NULL) {
enumArray++;
cnt++;
}
int cnt = 0;
while (*enumArray != NULL)
{
enumArray++;
cnt++;
}
return cnt;
return cnt;
}
ScopedIniGroup::ScopedIniGroup(IniInterface &mommy, const wxString &group)
: m_mom(mommy)
ScopedIniGroup::ScopedIniGroup(IniInterface& mommy, const wxString& group)
: m_mom(mommy)
{
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
m_mom.SetPath(group);
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
m_mom.SetPath(group);
}
ScopedIniGroup::~ScopedIniGroup()
{
m_mom.SetPath(L"..");
m_mom.SetPath(L"..");
}
// --------------------------------------------------------------------------------------
// 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()
{
m_Config = wxConfigBase::Get(false);
m_Config = wxConfigBase::Get(false);
}
IniInterface::~IniInterface()
{
Flush();
Flush();
}
void IniInterface::SetPath(const wxString &path)
void IniInterface::SetPath(const wxString& path)
{
if (m_Config)
m_Config->SetPath(path);
if (m_Config)
m_Config->SetPath(path);
}
void IniInterface::Flush()
{
if (m_Config)
m_Config->Flush();
if (m_Config)
m_Config->Flush();
}
// --------------------------------------------------------------------------------------
// IniLoader (implementations)
// --------------------------------------------------------------------------------------
IniLoader::IniLoader(wxConfigBase &config)
: IniInterface(config)
IniLoader::IniLoader(wxConfigBase& config)
: IniInterface(config)
{
}
IniLoader::IniLoader(wxConfigBase *config)
: IniInterface(config)
IniLoader::IniLoader(wxConfigBase* config)
: IniInterface(config)
{
}
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)
m_Config->Read(var, &value, defvalue);
else
value = defvalue;
if (m_Config)
m_Config->Read(var, &value, defvalue);
else
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;
if (m_Config)
m_Config->Read(var, &dest, wxEmptyString);
wxString dest;
if (m_Config)
m_Config->Read(var, &dest, wxEmptyString);
if (dest.IsEmpty())
value = defvalue;
else {
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
if (dest.IsEmpty())
value = defvalue;
else
{
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
if (value.IsAbsolute())
value.Normalize();
}
if (value.IsAbsolute())
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());
if (m_Config)
m_Config->Read(var, &dest, defvalue.GetFullPath());
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
wxString dest(defvalue.GetFullPath());
if (m_Config)
m_Config->Read(var, &dest, defvalue.GetFullPath());
value = dest;
if (isAllowRelative)
value = g_fullBaseDirName + value;
if (value.IsAbsolute())
value.Normalize();
if (value.IsAbsolute())
value.Normalize();
if (value.HasVolume())
value.SetVolume(value.GetVolume().Upper());
if (value.HasVolume())
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)
m_Config->Read(var, &value, defvalue);
else
value = defvalue;
if (m_Config)
m_Config->Read(var, &value, defvalue);
else
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)
m_Config->Read(var, (int *)&value, (int)defvalue);
else
value = defvalue;
if (m_Config)
m_Config->Read(var, (int*)&value, (int)defvalue);
else
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?
wxString dest;
if(defvalue)
dest = wxString("enabled");
else
dest = wxString("disabled");
// TODO : Stricter value checking on enabled/disabled?
wxString dest;
if (defvalue)
dest = wxString("enabled");
else
dest = wxString("disabled");
if (m_Config)
m_Config->Read(var, &dest, dest);
value = (dest == L"enabled") || (dest == L"1");
if (m_Config)
m_Config->Read(var, &dest, dest);
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.
bool result;
Entry(var, result, defvalue);
return result;
// Note: 'value' param is used by inisaver only.
bool result;
Entry(var, result, defvalue);
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;
Entry(var, result, defvalue);
return result;
int result;
Entry(var, result, defvalue);
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)
m_Config->Read(var, &readval);
if (m_Config)
m_Config->Read(var, &readval);
if (!readval.ToDouble(&value))
value = 0.0;
if (!readval.ToDouble(&value))
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) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
if (!m_Config)
{
value = defvalue;
return;
}
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) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
if (!m_Config)
{
value = defvalue;
return;
}
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) {
value = defvalue;
return;
}
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
if (!m_Config)
{
value = defvalue;
return;
}
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);
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) {
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
defvalue = cnt - 1;
}
const int cnt = _calcEnumLength(enumArray);
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt))
{
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) {
value = defvalue;
return;
}
if (!m_Config)
{
value = defvalue;
return;
}
wxString retval;
m_Config->Read(var, &retval, enumArray[defvalue]);
wxString retval;
m_Config->Read(var, &retval, enumArray[defvalue]);
int i = 0;
while (enumArray[i] != NULL && (retval != enumArray[i]))
i++;
int i = 0;
while (enumArray[i] != NULL && (retval != enumArray[i]))
i++;
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]);
value = defvalue;
} else
value = i;
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]);
value = defvalue;
}
else
value = i;
}
// --------------------------------------------------------------------------------------
// IniSaver (implementations)
// --------------------------------------------------------------------------------------
IniSaver::IniSaver(wxConfigBase &config)
: IniInterface(config)
IniSaver::IniSaver(wxConfigBase& config)
: IniInterface(config)
{
}
IniSaver::IniSaver(wxConfigBase *config)
: IniInterface(config)
IniSaver::IniSaver(wxConfigBase* config)
: IniInterface(config)
{
}
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)
return;
m_Config->Write(var, value);
if (!m_Config)
return;
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)
return;
wxDirName res(value);
if (!m_Config)
return;
wxDirName res(value);
if (res.IsAbsolute())
res.Normalize();
if (res.IsAbsolute())
res.Normalize();
if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
/*if( value == defvalue )
/*if( value == defvalue )
m_Config->Write( var, wxString() );
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)
return;
wxFileName res(value);
if (!m_Config)
return;
wxFileName res(value);
if (res.IsAbsolute())
res.Normalize();
if (res.IsAbsolute())
res.Normalize();
if (isAllowRelative)
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
if (isAllowRelative)
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)
return;
m_Config->Write(var, value);
if (!m_Config)
return;
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)
return;
m_Config->Write(var, (int)value);
if (!m_Config)
return;
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)
return;
m_Config->Write(var, value ? L"enabled" : L"disabled");
if (!m_Config)
return;
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)
m_Config->Write(var, value ? L"enabled" : L"disabled");
return value;
if (m_Config)
m_Config->Write(var, value ? L"enabled" : L"disabled");
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)
m_Config->Write(var, value);
return value;
if (m_Config)
m_Config->Write(var, 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)
return;
if (!m_Config)
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)
return;
m_Config->Write(var, ToString(value));
if (!m_Config)
return;
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)
return;
m_Config->Write(var, ToString(value));
if (!m_Config)
return;
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)
return;
m_Config->Write(var, ToString(value));
if (!m_Config)
return;
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)) {
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
defvalue = cnt - 1;
}
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt))
{
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
defvalue = cnt - 1;
}
if (!m_Config)
return;
if (!m_Config)
return;
if (value >= cnt) {
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
Console.Indent().Warning(
L"Illegal Value: %d\n"
L"Using Default: %d (%s)\n",
value, defvalue, enumArray[defvalue]);
if (value >= cnt)
{
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
Console.Indent().Warning(
L"Illegal Value: %d\n"
L"Using Default: %d (%s)\n",
value, defvalue, enumArray[defvalue]);
// Cause a debug assertion, since this is a fully recoverable error.
pxAssert(value < cnt);
// Cause a debug assertion, since this is a fully recoverable error.
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
{
protected:
wxConfigBase *m_Config;
wxConfigBase* m_Config;
public:
virtual ~IniInterface();
explicit IniInterface();
explicit IniInterface(wxConfigBase &config);
explicit IniInterface(wxConfigBase *config);
virtual ~IniInterface();
explicit IniInterface();
explicit IniInterface(wxConfigBase& config);
explicit IniInterface(wxConfigBase* config);
void SetPath(const wxString &path);
void Flush();
void SetPath(const wxString& path);
void Flush();
wxConfigBase &GetConfig()
{
pxAssert(m_Config);
return *m_Config;
}
bool IsOk() const { return m_Config != NULL; }
wxConfigBase& GetConfig()
{
pxAssert(m_Config);
return *m_Config;
}
bool IsOk() const { return m_Config != NULL; }
virtual bool IsLoading() const = 0;
bool IsSaving() const { return !IsLoading(); }
virtual bool IsLoading() const = 0;
bool IsSaving() const { return !IsLoading(); }
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, 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, 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, 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, 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, uint& value, const uint defvalue = 0) = 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.
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;
// 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 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, 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, 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, wxRect& value, const wxRect defvalue = wxDefaultRect) = 0;
template <typename T>
void EnumEntry(const wxString &var, T &value, const wxChar *const *enumArray = NULL, const T defvalue = (T)0)
{
int tstore = (int)value;
auto defaultvalue = enum_cast(defvalue);
if (enumArray == NULL)
Entry(var, tstore, defaultvalue);
else
_EnumEntry(var, tstore, enumArray, defaultvalue);
value = (T)tstore;
}
template <typename T>
void EnumEntry(const wxString& var, T& value, const wxChar* const* enumArray = NULL, const T defvalue = (T)0)
{
int tstore = (int)value;
auto defaultvalue = enum_cast(defvalue);
if (enumArray == NULL)
Entry(var, tstore, defaultvalue);
else
_EnumEntry(var, tstore, enumArray, defaultvalue);
value = (T)tstore;
}
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
{
protected:
IniInterface &m_mom;
IniInterface& m_mom;
public:
ScopedIniGroup(IniInterface &mommy, const wxString &group);
virtual ~ScopedIniGroup();
ScopedIniGroup(IniInterface& mommy, const wxString& group);
virtual ~ScopedIniGroup();
};
// --------------------------------------------------------------------------------------
@ -109,31 +109,31 @@ public:
class IniLoader : public IniInterface
{
public:
virtual ~IniLoader() = default;
explicit IniLoader();
explicit IniLoader(wxConfigBase &config);
explicit IniLoader(wxConfigBase *config);
virtual ~IniLoader() = default;
explicit IniLoader();
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, 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, int &value, const int 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, 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, 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, uint& value, const uint defvalue = 0);
void Entry(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);
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
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, wxSize &value, const wxSize defvalue = wxDefaultSize);
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
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, wxRect& value, const wxRect defvalue = wxDefaultRect);
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
{
public:
virtual ~IniSaver() = default;
explicit IniSaver();
explicit IniSaver(wxConfigBase &config);
explicit IniSaver(wxConfigBase *config);
virtual ~IniSaver() = default;
explicit IniSaver();
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, 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, int &value, const int 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, 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, 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, uint& value, const uint defvalue = 0);
void Entry(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);
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
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, wxSize &value, const wxSize defvalue = wxDefaultSize);
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
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, wxRect& value, const wxRect defvalue = wxDefaultRect);
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;
// 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.
// 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
// process, but the handler is executed by the thread that caused the exception.
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
// 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
// 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
// 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
// be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous
// signals)
// 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
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
// be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous
// signals)
// Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful.
// Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful.
// Note: This signal can be accessed by the EE or MTVU thread
// 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...
Threading::ScopedLock lock(PageFault_Mutex);
// Note: This signal can be accessed by the EE or MTVU thread
// 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...
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
// caused the SIGSEGV).
if (Source_PageFault->WasHandled())
return;
// resumes execution right where we left off (re-executes instruction that
// caused the SIGSEGV).
if (Source_PageFault->WasHandled())
return;
if (!wxThread::IsMain()) {
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
}
if (!wxThread::IsMain())
{
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
}
// Bad mojo! Completely invalid address.
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
// Bad mojo! Completely invalid address.
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
pxTrap();
if (!IsDebugBuild)
raise(SIGKILL);
pxTrap();
if (!IsDebugBuild)
raise(SIGKILL);
}
void _platform_InstallSignalHandler()
{
Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa;
Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
#ifdef __APPLE__
// MacOS uses SIGBUS for memory permission violations
sigaction(SIGBUS, &sa, NULL);
// MacOS uses SIGBUS for memory permission violations
sigaction(SIGBUS, &sa, NULL);
#else
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGSEGV, &sa, NULL);
#endif
}
static __ri void PageSizeAssertionTest(size_t size)
{
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
"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)",
getpagesize(), getpagesize(), __pagesize, __pagesize));
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
"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)",
getpagesize(), getpagesize(), __pagesize, __pagesize));
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
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)",
__pagesize, __pagesize, size, size));
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
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)",
__pagesize, __pagesize, size, size));
}
// returns FALSE if the mprotect call fails with an ENOMEM.
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
// 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())
lnxmode |= PROT_WRITE;
if (mode.CanRead())
lnxmode |= PROT_READ;
if (mode.CanExecute())
lnxmode |= PROT_EXEC | PROT_READ;
if (mode.CanWrite())
lnxmode |= PROT_WRITE;
if (mode.CanRead())
lnxmode |= PROT_READ;
if (mode.CanExecute())
lnxmode |= PROT_EXEC | PROT_READ;
const int result = mprotect(baseaddr, size, lnxmode);
const int result = mprotect(baseaddr, size, lnxmode);
if (result == 0)
return true;
if (result == 0)
return true;
switch (errno) {
case EINVAL:
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break;
switch (errno)
{
case EINVAL:
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break;
case EACCES:
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break;
case EACCES:
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
break;
case ENOMEM:
// caller handles assertion or exception, or whatever.
break;
}
return false;
case ENOMEM:
// caller handles assertion or exception, or whatever.
break;
}
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
// 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
// against the commit table.
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// 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
// is completely inaccessible, the OS will simply reserve it and will not put it
// against the commit table.
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
// 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
// later when the user changes permissions to something useful via calls to MemProtect).
// In linux, reserved memory is automatically committed when its permissions are
// 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
// later when the user changes permissions to something useful via calls to MemProtect).
if (mode.IsNone())
return false;
if (mode.IsNone())
return false;
if (_memprotect(base, size, mode))
return true;
if (_memprotect(base, size, mode))
return true;
if (!pxDoOutOfMemory)
return false;
pxDoOutOfMemory(size);
return _memprotect(base, size, mode);
if (!pxDoOutOfMemory)
return false;
pxDoOutOfMemory(size);
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(
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
base, (uptr)base + size));
pxAssertRel((uptr)result == (uptr)base, pxsFmt(
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
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)
{
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)
{
if (!base)
return;
munmap((void *)base, size);
if (!base)
return;
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)) {
throw Exception::OutOfMemory(L"MemProtect")
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
}
if (!_memprotect(baseaddr, size, mode))
{
throw Exception::OutOfMemory(L"MemProtect")
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
}
}
#endif

View File

@ -39,21 +39,21 @@
__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
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()
{
// If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required).
__asm__("pause");
// If this doesn't compile you can just comment it out (it only serves as a
// performance hint and isn't required).
__asm__("pause");
}
__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()
@ -63,69 +63,72 @@ __forceinline void Threading::DisableHiresScheduler()
// Unit of time of GetThreadCpuTime/GetCpuTime
u64 Threading::GetThreadTicksPerSecond()
{
return 1000000;
return 1000000;
}
// Helper function to get either either the current cpu usage
// in called thread or in id thread
static u64 get_thread_time(uptr id = 0)
{
clockid_t cid;
if (id) {
int err = pthread_getcpuclockid((pthread_t)id, &cid);
if (err)
return 0;
} else {
cid = CLOCK_THREAD_CPUTIME_ID;
}
clockid_t cid;
if (id)
{
int err = pthread_getcpuclockid((pthread_t)id, &cid);
if (err)
return 0;
}
else
{
cid = CLOCK_THREAD_CPUTIME_ID;
}
struct timespec ts;
int err = clock_gettime(cid, &ts);
if (err)
return 0;
struct timespec ts;
int err = clock_gettime(cid, &ts);
if (err)
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)
u64 Threading::GetThreadCpuTime()
{
return get_thread_time();
return get_thread_time();
}
u64 Threading::pxThread::GetCpuTime() const
{
// 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
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
// 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
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
if (!m_native_id)
return 0;
if (!m_native_id)
return 0;
return get_thread_time(m_native_id);
return get_thread_time(m_native_id);
}
void Threading::pxThread::_platform_specific_OnStartInThread()
{
// Obtain linux-specific thread IDs or Handles here, which can be used to query
// kernel scheduler performance information.
m_native_id = (uptr)pthread_self();
// Obtain linux-specific thread IDs or Handles here, which can be used to query
// kernel scheduler performance information.
m_native_id = (uptr)pthread_self();
}
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__)
// Extract of manpage: "The name can be up to 16 bytes long, and should be
// null-terminated if it contains fewer bytes."
prctl(PR_SET_NAME, name, 0, 0, 0);
// Extract of manpage: "The name can be up to 16 bytes long, and should be
// null-terminated if it contains fewer bytes."
prctl(PR_SET_NAME, name, 0, 0, 0);
#elif defined(__unix__)
pthread_set_name_np(pthread_self(), name);
pthread_set_name_np(pthread_self(), name);
#endif
}

View File

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

View File

@ -22,7 +22,7 @@
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
// other implementations. So for this combination only, prefer memcmp_mmx
#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
#define memcmp_mmx memcmp
#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
// for you!
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.
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>
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) {
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);
} else
srcreg = _mm_setzero_ps();
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);
}
else
srcreg = _mm_setzero_ps();
float(*destxmm)[4] = (float(*)[4])dest;
float(*destxmm)[4] = (float(*)[4])dest;
switch (MZFqwc & 0x07) {
case 0x07:
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
// Fall through
case 0x06:
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
// Fall through
case 0x05:
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
// Fall through
case 0x04:
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
// Fall through
case 0x03:
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
// Fall through
case 0x02:
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
// Fall through
case 0x01:
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
// Fall through
}
switch (MZFqwc & 0x07)
{
case 0x07:
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
// Fall through
case 0x06:
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
// Fall through
case 0x05:
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
// Fall through
case 0x04:
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
// Fall through
case 0x03:
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
// Fall through
case 0x02:
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
// Fall through
case 0x01:
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
// Fall through
}
destxmm += (MZFqwc & 0x07);
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[2][0], srcreg);
_mm_store_ps(&destxmm[3][0], srcreg);
_mm_store_ps(&destxmm[4][0], srcreg);
_mm_store_ps(&destxmm[5][0], srcreg);
_mm_store_ps(&destxmm[6][0], srcreg);
_mm_store_ps(&destxmm[7][0], srcreg);
}
destxmm += (MZFqwc & 0x07);
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[2][0], srcreg);
_mm_store_ps(&destxmm[3][0], srcreg);
_mm_store_ps(&destxmm[4][0], srcreg);
_mm_store_ps(&destxmm[5][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>
__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");
memset_sse_a<data>(&dest, sizeof(dest));
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
memset_sse_a<data>(&dest, sizeof(dest));
}
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");
memset_sse_a<0>(&dest, sizeof(dest));
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
memset_sse_a<0>(&dest, sizeof(dest));
}

View File

@ -20,9 +20,9 @@
namespace Threading
{
static std::atomic<int> _attr_refcount(0);
static pthread_mutexattr_t _attr_recursive;
}
static std::atomic<int> _attr_refcount(0);
static pthread_mutexattr_t _attr_recursive;
} // namespace Threading
// --------------------------------------------------------------------------------------
// Mutex Implementations
@ -52,90 +52,94 @@ static pthread_mutexattr_t _attr_recursive;
// This is an implementation that emulates pthread_mutex_timedlock() via
// pthread_mutex_trylock().
static int xpthread_mutex_timedlock(
pthread_mutex_t *mutex,
const struct timespec *abs_timeout)
pthread_mutex_t* mutex,
const struct timespec* abs_timeout)
{
int err = 0;
int err = 0;
while ((err = pthread_mutex_trylock(mutex)) == EBUSY) {
// check if the timeout has expired, gettimeofday() is implemented
// efficiently (in userspace) on OSX
struct timeval now;
gettimeofday(&now, NULL);
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)) {
return ETIMEDOUT;
}
while ((err = pthread_mutex_trylock(mutex)) == EBUSY)
{
// check if the timeout has expired, gettimeofday() is implemented
// efficiently (in userspace) on OSX
struct timeval now;
gettimeofday(&now, NULL);
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))
{
return ETIMEDOUT;
}
// acquiring lock failed, sleep some
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
while (nanosleep(&ts, &ts) == -1);
}
// acquiring lock failed, sleep some
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
while (nanosleep(&ts, &ts) == -1)
;
}
return err;
return err;
}
#endif
Threading::Mutex::Mutex()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_mutex_init(&m_mutex, NULL);
}
static wxTimeSpan def_detach_timeout(0, 0, 6, 0);
void Threading::Mutex::Detach()
{
if (EBUSY != pthread_mutex_destroy(&m_mutex))
return;
if (EBUSY != pthread_mutex_destroy(&m_mutex))
return;
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.
// (note: if the mutex is locked recursively more than twice then this assert won't
// detect it)
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.
// (note: if the mutex is locked recursively more than twice then this assert won't
// detect it)
Release();
Release(); // in case of double recursion.
int result = pthread_mutex_destroy(&m_mutex);
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
return;
}
Release();
Release(); // in case of double recursion.
int result = pthread_mutex_destroy(&m_mutex);
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
return;
}
if (Wait(def_detach_timeout))
pthread_mutex_destroy(&m_mutex);
else
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
if (Wait(def_detach_timeout))
pthread_mutex_destroy(&m_mutex);
else
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
}
Threading::Mutex::~Mutex()
{
try {
Mutex::Detach();
}
DESTRUCTOR_CATCHALL;
try
{
Mutex::Detach();
}
DESTRUCTOR_CATCHALL;
}
Threading::MutexRecursive::MutexRecursive()
: Mutex(false)
: Mutex(false)
{
if (++_attr_refcount == 1) {
if (0 != pthread_mutexattr_init(&_attr_recursive))
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
if (++_attr_refcount == 1)
{
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))
Console.Error("(Thread Log) Failed to initialize mutex.");
if (pthread_mutex_init(&m_mutex, &_attr_recursive))
Console.Error("(Thread Log) Failed to initialize mutex.");
}
Threading::MutexRecursive::~MutexRecursive()
{
if (--_attr_refcount == 0)
pthread_mutexattr_destroy(&_attr_recursive);
if (--_attr_refcount == 0)
pthread_mutexattr_destroy(&_attr_recursive);
}
// 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.
void Threading::Mutex::Recreate()
{
Detach();
pthread_mutex_init(&m_mutex, NULL);
Detach();
pthread_mutex_init(&m_mutex, NULL);
}
// Returns:
@ -153,11 +157,12 @@ void Threading::Mutex::Recreate()
// unlocked.
bool Threading::Mutex::RecreateIfLocked()
{
if (!Wait(def_detach_timeout)) {
Recreate();
return true;
}
return false;
if (!Wait(def_detach_timeout))
{
Recreate();
return true;
}
return false;
}
@ -167,25 +172,25 @@ bool Threading::Mutex::RecreateIfLocked()
// other than the main thread.
void Threading::Mutex::AcquireWithoutYield()
{
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
pthread_mutex_lock(&m_mutex);
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
pthread_mutex_lock(&m_mutex);
}
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan &timeout)
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan& timeout)
{
wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
}
void Threading::Mutex::Release()
{
pthread_mutex_unlock(&m_mutex);
pthread_mutex_unlock(&m_mutex);
}
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
@ -194,45 +199,56 @@ bool Threading::Mutex::TryAcquire()
void Threading::Mutex::Acquire()
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
pthread_mutex_lock(&m_mutex);
} else if (_WaitGui_RecursionGuard(L"Mutex::Acquire")) {
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
pthread_mutex_lock(&m_mutex);
} else {
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!AcquireWithoutYield(def_yieldgui_interval))
YieldToMain();
}
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
pthread_mutex_lock(&m_mutex);
}
else if (_WaitGui_RecursionGuard(L"Mutex::Acquire"))
{
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
pthread_mutex_lock(&m_mutex);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!AcquireWithoutYield(def_yieldgui_interval))
YieldToMain();
}
#else
pthread_mutex_lock(&m_mutex);
pthread_mutex_lock(&m_mutex);
#endif
}
bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
return AcquireWithoutYield(timeout);
} else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire")) {
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
return AcquireWithoutYield(timeout);
} else {
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
return AcquireWithoutYield(timeout);
}
else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire"))
{
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
return AcquireWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do {
if (AcquireWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
do
{
if (AcquireWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0;
}
return countdown.GetMilliseconds() > 0;
}
#else
return AcquireWithoutYield();
return AcquireWithoutYield();
#endif
}
@ -245,14 +261,14 @@ bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
//
void Threading::Mutex::Wait()
{
Acquire();
Release();
Acquire();
Release();
}
void Threading::Mutex::WaitWithoutYield()
{
AcquireWithoutYield();
Release();
AcquireWithoutYield();
Release();
}
// 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
// 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)) {
Release();
return true;
}
return false;
if (Acquire(timeout))
{
Release();
return true;
}
return false;
}
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
{
if (AcquireWithoutYield(timeout)) {
Release();
return true;
}
return false;
if (AcquireWithoutYield(timeout))
{
Release();
return true;
}
return false;
}
// --------------------------------------------------------------------------------------
@ -286,72 +304,72 @@ bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
Threading::ScopedLock::~ScopedLock()
{
if (m_IsLocked && m_lock)
m_lock->Release();
if (m_IsLocked && m_lock)
m_lock->Release();
}
Threading::ScopedLock::ScopedLock(const Mutex *locker)
Threading::ScopedLock::ScopedLock(const Mutex* locker)
{
m_IsLocked = false;
AssignAndLock(locker);
m_IsLocked = false;
AssignAndLock(locker);
}
Threading::ScopedLock::ScopedLock(const Mutex &locker)
Threading::ScopedLock::ScopedLock(const Mutex& locker)
{
m_IsLocked = false;
AssignAndLock(locker);
m_IsLocked = false;
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);
if (!m_lock)
return;
m_lock = const_cast<Mutex*>(locker);
if (!m_lock)
return;
m_IsLocked = true;
m_lock->Acquire();
m_IsLocked = true;
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.
void Threading::ScopedLock::Release()
{
if (!m_IsLocked)
return;
m_IsLocked = false;
if (m_lock)
m_lock->Release();
if (!m_IsLocked)
return;
m_IsLocked = false;
if (m_lock)
m_lock->Release();
}
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedLock::Acquire()
{
if (m_IsLocked || !m_lock)
return;
m_lock->Acquire();
m_IsLocked = true;
if (m_IsLocked || !m_lock)
return;
m_lock->Acquire();
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);
if (!m_lock)
return;
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
m_lock = const_cast<Mutex*>(&locker);
if (!m_lock)
return;
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
}

View File

@ -30,12 +30,12 @@
struct PageFaultInfo
{
uptr addr;
uptr addr;
PageFaultInfo(uptr address)
{
addr = address;
}
PageFaultInfo(uptr address)
{
addr = address;
}
};
// --------------------------------------------------------------------------------------
@ -44,22 +44,22 @@ struct PageFaultInfo
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
{
public:
typedef PageFaultInfo EvtParams;
typedef PageFaultInfo EvtParams;
public:
virtual ~IEventListener_PageFault() = default;
virtual ~IEventListener_PageFault() = default;
virtual void DispatchEvent(const PageFaultInfo &evtinfo, bool &handled)
{
OnPageFaultEvent(evtinfo, handled);
}
virtual void DispatchEvent(const PageFaultInfo& evtinfo, bool& handled)
{
OnPageFaultEvent(evtinfo, handled);
}
virtual void DispatchEvent(const PageFaultInfo &evtinfo)
{
pxFailRel("Don't call me, damnit. Use DispatchException instead.");
}
virtual void DispatchEvent(const PageFaultInfo& evtinfo)
{
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
{
public:
EventListener_PageFault();
virtual ~EventListener_PageFault();
EventListener_PageFault();
virtual ~EventListener_PageFault();
};
template <typename TypeToDispatchTo>
class EventListenerHelper_PageFault : public EventListener_PageFault
{
public:
TypeToDispatchTo *Owner;
TypeToDispatchTo* Owner;
public:
EventListenerHelper_PageFault(TypeToDispatchTo &dispatchTo)
{
Owner = &dispatchTo;
}
EventListenerHelper_PageFault(TypeToDispatchTo& dispatchTo)
{
Owner = &dispatchTo;
}
EventListenerHelper_PageFault(TypeToDispatchTo *dispatchTo)
{
Owner = dispatchTo;
}
EventListenerHelper_PageFault(TypeToDispatchTo* dispatchTo)
{
Owner = dispatchTo;
}
virtual ~EventListenerHelper_PageFault() = default;
virtual ~EventListenerHelper_PageFault() = default;
protected:
virtual void OnPageFaultEvent(const PageFaultInfo &info, bool &handled)
{
Owner->OnPageFaultEvent(info, handled);
}
virtual void OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
{
Owner->OnPageFaultEvent(info, handled);
}
};
// --------------------------------------------------------------------------------------
@ -104,23 +104,23 @@ protected:
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
{
protected:
typedef EventSource<IEventListener_PageFault> _parent;
typedef EventSource<IEventListener_PageFault> _parent;
protected:
bool m_handled;
bool m_handled;
public:
SrcType_PageFault()
: m_handled(false)
{
}
virtual ~SrcType_PageFault() = default;
SrcType_PageFault()
: m_handled(false)
{
}
virtual ~SrcType_PageFault() = default;
bool WasHandled() const { return m_handled; }
virtual void Dispatch(const PageFaultInfo &params);
bool WasHandled() const { return m_handled; }
virtual void Dispatch(const PageFaultInfo& params);
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
{
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)
std::atomic<bool> *m_pageuse;
// An array to track page usage (to trigger asserts if things try to overlap)
std::atomic<bool>* m_pageuse;
// reserved memory (in pages)
u32 m_pages_reserved;
// reserved memory (in pages)
u32 m_pages_reserved;
public:
// 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
// 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();
// 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
// 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();
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
// offsetLocation must be page-aligned
void *Alloc(uptr offsetLocation, size_t size) const;
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
// offsetLocation must be page-aligned
void* Alloc(uptr offsetLocation, size_t size) const;
void *AllocAtAddress(void *address, size_t size) const {
return Alloc(size, (uptr)address - m_baseptr);
}
void* AllocAtAddress(void* address, size_t size) const
{
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?
// (If not, calls to Alloc will return null pointers)
bool IsOk() const { return m_baseptr != 0; }
// Was this VirtualMemoryManager successfully able to get its memory mapping?
// (If not, calls to Alloc will return null pointers)
bool IsOk() const { return m_baseptr != 0; }
};
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
@ -173,13 +174,14 @@ typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
// --------------------------------------------------------------------------------------
class VirtualMemoryBumpAllocator
{
const VirtualMemoryManagerPtr m_allocator;
std::atomic<uptr> m_baseptr{0};
const uptr m_endptr = 0;
const VirtualMemoryManagerPtr m_allocator;
std::atomic<uptr> m_baseptr{0};
const uptr m_endptr = 0;
public:
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
void *Alloc(size_t size);
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
void* Alloc(size_t size);
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
};
// --------------------------------------------------------------------------------------
@ -187,108 +189,108 @@ public:
// --------------------------------------------------------------------------------------
class VirtualMemoryReserve
{
DeclareNoncopyableObject(VirtualMemoryReserve);
DeclareNoncopyableObject(VirtualMemoryReserve);
protected:
wxString m_name;
wxString m_name;
// Where the memory came from (so we can return it)
VirtualMemoryManagerPtr m_allocator;
// Where the memory came from (so we can return it)
VirtualMemoryManagerPtr m_allocator;
// 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
// in the Reserve parameters.
size_t m_defsize;
// 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
// in the Reserve parameters.
size_t m_defsize;
void *m_baseptr;
void* m_baseptr;
// reserved memory (in pages).
uptr m_pages_reserved;
// reserved memory (in pages).
uptr m_pages_reserved;
// Records the number of pages committed to memory.
// (metric for analysis of buffer usage)
uptr m_pages_commited;
// Records the number of pages committed to memory.
// (metric for analysis of buffer usage)
uptr m_pages_commited;
// Protection mode to be applied to committed blocks.
PageProtectionMode m_prot_mode;
// Protection mode to be applied to committed blocks.
PageProtectionMode m_prot_mode;
// 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
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
// as well.
bool m_allow_writes;
// 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
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
// as well.
bool m_allow_writes;
// 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
virtual size_t GetSize(size_t requestedSize);
// 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
virtual size_t GetSize(size_t requestedSize);
public:
VirtualMemoryReserve(const wxString &name, size_t size = 0);
virtual ~VirtualMemoryReserve()
{
Release();
}
VirtualMemoryReserve(const wxString& name, size_t size = 0);
virtual ~VirtualMemoryReserve()
{
Release();
}
// Initialize with the given piece of memory
// 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
virtual void *Assign(VirtualMemoryManagerPtr allocator, void *baseptr, size_t size);
// Initialize with the given piece of memory
// 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
virtual void* Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size);
void *Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
{
size = GetSize(size);
void *allocation = allocator->Alloc(baseOffset, size);
return Assign(std::move(allocator), allocation, size);
}
void *Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
{
size = GetSize(size);
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
}
void* Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
{
size = GetSize(size);
void* allocation = allocator->Alloc(baseOffset, size);
return Assign(std::move(allocator), allocation, size);
}
void* Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
{
size = GetSize(size);
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
}
virtual void Reset();
virtual void Release();
virtual bool TryResize(uint newsize);
virtual bool Commit();
virtual void Reset();
virtual void Release();
virtual bool TryResize(uint newsize);
virtual bool Commit();
virtual void ForbidModification();
virtual void AllowModification();
virtual void ForbidModification();
virtual void AllowModification();
bool IsOk() const { return m_baseptr != NULL; }
const wxString& GetName() const { return m_name; }
bool IsOk() const { return m_baseptr != NULL; }
const wxString& GetName() const { return m_name; }
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
uint GetCommittedPageCount() const { return m_pages_commited; }
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
uint GetCommittedPageCount() const { return m_pages_commited; }
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
u8 *GetPtr() { return (u8 *)m_baseptr; }
const u8 *GetPtr() const { return (u8 *)m_baseptr; }
u8 *GetPtrEnd() { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
const u8 *GetPtrEnd() const { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
u8* GetPtr() { return (u8*)m_baseptr; }
const u8* GetPtr() const { return (u8*)m_baseptr; }
u8* GetPtrEnd() { 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 const void *() const { return m_baseptr; }
operator void*() { return m_baseptr; }
operator const void*() const { return m_baseptr; }
operator u8 *() { return (u8 *)m_baseptr; }
operator const u8 *() const { return (u8 *)m_baseptr; }
operator u8*() { return (u8*)m_baseptr; }
operator const u8*() const { return (u8*)m_baseptr; }
u8 &operator[](uint idx)
{
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8 *)m_baseptr + idx);
}
u8& operator[](uint idx)
{
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8*)m_baseptr + idx);
}
const u8 &operator[](uint idx) const
{
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8 *)m_baseptr + idx);
}
const u8& operator[](uint idx) const
{
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8*)m_baseptr + idx);
}
protected:
virtual void ReprotectCommittedBlocks(const PageProtectionMode &newmode);
virtual void ReprotectCommittedBlocks(const PageProtectionMode& newmode);
};
#ifdef __POSIX__
@ -299,11 +301,11 @@ protected:
#elif defined(_WIN32)
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_EXCEPT \
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
#else
#error PCSX2 - Unsupported operating system platform.
@ -313,5 +315,5 @@ extern void pxInstallSignalHandler();
extern void _platform_InstallSignalHandler();
#include "Threading.h"
extern SrcType_PageFault *Source_PageFault;
extern SrcType_PageFault* Source_PageFault;
extern Threading::Mutex PageFault_Mutex;

View File

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

View File

@ -22,60 +22,60 @@
// 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.");
if (right.IsAbsolute())
return right;
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
if (right.IsAbsolute())
return right;
// 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
// for getting each component of the path. So instead let's use Normalize:
// 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
// for getting each component of the path. So instead let's use Normalize:
wxFileName result(right);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
return result;
wxFileName result(right);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
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);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
return result;
wxDirName result(right);
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
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.");
if (!wxFileName::Normalize(flags, cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
return *this;
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::Normalize(flags, cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
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.");
if (!wxFileName::MakeRelativeTo(pathBase))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
return *this;
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::MakeRelativeTo(pathBase))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
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.");
if (!wxFileName::MakeAbsolute(cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
return *this;
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
if (!wxFileName::MakeAbsolute(cwd))
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
return *this;
}
void wxDirName::Rmdir()
{
if (!Exists())
return;
wxFileName::Rmdir();
// TODO : Throw exception if operation failed? Do we care?
if (!Exists())
return;
wxFileName::Rmdir();
// TODO : Throw exception if operation failed? Do we care?
}
bool wxDirName::Mkdir()
@ -87,9 +87,9 @@ bool wxDirName::Mkdir()
#define wxS_DIR_DEFAULT 0777
#endif
if (Exists())
return true;
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
if (Exists())
return true;
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.
s64 Path::GetFileSize(const wxString &path)
s64 Path::GetFileSize(const wxString& path)
{
if (!wxFile::Exists(path.c_str()))
return -1;
return (s64)wxFileName::GetSize(path).GetValue();
if (!wxFile::Exists(path.c_str()))
return -1;
return (s64)wxFileName::GetSize(path).GetValue();
}
wxString Path::Normalize(const wxString &src)
wxString Path::Normalize(const wxString& src)
{
wxFileName normalize(src);
normalize.Normalize();
return normalize.GetFullPath();
wxFileName normalize(src);
normalize.Normalize();
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);
absolute.MakeAbsolute();
return absolute.GetFullPath();
wxFileName absolute(src);
absolute.MakeAbsolute();
return absolute.GetFullPath();
}
// Concatenates two pathnames together, inserting delimiters (backslash on win32)
// 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.
// 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);
jojo.SetExt(ext);
return jojo.GetFullPath();
wxFileName jojo(src);
jojo.SetExt(ext);
return jojo.GetFullPath();
}
wxString Path::ReplaceFilename(const wxString &src, const wxString &newfilename)
wxString Path::ReplaceFilename(const wxString& src, const wxString& newfilename)
{
wxFileName jojo(src);
jojo.SetFullName(newfilename);
return jojo.GetFullPath();
wxFileName jojo(src);
jojo.SetFullName(newfilename);
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.
// 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());
if (pos == wxString::npos)
return wxString();
else
return wxString(src.begin(), src.begin() + pos);
size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
if (pos == wxString::npos)
return wxString();
else
return wxString(src.begin(), src.begin() + pos);
}
// ------------------------------------------------------------------------
// 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
// 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
union u128
{
struct
{
u64 lo;
u64 hi;
};
struct
{
u64 lo;
u64 hi;
};
u64 _u64[2];
u32 _u32[4];
u16 _u16[8];
u8 _u8[16];
u64 _u64[2];
u32 _u32[4];
u16 _u16[8];
u8 _u8[16];
// Explicit conversion from u64. Zero-extends the source through 128 bits.
static u128 From64(u64 src)
{
u128 retval;
retval.lo = src;
retval.hi = 0;
return retval;
}
// Explicit conversion from u64. Zero-extends the source through 128 bits.
static u128 From64(u64 src)
{
u128 retval;
retval.lo = src;
retval.hi = 0;
return retval;
}
// Explicit conversion from u32. Zero-extends the source through 128 bits.
static u128 From32(u32 src)
{
u128 retval;
retval._u32[0] = src;
retval._u32[1] = 0;
retval.hi = 0;
return retval;
}
// Explicit conversion from u32. Zero-extends the source through 128 bits.
static u128 From32(u32 src)
{
u128 retval;
retval._u32[0] = src;
retval._u32[1] = 0;
retval.hi = 0;
return retval;
}
operator u32() const { return _u32[0]; }
operator u16() const { return _u16[0]; }
operator u8() const { return _u8[0]; }
operator u32() const { return _u32[0]; }
operator u16() const { return _u16[0]; }
operator u8() const { return _u8[0]; }
bool operator==(const u128 &right) const
{
return (lo == right.lo) && (hi == right.hi);
}
bool operator==(const u128& right) const
{
return (lo == right.lo) && (hi == right.hi);
}
bool operator!=(const u128 &right) const
{
return (lo != right.lo) || (hi != right.hi);
}
bool operator!=(const u128& right) const
{
return (lo != right.lo) || (hi != right.hi);
}
// 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
// using them, then you will need to provide your own implementations of these methods.
wxString ToString() const;
wxString ToString64() const;
wxString ToString8() const;
// 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
// using them, then you will need to provide your own implementations of these methods.
wxString ToString() const;
wxString ToString64() const;
wxString ToString8() const;
void WriteTo(FastFormatAscii &dest) const;
void WriteTo8(FastFormatAscii &dest) const;
void WriteTo64(FastFormatAscii &dest) const;
void WriteTo(FastFormatAscii& dest) const;
void WriteTo8(FastFormatAscii& dest) const;
void WriteTo64(FastFormatAscii& dest) const;
};
struct s128
{
s64 lo;
s64 hi;
s64 lo;
s64 hi;
// explicit conversion from s64, with sign extension.
static s128 From64(s64 src)
{
s128 retval = {src, (src < 0) ? -1 : 0};
return retval;
}
// explicit conversion from s64, with sign extension.
static s128 From64(s64 src)
{
s128 retval = {src, (src < 0) ? -1 : 0};
return retval;
}
// explicit conversion from s32, with sign extension.
static s128 From64(s32 src)
{
s128 retval = {src, (src < 0) ? -1 : 0};
return retval;
}
// explicit conversion from s32, with sign extension.
static s128 From64(s32 src)
{
s128 retval = {src, (src < 0) ? -1 : 0};
return retval;
}
operator u32() const { return (s32)lo; }
operator u16() const { return (s16)lo; }
operator u8() const { return (s8)lo; }
operator u32() const { return (s32)lo; }
operator u16() const { return (s16)lo; }
operator u8() const { return (s8)lo; }
bool operator==(const s128 &right) const
{
return (lo == right.lo) && (hi == right.hi);
}
bool operator==(const s128& right) const
{
return (lo == right.lo) && (hi == right.hi);
}
bool operator!=(const s128 &right) const
{
return (lo != right.lo) || (hi != right.hi);
}
bool operator!=(const s128& right) const
{
return (lo != right.lo) || (hi != right.hi);
}
};
#else
typedef union _u128_t
{
struct
{
u64 lo;
u64 hi;
};
struct
{
u64 lo;
u64 hi;
};
u64 _u64[2];
u32 _u32[4];
u16 _u16[8];
u8 _u8[16];
u64 _u64[2];
u32 _u32[4];
u16 _u16[8];
u8 _u8[16];
} u128;
typedef union _s128_t
{
u64 lo;
s64 hi;
u64 lo;
s64 hi;
} s128;
#endif

View File

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

View File

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

View File

@ -22,188 +22,188 @@
namespace Threading
{
// --------------------------------------------------------------------------------------
// ThreadDeleteEvent
// --------------------------------------------------------------------------------------
class EventListener_Thread : public IEventDispatcher<int>
{
public:
typedef int EvtParams;
// --------------------------------------------------------------------------------------
// ThreadDeleteEvent
// --------------------------------------------------------------------------------------
class EventListener_Thread : public IEventDispatcher<int>
{
public:
typedef int EvtParams;
protected:
pxThread *m_thread;
protected:
pxThread* m_thread;
public:
EventListener_Thread()
{
m_thread = NULL;
}
public:
EventListener_Thread()
{
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)
{
OnThreadCleanup();
}
void DispatchEvent(const int& params)
{
OnThreadCleanup();
}
protected:
// Invoked by the pxThread when the thread execution is ending. This is
// typically more useful than a delete listener since the extended thread information
// provided by virtualized functions/methods will be available.
// 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).
virtual void OnThreadCleanup() = 0;
};
protected:
// Invoked by the pxThread when the thread execution is ending. This is
// typically more useful than a delete listener since the extended thread information
// provided by virtualized functions/methods will be available.
// 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).
virtual void OnThreadCleanup() = 0;
};
/// Set the name of the current thread
void SetNameOfCurrentThread(const char* name);
/// Set the name of the current thread
void SetNameOfCurrentThread(const char* name);
// --------------------------------------------------------------------------------------
// 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
// 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
// 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
// design where sleeping, suspending, and resuming threads is very efficient, but starting
// new threads has quite a bit of overhead.
//
// To use this as a base class for your threaded procedure, overload the following virtual
// methods:
// void OnStart();
// void ExecuteTaskInThread();
// void OnCleanupInThread();
//
// 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
// it in your derived class if your thread utilizes the post).
//
// Notes:
// * 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
// no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead.
//
class pxThread
{
DeclareNoncopyableObject(pxThread);
// --------------------------------------------------------------------------------------
// 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
// 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
// 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
// design where sleeping, suspending, and resuming threads is very efficient, but starting
// new threads has quite a bit of overhead.
//
// To use this as a base class for your threaded procedure, overload the following virtual
// methods:
// void OnStart();
// void ExecuteTaskInThread();
// void OnCleanupInThread();
//
// 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
// it in your derived class if your thread utilizes the post).
//
// Notes:
// * 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
// no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead.
//
class pxThread
{
DeclareNoncopyableObject(pxThread);
friend void pxYield(int ms);
friend void pxYield(int ms);
protected:
wxString m_name; // diagnostic name for our thread.
pthread_t m_thread;
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.
protected:
wxString m_name; // diagnostic name for our thread.
pthread_t m_thread;
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.
Semaphore m_sem_event; // general wait event that's needed by most threads
Semaphore m_sem_startup; // startup sync tool
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.
Mutex m_mtx_ThreadName;
Semaphore m_sem_event; // general wait event that's needed by most threads
Semaphore m_sem_startup; // startup sync tool
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.
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_running; // set true by Start(), and set false by Cancel(), Block(), etc.
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.
// exception handle, set non-NULL if the thread terminated with an exception
// Use RethrowException() to re-throw the exception using its original exception type.
ScopedPtrMT<BaseException> m_except;
// exception handle, set non-NULL if the thread terminated with an exception
// Use RethrowException() to re-throw the exception using its original exception type.
ScopedPtrMT<BaseException> m_except;
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
public:
virtual ~pxThread();
pxThread(const wxString &name = L"pxThread");
public:
virtual ~pxThread();
pxThread(const wxString& name = L"pxThread");
pthread_t GetId() const { return m_thread; }
u64 GetCpuTime() const;
pthread_t GetId() const { return m_thread; }
u64 GetCpuTime() const;
virtual void Start();
virtual void Cancel(bool isBlocking = true);
virtual bool Cancel(const wxTimeSpan &timeout);
virtual bool Detach();
virtual void Block();
virtual bool Block(const wxTimeSpan &timeout);
virtual void RethrowException() const;
virtual void Start();
virtual void Cancel(bool isBlocking = true);
virtual bool Cancel(const wxTimeSpan& timeout);
virtual bool Detach();
virtual void Block();
virtual bool Block(const wxTimeSpan& timeout);
virtual void RethrowException() const;
void AddListener(EventListener_Thread &evt);
void AddListener(EventListener_Thread *evt)
{
if (evt == NULL)
return;
AddListener(*evt);
}
void AddListener(EventListener_Thread& evt);
void AddListener(EventListener_Thread* evt)
{
if (evt == NULL)
return;
AddListener(*evt);
}
void WaitOnSelf(Semaphore &mutex) const;
void WaitOnSelf(Mutex &mutex) const;
bool WaitOnSelf(Semaphore &mutex, const wxTimeSpan &timeout) const;
bool WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const;
void WaitOnSelf(Semaphore& mutex) const;
void WaitOnSelf(Mutex& mutex) const;
bool WaitOnSelf(Semaphore& mutex, const wxTimeSpan& timeout) const;
bool WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const;
bool IsRunning() const;
bool IsSelf() const;
bool HasPendingException() const { return !!m_except; }
bool IsRunning() const;
bool IsSelf() const;
bool HasPendingException() const { return !!m_except; }
wxString GetName() const;
void SetName(const wxString &newname);
wxString GetName() const;
void SetName(const wxString& newname);
protected:
// Extending classes should always implement your own OnStart(), which is called by
// Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;)
virtual void OnStart();
protected:
// Extending classes should always implement your own OnStart(), which is called by
// Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;)
virtual void OnStart();
virtual void OnStartInThread();
virtual void OnStartInThread();
// 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.
virtual void OnCleanupInThread();
// 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.
virtual void OnCleanupInThread();
// Implemented by derived class to perform actual threaded task!
virtual void ExecuteTaskInThread() = 0;
// Implemented by derived class to perform actual threaded task!
virtual void ExecuteTaskInThread() = 0;
void TestCancel() const;
void TestCancel() const;
// 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()
// or better yet, disable cancellation of the thread completely with DisableCancellation().
//
// Parameters:
// 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
// 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.
void Yield(int ms = 0)
{
pxAssert(IsSelf());
Threading::Sleep(ms);
TestCancel();
}
// 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()
// or better yet, disable cancellation of the thread completely with DisableCancellation().
//
// Parameters:
// 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
// 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.
void Yield(int ms = 0)
{
pxAssert(IsSelf());
Threading::Sleep(ms);
TestCancel();
}
void FrankenMutex(Mutex &mutex);
void FrankenMutex(Mutex& mutex);
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const;
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const;
bool AffinityAssert_AllowFromSelf(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_OnCleanupInThread();
bool _basecancel();
void _selfRunningTest(const wxChar *name) const;
void _DoSetThreadName(const wxString &name);
void _DoSetThreadName(const char *name) { SetNameOfCurrentThread(name); }
void _internal_execute();
void _try_virtual_invoke(void (pxThread::*method)());
void _ThreadCleanup();
void _platform_specific_OnStartInThread();
void _platform_specific_OnCleanupInThread();
bool _basecancel();
void _selfRunningTest(const wxChar* name) const;
void _DoSetThreadName(const wxString& name);
void _DoSetThreadName(const char* name) { SetNameOfCurrentThread(name); }
void _internal_execute();
void _try_virtual_invoke(void (pxThread::*method)());
void _ThreadCleanup();
static void *_internal_callback(void *func);
static void internal_callback_helper(void *func);
static void _pt_callback_cleanup(void *handle);
};
}
static void* _internal_callback(void* func);
static void internal_callback_helper(void* func);
static void _pt_callback_cleanup(void* handle);
};
} // namespace Threading

View File

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

View File

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

View File

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

View File

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

View File

@ -28,34 +28,34 @@
// pointer to null after deallocation.
#define safe_delete(ptr) \
((void)(delete (ptr)), (ptr) = NULL)
((void)(delete (ptr)), (ptr) = NULL)
#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
// just about every compiler and libc implementation of any recentness.
#define safe_free(ptr) \
((void)(free(ptr), !!0), (ptr) = NULL)
((void)(free(ptr), !!0), (ptr) = NULL)
//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
#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
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
// do it here.
#define safe_aligned_free(ptr) \
((void)(_aligned_free(ptr), (ptr) = NULL))
((void)(_aligned_free(ptr), (ptr) = NULL))
// aligned_malloc: Implement/declare linux equivalents here!
#if !defined(_MSC_VER)
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 _aligned_free(void *pmem);
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 _aligned_free(void* pmem);
#else
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
_aligned_realloc(handle, new_size, align)
_aligned_realloc(handle, new_size, align)
#endif
// --------------------------------------------------------------------------------------
@ -63,7 +63,7 @@ extern void _aligned_free(void *pmem);
// --------------------------------------------------------------------------------------
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
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
@ -93,74 +93,74 @@ template <typename T>
class BaseScopedAlloc
{
protected:
T *m_buffer;
uint m_size;
T* m_buffer;
uint m_size;
public:
BaseScopedAlloc()
{
m_buffer = NULL;
m_size = 0;
}
BaseScopedAlloc()
{
m_buffer = NULL;
m_size = 0;
}
virtual ~BaseScopedAlloc()
{
//pxAssert(m_buffer==NULL);
}
virtual ~BaseScopedAlloc()
{
//pxAssert(m_buffer==NULL);
}
public:
size_t GetSize() const { return m_size; }
size_t GetLength() const { return m_size; }
size_t GetSize() const { return m_size; }
size_t GetLength() const { return m_size; }
// 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.
// Parameter:
// 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().
virtual void Alloc(size_t newsize) = 0;
// 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.
// Parameter:
// 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().
virtual void Alloc(size_t newsize) = 0;
// Re-sizes the allocation to the requested size, without any data loss.
// Parameter:
// 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().
virtual void Resize(size_t newsize) = 0;
// Re-sizes the allocation to the requested size, without any data loss.
// Parameter:
// 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().
virtual void Resize(size_t newsize) = 0;
void Free()
{
Alloc(0);
}
void Free()
{
Alloc(0);
}
// Makes enough room for the requested size. Existing data in the array is retained.
void MakeRoomFor(uint size)
{
if (size <= m_size)
return;
Resize(size);
}
// Makes enough room for the requested size. Existing data in the array is retained.
void MakeRoomFor(uint size)
{
if (size <= m_size)
return;
Resize(size);
}
T *GetPtr(uint idx = 0) const
{
T* GetPtr(uint idx = 0) const
{
#if pxUSE_SECURE_MALLOC
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#endif
return &m_buffer[idx];
}
return &m_buffer[idx];
}
T &operator[](uint idx)
{
T& operator[](uint idx)
{
#if pxUSE_SECURE_MALLOC
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#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
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
#endif
return m_buffer[idx];
}
return m_buffer[idx];
}
};
// --------------------------------------------------------------------------------------
@ -175,42 +175,42 @@ public:
template <typename T>
class ScopedAlloc : public BaseScopedAlloc<T>
{
typedef BaseScopedAlloc<T> _parent;
typedef BaseScopedAlloc<T> _parent;
public:
ScopedAlloc(size_t size = 0)
: _parent()
{
Alloc(size);
}
ScopedAlloc(size_t size = 0)
: _parent()
{
Alloc(size);
}
virtual ~ScopedAlloc()
{
safe_free(this->m_buffer);
}
virtual ~ScopedAlloc()
{
safe_free(this->m_buffer);
}
virtual void Alloc(size_t newsize)
{
safe_free(this->m_buffer);
this->m_size = newsize;
if (!this->m_size)
return;
virtual void Alloc(size_t newsize)
{
safe_free(this->m_buffer);
this->m_size = newsize;
if (!this->m_size)
return;
this->m_buffer = (T *)malloc(this->m_size * sizeof(T));
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc");
}
this->m_buffer = (T*)malloc(this->m_size * sizeof(T));
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc");
}
virtual void Resize(size_t newsize)
{
this->m_size = newsize;
this->m_buffer = (T *)realloc(this->m_buffer, this->m_size * sizeof(T));
virtual void Resize(size_t newsize)
{
this->m_size = newsize;
this->m_buffer = (T*)realloc(this->m_buffer, this->m_size * sizeof(T));
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
}
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
}
using _parent::operator[];
using _parent::operator[];
};
// --------------------------------------------------------------------------------------
@ -225,40 +225,40 @@ public:
template <typename T, uint align>
class ScopedAlignedAlloc : public BaseScopedAlloc<T>
{
typedef BaseScopedAlloc<T> _parent;
typedef BaseScopedAlloc<T> _parent;
public:
ScopedAlignedAlloc(size_t size = 0)
: _parent()
{
Alloc(size);
}
ScopedAlignedAlloc(size_t size = 0)
: _parent()
{
Alloc(size);
}
virtual ~ScopedAlignedAlloc()
{
safe_aligned_free(this->m_buffer);
}
virtual ~ScopedAlignedAlloc()
{
safe_aligned_free(this->m_buffer);
}
virtual void Alloc(size_t newsize)
{
safe_aligned_free(this->m_buffer);
this->m_size = newsize;
if (!this->m_size)
return;
virtual void Alloc(size_t newsize)
{
safe_aligned_free(this->m_buffer);
this->m_size = newsize;
if (!this->m_size)
return;
this->m_buffer = (T *)_aligned_malloc(this->m_size * sizeof(T), align);
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
}
this->m_buffer = (T*)_aligned_malloc(this->m_size * sizeof(T), align);
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
}
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_size = 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_size = newsize;
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
}
if (!this->m_buffer)
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
}
using _parent::operator[];
using _parent::operator[];
};

View File

@ -25,91 +25,91 @@ using Threading::ScopedLock;
template <typename T>
class ScopedPtrMT
{
DeclareNoncopyableObject(ScopedPtrMT);
DeclareNoncopyableObject(ScopedPtrMT);
protected:
std::atomic<T *> m_ptr;
Threading::Mutex m_mtx;
std::atomic<T*> m_ptr;
Threading::Mutex m_mtx;
public:
typedef T element_type;
typedef T element_type;
wxEXPLICIT ScopedPtrMT(T *ptr = nullptr)
{
m_ptr = ptr;
}
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
{
m_ptr = ptr;
}
~ScopedPtrMT() { _Delete_unlocked(); }
~ScopedPtrMT() { _Delete_unlocked(); }
ScopedPtrMT &Reassign(T *ptr = nullptr)
{
T *doh = m_ptr.exchange(ptr);
if (ptr != doh)
delete doh;
return *this;
}
ScopedPtrMT& Reassign(T* ptr = nullptr)
{
T* doh = m_ptr.exchange(ptr);
if (ptr != doh)
delete doh;
return *this;
}
ScopedPtrMT &Delete() noexcept
{
ScopedLock lock(m_mtx);
_Delete_unlocked();
}
ScopedPtrMT& Delete() noexcept
{
ScopedLock lock(m_mtx);
_Delete_unlocked();
}
// Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method)
T *DetachPtr()
{
ScopedLock lock(m_mtx);
// Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method)
T* DetachPtr()
{
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
// has no object in management.
T *GetPtr() const
{
return m_ptr;
}
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
// has no object in management.
T* GetPtr() const
{
return m_ptr;
}
void SwapPtr(ScopedPtrMT &other)
{
ScopedLock lock(m_mtx);
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
T *const tmp = other.m_ptr;
other.m_ptr = m_ptr;
m_ptr = tmp;
}
void SwapPtr(ScopedPtrMT& other)
{
ScopedLock lock(m_mtx);
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
T* const tmp = other.m_ptr;
other.m_ptr = m_ptr;
m_ptr = tmp;
}
// ----------------------------------------------------------------------------
// ScopedPtrMT Operators
// ----------------------------------------------------------------------------
// 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
// allow the T* implicit casting.
// ----------------------------------------------------------------------------
// ScopedPtrMT Operators
// ----------------------------------------------------------------------------
// 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
// allow the T* implicit casting.
bool operator!() const noexcept
{
return m_ptr.load() == nullptr;
}
bool operator!() const noexcept
{
return m_ptr.load() == nullptr;
}
// Equality
bool operator==(T *pT) const noexcept
{
return m_ptr == pT;
}
// Equality
bool operator==(T* pT) const noexcept
{
return m_ptr == pT;
}
// Inequality
bool operator!=(T *pT) const noexcept
{
return !operator==(pT);
}
// Inequality
bool operator!=(T* pT) const noexcept
{
return !operator==(pT);
}
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer.
ScopedPtrMT &operator=(T *src)
{
return Reassign(src);
}
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer.
ScopedPtrMT& operator=(T* src)
{
return Reassign(src);
}
#if 0
operator T*() const
@ -133,8 +133,8 @@ public:
#endif
protected:
void _Delete_unlocked() noexcept
{
delete m_ptr.exchange(nullptr);
}
void _Delete_unlocked() noexcept
{
delete m_ptr.exchange(nullptr);
}
};

View File

@ -26,49 +26,50 @@
Threading::Semaphore::Semaphore()
{
sem_init(&m_sema, false, 0);
sem_init(&m_sema, false, 0);
}
Threading::Semaphore::~Semaphore()
{
sem_destroy(&m_sema);
sem_destroy(&m_sema);
}
void Threading::Semaphore::Reset()
{
sem_destroy(&m_sema);
sem_init(&m_sema, false, 0);
sem_destroy(&m_sema);
sem_init(&m_sema, false, 0);
}
void Threading::Semaphore::Post()
{
sem_post(&m_sema);
sem_post(&m_sema);
}
void Threading::Semaphore::Post(int multiple)
{
#if defined(_MSC_VER)
sem_post_multiple(&m_sema, multiple);
sem_post_multiple(&m_sema, multiple);
#else
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
while (multiple > 0) {
multiple--;
sem_post(&m_sema);
}
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
while (multiple > 0)
{
multiple--;
sem_post(&m_sema);
}
#endif
}
void Threading::Semaphore::WaitWithoutYield()
{
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
sem_wait(&m_sema);
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
sem_wait(&m_sema);
}
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
{
wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return sem_timedwait(&m_sema, &fail) == 0;
wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return sem_timedwait(&m_sema, &fail) == 0;
}
@ -80,18 +81,23 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
void Threading::Semaphore::Wait()
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
sem_wait(&m_sema);
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
sem_wait(&m_sema);
} else {
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!WaitWithoutYield(def_yieldgui_interval))
YieldToMain();
}
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
sem_wait(&m_sema);
}
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
{
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
sem_wait(&m_sema);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!WaitWithoutYield(def_yieldgui_interval))
YieldToMain();
}
#else
sem_wait(&m_sema);
sem_wait(&m_sema);
#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
// reached prior to timeout.
//
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
return WaitWithoutYield(timeout);
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
return WaitWithoutYield(timeout);
} else {
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
return WaitWithoutYield(timeout);
}
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
{
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
return WaitWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do {
if (WaitWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
do
{
if (WaitWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0;
}
return countdown.GetMilliseconds() > 0;
}
#else
return WaitWithoutYield(timeout);
return WaitWithoutYield(timeout);
#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.
void Threading::Semaphore::WaitNoCancel()
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield();
Wait();
pthread_setcancelstate(oldstate, NULL);
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield();
Wait();
pthread_setcancelstate(oldstate, NULL);
}
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout)
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield( timeout );
Wait(timeout);
pthread_setcancelstate(oldstate, NULL);
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield( timeout );
Wait(timeout);
pthread_setcancelstate(oldstate, NULL);
}
int Threading::Semaphore::Count()
{
int retval;
sem_getvalue(&m_sema, &retval);
return retval;
int retval;
sem_getvalue(&m_sema, &retval);
return retval;
}
#endif

View File

@ -17,59 +17,59 @@
#include "common/Pcsx2Defs.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
// 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
// we use a LOCAL instance of wxMBConvUTF8(). --air
// 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
// 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
// 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
// uses the stupid globals in the first place!) --air
// 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
// 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
{
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
{
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
{
FastFormatUnicode result;
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
for (uint i = 2; i < 16; i += 2)
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
return result;
FastFormatUnicode result;
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
for (uint i = 2; i < 16; i += 2)
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
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]);
for (uint i = 2; i < 16; i += 2)
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
for (uint i = 2; i < 16; i += 2)
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
}
// 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
// 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);
while (parts.HasMoreTokens())
dest.Add(parts.GetNextToken());
wxStringTokenizer parts(src, delims, mode);
while (parts.HasMoreTokens())
dest.Add(parts.GetNextToken());
}
// 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
// my own.
wxString JoinString(const wxArrayString &src, const wxString &separator)
wxString JoinString(const wxArrayString& src, const wxString& separator)
{
wxString dest;
for (int i = 0, len = src.GetCount(); i < len; ++i) {
if (src[i].IsEmpty())
continue;
if (!dest.IsEmpty())
dest += separator;
dest += src[i];
}
return dest;
wxString dest;
for (int i = 0, len = src.GetCount(); i < len; ++i)
{
if (src[i].IsEmpty())
continue;
if (!dest.IsEmpty())
dest += separator;
dest += src[i];
}
return dest;
}
wxString JoinString(const wxChar **src, const wxString &separator)
wxString JoinString(const wxChar** src, const wxString& separator)
{
wxString dest;
while (*src != NULL) {
if (*src[0] == 0)
continue;
wxString dest;
while (*src != NULL)
{
if (*src[0] == 0)
continue;
if (!dest.IsEmpty())
dest += separator;
dest += *src;
++src;
}
return dest;
if (!dest.IsEmpty())
dest += separator;
dest += *src;
++src;
}
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.
//
template <typename T>
T Parse(const wxString &src, const wxString &separators = L",")
T Parse(const wxString& src, const wxString& separators = L",")
{
T retval;
if (!TryParse(retval, src, separators))
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
return retval;
T retval;
if (!TryParse(retval, src, separators))
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
return retval;
}
@ -141,104 +143,104 @@ T Parse(const wxString &src, const wxString &separators = L",")
// --------------------------------------------------------------------------------------
// 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!
// 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!
// --------------------------------------------------------------------------------------
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]))
return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false;
dest.x = result[0];
dest.y = result[1];
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false;
dest.x = result[0];
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]))
return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false;
dest.SetWidth(result[0]);
dest.SetHeight(result[1]);
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
return false;
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
return false;
dest.SetWidth(result[0]);
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
// 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;
wxStringTokenizer parts(src, separators);
return TryParse(dest, parts);
dest = defval;
wxStringTokenizer parts(src, separators);
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;
wxStringTokenizer parts(src, separators);
return TryParse(dest, parts);
dest = defval;
wxStringTokenizer parts(src, separators);
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;
wxSize size;
wxPoint point;
wxSize size;
if (!TryParse(point, parts))
return false;
if (!TryParse(size, parts))
return false;
if (!TryParse(point, parts))
return false;
if (!TryParse(size, parts))
return false;
dest = wxRect(point, size);
return true;
dest = wxRect(point, size);
return true;
}
// 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";"))
return false;
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
return false;
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
ldest = src.BeforeFirst(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,
@ -249,37 +251,41 @@ ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
// from incoming data. Mac platforms may need an implementation of their own that converts
// newlines to CRs...?
//
void px_fputs(FILE *fp, const char *src)
void px_fputs(FILE* fp, const char* src)
{
if (fp == NULL)
return;
if (fp == NULL)
return;
#ifdef _WIN32
// 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.. >_<
// 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.. >_<
const char *curchar = src;
bool prevcr = false;
while (*curchar != 0) {
if (*curchar == '\r') {
prevcr = true;
} else {
// Only write a CR/LF pair if the current LF is not prefixed nor
// post-fixed by a CR.
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
fputs("\r\n", fp);
else
fputc(*curchar, fp);
const char* curchar = src;
bool prevcr = false;
while (*curchar != 0)
{
if (*curchar == '\r')
{
prevcr = true;
}
else
{
// Only write a CR/LF pair if the current LF is not prefixed nor
// post-fixed by a CR.
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
fputs("\r\n", fp);
else
fputc(*curchar, fp);
prevcr = false;
}
++curchar;
}
prevcr = false;
}
++curchar;
}
#else
// 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?
// 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?
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
}

View File

@ -24,7 +24,7 @@
#define WX_STR(str) (str.wc_str())
#else
// 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
// --------------------------------------------------------------------------------------
@ -33,59 +33,59 @@
// Converts a string to UTF8 and provides an interface for getting its length.
class pxToUTF8
{
DeclareNoncopyableObject(pxToUTF8);
DeclareNoncopyableObject(pxToUTF8);
protected:
wxCharBuffer m_result;
int m_length;
wxCharBuffer m_result;
int m_length;
public:
explicit pxToUTF8(const wxString &src)
: m_result(src.ToUTF8())
{
m_length = -1;
}
explicit pxToUTF8(const wxString& src)
: m_result(src.ToUTF8())
{
m_length = -1;
}
size_t Length()
{
if (-1 == m_length)
m_length = strlen(m_result);
return m_length;
}
size_t Length()
{
if (-1 == m_length)
m_length = strlen(m_result);
return m_length;
}
void Convert(const wxString &src)
{
m_result = src.ToUTF8();
m_length = -1;
}
void Convert(const wxString& src)
{
m_result = src.ToUTF8();
m_length = -1;
}
const char *data() const { return m_result; }
const char* data() const { return m_result; }
operator const char *() const
{
return m_result.data();
}
operator const char*() const
{
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...
extern const wxRect wxDefaultRect;
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 wxChar **src, const wxString &separator);
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 wxChar** src, const wxString& separator);
extern wxString ToString(const wxPoint &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 wxPoint& 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 bool TryParse(wxPoint &dest, const wxStringTokenizer &parts);
extern bool TryParse(wxSize &dest, const wxStringTokenizer &parts);
extern bool TryParse(wxPoint& 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(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(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(wxRect& dest, const wxString& src, const wxRect& defval = wxDefaultRect, const wxString& separators = L",");
// --------------------------------------------------------------------------------------
// ParsedAssignmentString
@ -103,11 +103,11 @@ extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = w
//
struct ParsedAssignmentString
{
wxString lvalue;
wxString rvalue;
bool IsComment;
wxString lvalue;
wxString rvalue;
bool IsComment;
ParsedAssignmentString(const wxString &src);
ParsedAssignmentString(const wxString& src);
};
// ======================================================================================
@ -139,40 +139,40 @@ typedef ScopedAlignedAlloc<char, 16> CharBufferType;
class FastFormatAscii
{
protected:
CharBufferType m_dest;
CharBufferType m_dest;
public:
FastFormatAscii();
~FastFormatAscii() = default;
FastFormatAscii &Write(const char *fmt, ...);
FastFormatAscii &WriteV(const char *fmt, va_list argptr);
FastFormatAscii();
~FastFormatAscii() = default;
FastFormatAscii& Write(const char* fmt, ...);
FastFormatAscii& WriteV(const char* fmt, va_list argptr);
void Clear();
bool IsEmpty() const;
void Clear();
bool IsEmpty() const;
const char *c_str() const { return m_dest.GetPtr(); }
operator const char *() const { return m_dest.GetPtr(); }
const char* c_str() const { return m_dest.GetPtr(); }
operator const char*() const { return m_dest.GetPtr(); }
const wxString GetString() const;
//operator wxString() const;
const wxString GetString() const;
//operator wxString() const;
FastFormatAscii &operator+=(const wxString &s)
{
Write("%s", WX_STR(s));
return *this;
}
FastFormatAscii& operator+=(const wxString& s)
{
Write("%s", WX_STR(s));
return *this;
}
FastFormatAscii &operator+=(const wxChar *psz)
{
Write("%ls", psz);
return *this;
}
FastFormatAscii& operator+=(const wxChar* psz)
{
Write("%ls", psz);
return *this;
}
FastFormatAscii &operator+=(const char *psz)
{
Write("%s", psz);
return *this;
}
FastFormatAscii& operator+=(const char* psz)
{
Write("%s", psz);
return *this;
}
};
// --------------------------------------------------------------------------------------
@ -181,54 +181,54 @@ public:
class FastFormatUnicode
{
protected:
CharBufferType m_dest;
uint m_Length;
CharBufferType m_dest;
uint m_Length;
public:
FastFormatUnicode();
~FastFormatUnicode() = default;
FastFormatUnicode();
~FastFormatUnicode() = default;
FastFormatUnicode &Write(const char *fmt, ...);
FastFormatUnicode &Write(const wxChar *fmt, ...);
FastFormatUnicode &Write(const wxString fmt, ...);
FastFormatUnicode &WriteV(const char *fmt, va_list argptr);
FastFormatUnicode &WriteV(const wxChar *fmt, va_list argptr);
FastFormatUnicode& Write(const char* fmt, ...);
FastFormatUnicode& Write(const wxChar* fmt, ...);
FastFormatUnicode& Write(const wxString fmt, ...);
FastFormatUnicode& WriteV(const char* fmt, va_list argptr);
FastFormatUnicode& WriteV(const wxChar* fmt, va_list argptr);
void Clear();
bool IsEmpty() const;
uint Length() const { return m_Length; }
void Clear();
bool IsEmpty() const;
uint Length() const { return m_Length; }
FastFormatUnicode &ToUpper();
FastFormatUnicode &ToLower();
FastFormatUnicode& ToUpper();
FastFormatUnicode& ToLower();
const wxChar *c_str() 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(); }
const wxChar* c_str() 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(); }
FastFormatUnicode &operator+=(const wxString &s)
{
Write(L"%s", WX_STR(s));
return *this;
}
FastFormatUnicode& operator+=(const wxString& s)
{
Write(L"%s", WX_STR(s));
return *this;
}
FastFormatUnicode &operator+=(const wxChar *psz)
{
Write(L"%s", psz);
return *this;
}
FastFormatUnicode& operator+=(const wxChar* psz)
{
Write(L"%s", psz);
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 pxsFmtV FastFormatUnicode().WriteV
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
extern wxString &operator+=(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 FastFormatUnicode &str1, const wxString &str2);
extern wxString operator+(const FastFormatUnicode &str1, const wxChar *str2);
extern wxString& operator+=(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 FastFormatUnicode& str1, const wxString& 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()
{
static const TraceLogDescriptor myDesc =
{
L"p&xThread", L"pxThread",
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
static const TraceLogDescriptor myDesc =
{
L"p&xThread", L"pxThread",
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
m_Descriptor = &myDesc;
m_Descriptor = &myDesc;
}
ConsoleLogSource_Threading pxConLog_Thread;
@ -47,18 +47,18 @@ ConsoleLogSource_Threading pxConLog_Thread;
class StaticMutex : public Mutex
{
protected:
bool &m_DeletedFlag;
bool& m_DeletedFlag;
public:
StaticMutex(bool &deletedFlag)
: m_DeletedFlag(deletedFlag)
{
}
StaticMutex(bool& deletedFlag)
: m_DeletedFlag(deletedFlag)
{
}
virtual ~StaticMutex()
{
m_DeletedFlag = true;
}
virtual ~StaticMutex()
{
m_DeletedFlag = true;
}
};
static pthread_key_t curthread_key = 0;
@ -67,111 +67,115 @@ static s32 total_key_count = 0;
static bool tkl_destructed = false;
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);
if (total_key_count++ != 0)
return;
ScopedLock lock(total_key_lock);
if (total_key_count++ != 0)
return;
if (0 != pthread_key_create(&curthread_key, NULL)) {
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
curthread_key = 0;
}
if (0 != pthread_key_create(&curthread_key, NULL))
{
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
curthread_key = 0;
}
}
static void unmake_curthread_key()
{
ScopedLock lock;
if (!tkl_destructed)
lock.AssignAndLock(total_key_lock);
ScopedLock lock;
if (!tkl_destructed)
lock.AssignAndLock(total_key_lock);
if (--total_key_count > 0)
return;
if (--total_key_count > 0)
return;
if (curthread_key)
pthread_key_delete(curthread_key);
if (curthread_key)
pthread_key_delete(curthread_key);
curthread_key = 0;
curthread_key = 0;
}
void Threading::pxTestCancel()
{
pthread_testcancel();
pthread_testcancel();
}
// 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
// through pxThread it will also return NULL. Callers can use wxThread::IsMain() to
// 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
// nor the Main/UI thread.
wxString Threading::pxGetCurrentThreadName()
{
if (pxThread *thr = pxGetCurrentThread()) {
return thr->GetName();
} else if (wxThread::IsMain()) {
return L"Main/UI";
}
if (pxThread* thr = pxGetCurrentThread())
{
return thr->GetName();
}
else if (wxThread::IsMain())
{
return L"Main/UI";
}
return L"Unknown";
return L"Unknown";
}
void Threading::pxYield(int ms)
{
if (pxThread *thr = pxGetCurrentThread())
thr->Yield(ms);
else
Sleep(ms);
if (pxThread* thr = pxGetCurrentThread())
thr->Yield(ms);
else
Sleep(ms);
}
// (intended for internal use only)
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
// 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.
// 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.
// 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
// against them here and, if recursion is detected, perform a standard blocking wait.
static int __Guard = 0;
RecursionGuard guard(__Guard);
static int __Guard = 0;
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())
return false;
pxThreadLog.Write(pxGetCurrentThreadName(),
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
return true;
if (!guard.IsReentrant())
return false;
pxThreadLog.Write(pxGetCurrentThreadName(),
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
return true;
}
__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)
: m_name(name)
, m_thread()
, m_native_id(0)
, m_native_handle(0)
, m_detached(true) // start out with m_thread in detached/invalid state
, m_running(false)
Threading::pxThread::pxThread(const wxString& name)
: m_name(name)
, m_thread()
, m_native_id(0)
, m_native_handle(0)
, m_detached(true) // start out with m_thread in detached/invalid state
, 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.
Threading::pxThread::~pxThread()
{
try {
pxThreadLog.Write(GetName(), L"Executing default destructor!");
try
{
pxThreadLog.Write(GetName(), L"Executing default destructor!");
if (m_running) {
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
m_mtx_InThread.Wait();
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
}
Threading::Sleep(1);
Detach();
}
DESTRUCTOR_CATCHALL
if (m_running)
{
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
m_mtx_InThread.Wait();
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
}
Threading::Sleep(1);
Detach();
}
DESTRUCTOR_CATCHALL
}
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const
{
if (IsSelf())
return true;
if (IsSelf())
return true;
if (IsDevBuild)
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
if (IsDevBuild)
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())
return true;
if (!IsSelf())
return true;
if (IsDevBuild)
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
if (IsDevBuild)
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()) {
// Our lock is bupkis, which means the previous thread probably deadlocked.
// Let's create a new mutex lock to replace it.
if (mutex.RecreateIfLocked())
{
// 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
@ -238,53 +245,56 @@ void Threading::pxThread::FrankenMutex(Mutex &mutex)
// This function should not be called from the owner thread.
void Threading::pxThread::Start()
{
// Prevents sudden parallel startup, and or parallel startup + cancel:
ScopedLock startlock(m_mtx_start);
if (m_running) {
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
return;
}
// Prevents sudden parallel startup, and or parallel startup + cancel:
ScopedLock startlock(m_mtx_start);
if (m_running)
{
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
return;
}
Detach(); // clean up previous thread handle, if one exists.
OnStart();
Detach(); // clean up previous thread handle, if one exists.
OnStart();
m_except = NULL;
m_except = NULL;
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
#ifdef ASAN_WORKAROUND
// 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
// waiting... So waits 100ms and checks the counter value manually
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.");
}
// 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
// waiting... So waits 100ms and checks the counter value manually
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.");
}
#else
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0))) {
RethrowException();
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0)))
{
RethrowException();
// And if the thread threw nothing of its own:
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
}
// And if the thread threw nothing of its own:
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
}
#endif
// 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
// (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
// 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
// overhead in starting threads).
// 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
// (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
// 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
// overhead in starting threads).
// (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
// 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-
// possible to safely block against a running thread)
// (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
// 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-
// possible to safely block against a running thread)
}
// 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.
bool Threading::pxThread::Detach()
{
AffinityAssert_DisallowFromSelf(pxDiagSpot);
AffinityAssert_DisallowFromSelf(pxDiagSpot);
if (m_detached.exchange(true))
return false;
pthread_detach(m_thread);
return true;
if (m_detached.exchange(true))
return false;
pthread_detach(m_thread);
return true;
}
bool Threading::pxThread::_basecancel()
{
if (!m_running)
return false;
if (!m_running)
return false;
if (m_detached) {
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
return false;
}
if (m_detached)
{
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
return false;
}
pthread_cancel(m_thread);
return true;
pthread_cancel(m_thread);
return true;
}
// Remarks:
@ -330,34 +341,35 @@ bool Threading::pxThread::_basecancel()
//
void Threading::pxThread::Cancel(bool isBlocking)
{
AffinityAssert_DisallowFromSelf(pxDiagSpot);
AffinityAssert_DisallowFromSelf(pxDiagSpot);
// Prevent simultaneous startup and cancel, necessary to avoid
ScopedLock startlock(m_mtx_start);
// Prevent simultaneous startup and cancel, necessary to avoid
ScopedLock startlock(m_mtx_start);
if (!_basecancel())
return;
if (!_basecancel())
return;
if (isBlocking) {
WaitOnSelf(m_mtx_InThread);
Detach();
}
if (isBlocking)
{
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:
ScopedLock startlock(m_mtx_start);
// Prevent simultaneous startup and cancel:
ScopedLock startlock(m_mtx_start);
if (!_basecancel())
return true;
if (!_basecancel())
return true;
if (!WaitOnSelf(m_mtx_InThread, timespan))
return false;
Detach();
return true;
if (!WaitOnSelf(m_mtx_InThread, timespan))
return false;
Detach();
return true;
}
@ -373,32 +385,32 @@ bool Threading::pxThread::Cancel(const wxTimeSpan &timespan)
//
void Threading::pxThread::Block()
{
AffinityAssert_DisallowFromSelf(pxDiagSpot);
WaitOnSelf(m_mtx_InThread);
AffinityAssert_DisallowFromSelf(pxDiagSpot);
WaitOnSelf(m_mtx_InThread);
}
bool Threading::pxThread::Block(const wxTimeSpan &timeout)
bool Threading::pxThread::Block(const wxTimeSpan& timeout)
{
AffinityAssert_DisallowFromSelf(pxDiagSpot);
return WaitOnSelf(m_mtx_InThread, timeout);
AffinityAssert_DisallowFromSelf(pxDiagSpot);
return WaitOnSelf(m_mtx_InThread, timeout);
}
bool Threading::pxThread::IsSelf() const
{
// Detached threads may have their pthread handles recycled as newer threads, causing
// false IsSelf reports.
return !m_detached && (pthread_self() == m_thread);
// Detached threads may have their pthread handles recycled as newer threads, causing
// false IsSelf reports.
return !m_detached && (pthread_self() == m_thread);
}
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);
m_evtsrc_OnDelete.Add(evt);
evt.SetThread(this);
m_evtsrc_OnDelete.Add(evt);
}
// 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.
void Threading::pxThread::RethrowException() const
{
// 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
// after.
// 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
// after.
ScopedExcept ptr(const_cast<pxThread *>(this)->m_except.DetachPtr());
if (ptr)
ptr->Rethrow();
ScopedExcept ptr(const_cast<pxThread*>(this)->m_except.DetachPtr());
if (ptr)
ptr->Rethrow();
}
static bool m_BlockDeletions = false;
bool Threading::AllowDeletions()
{
AffinityAssert_AllowFrom_MainUI();
return !m_BlockDeletions;
AffinityAssert_AllowFrom_MainUI();
return !m_BlockDeletions;
}
void Threading::YieldToMain()
{
m_BlockDeletions = true;
wxTheApp->Yield(true);
m_BlockDeletions = false;
m_BlockDeletions = true;
wxTheApp->Yield(true);
m_BlockDeletions = false;
}
void Threading::pxThread::_selfRunningTest(const wxChar *name) const
void Threading::pxThread::_selfRunningTest(const wxChar* name) const
{
if (HasPendingException()) {
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
RethrowException();
}
if (HasPendingException())
{
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
RethrowException();
}
if (!m_running) {
throw Exception::CancelEvent(pxsFmt(
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
WX_STR(GetName()), name));
}
if (!m_running)
{
throw Exception::CancelEvent(pxsFmt(
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
// 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).
// 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
// objects from being deleted until outside the scope of a mutex/semaphore wait).
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
Threading::YieldToMain();
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
Threading::YieldToMain();
}
// 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
// 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))
return;
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return;
while (true) {
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
return;
_selfRunningTest(L"semaphore");
}
while (true)
{
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
return;
_selfRunningTest(L"semaphore");
}
}
// 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
// terminated).
//
void Threading::pxThread::WaitOnSelf(Mutex &mutex) const
void Threading::pxThread::WaitOnSelf(Mutex& mutex) const
{
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return;
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return;
while (true) {
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
return;
_selfRunningTest(L"mutex");
}
while (true)
{
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
return;
_selfRunningTest(L"mutex");
}
}
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))
return true;
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return true;
wxTimeSpan runningout(timeout);
wxTimeSpan runningout(timeout);
while (runningout.GetMilliseconds() > 0) {
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
if (sem.WaitWithoutYield(interval))
return true;
_selfRunningTest(L"semaphore");
runningout -= interval;
}
return false;
while (runningout.GetMilliseconds() > 0)
{
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
if (sem.WaitWithoutYield(interval))
return true;
_selfRunningTest(L"semaphore");
runningout -= interval;
}
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))
return true;
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
return true;
wxTimeSpan runningout(timeout);
wxTimeSpan runningout(timeout);
while (runningout.GetMilliseconds() > 0) {
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
if (mutex.WaitWithoutYield(interval))
return true;
_selfRunningTest(L"mutex");
runningout -= interval;
}
return false;
while (runningout.GetMilliseconds() > 0)
{
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
if (mutex.WaitWithoutYield(interval))
return true;
_selfRunningTest(L"mutex");
runningout -= interval;
}
return false;
}
// 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).
void Threading::pxThread::TestCancel() const
{
AffinityAssert_AllowFromSelf(pxDiagSpot);
pthread_testcancel();
AffinityAssert_AllowFromSelf(pxDiagSpot);
pthread_testcancel();
}
// Executes the virtual member method
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
{
try {
(this->*method)();
}
try
{
(this->*method)();
}
// ----------------------------------------------------------------------------
// Neat repackaging for STL Runtime errors...
//
catch (std::runtime_error &ex) {
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
}
// ----------------------------------------------------------------------------
// Neat repackaging for STL Runtime errors...
//
catch (std::runtime_error& ex)
{
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
}
// ----------------------------------------------------------------------------
catch (Exception::RuntimeError &ex) {
BaseException *woot = ex.Clone();
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
m_except = woot;
}
// ----------------------------------------------------------------------------
catch (Exception::RuntimeError& ex)
{
BaseException* woot = ex.Clone();
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
m_except = woot;
}
#ifndef PCSX2_DEVBUILD
// ----------------------------------------------------------------------------
// 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
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
/*catch( std::logic_error& ex )
// ----------------------------------------------------------------------------
// 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
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
/*catch( std::logic_error& ex )
{
throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s",
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() )) )
);
}*/
// ----------------------------------------------------------------------------
// BaseException -- same deal as LogicErrors.
//
catch (BaseException &ex) {
BaseException *woot = ex.Clone();
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
m_except = woot;
}
// ----------------------------------------------------------------------------
// BaseException -- same deal as LogicErrors.
//
catch (BaseException& ex)
{
BaseException* woot = ex.Clone();
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
m_except = woot;
}
#endif
}
@ -597,25 +619,25 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
// OnCleanupInThread() to extend cleanup functionality.
void Threading::pxThread::_ThreadCleanup()
{
AffinityAssert_AllowFromSelf(pxDiagSpot);
_try_virtual_invoke(&pxThread::OnCleanupInThread);
m_mtx_InThread.Release();
AffinityAssert_AllowFromSelf(pxDiagSpot);
_try_virtual_invoke(&pxThread::OnCleanupInThread);
m_mtx_InThread.Release();
// 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.
m_running = false;
// 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.
m_running = false;
}
wxString Threading::pxThread::GetName() const
{
ScopedLock lock(m_mtx_ThreadName);
return m_name;
ScopedLock lock(m_mtx_ThreadName);
return m_name;
}
void Threading::pxThread::SetName(const wxString &newname)
void Threading::pxThread::SetName(const wxString& newname)
{
ScopedLock lock(m_mtx_ThreadName);
m_name = newname;
ScopedLock lock(m_mtx_ThreadName);
m_name = newname;
}
// 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()
{
m_detached = false;
m_running = true;
m_detached = false;
m_running = true;
_platform_specific_OnStartInThread();
_platform_specific_OnStartInThread();
}
void Threading::pxThread::_internal_execute()
{
m_mtx_InThread.Acquire();
m_mtx_InThread.Acquire();
_DoSetThreadName(GetName());
make_curthread_key(this);
if (curthread_key)
pthread_setspecific(curthread_key, this);
_DoSetThreadName(GetName());
make_curthread_key(this);
if (curthread_key)
pthread_setspecific(curthread_key, this);
OnStartInThread();
m_sem_startup.Post();
OnStartInThread();
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
// running thread has been canceled or detached.
void Threading::pxThread::OnStart()
{
m_native_handle = 0;
m_native_id = 0;
m_native_handle = 0;
m_native_id = 0;
FrankenMutex(m_mtx_InThread);
m_sem_event.Reset();
m_sem_startup.Reset();
FrankenMutex(m_mtx_InThread);
m_sem_event.Reset();
m_sem_startup.Reset();
}
// Extending classes that override this method should always call it last from their
// personal implementations.
void Threading::pxThread::OnCleanupInThread()
{
if (curthread_key)
pthread_setspecific(curthread_key, NULL);
if (curthread_key)
pthread_setspecific(curthread_key, NULL);
unmake_curthread_key();
unmake_curthread_key();
_platform_specific_OnCleanupInThread();
_platform_specific_OnCleanupInThread();
m_native_handle = 0;
m_native_id = 0;
m_native_handle = 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
// callback function
void *Threading::pxThread::_internal_callback(void *itsme)
void* Threading::pxThread::_internal_callback(void* itsme)
{
if (!pxAssertDev(itsme != NULL, wxNullChar))
return NULL;
if (!pxAssertDev(itsme != NULL, wxNullChar))
return NULL;
internal_callback_helper(itsme);
return nullptr;
internal_callback_helper(itsme);
return nullptr;
}
// __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
// 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);
owner._internal_execute();
pthread_cleanup_pop(true);
pthread_cleanup_push(_pt_callback_cleanup, itsme);
owner._internal_execute();
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 null_str(L"Null Thread Object");
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
wxString null_str(L"Null Thread Object");
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
}
wxString Exception::BaseThreadError::FormatDisplayMessage() const
{
wxString null_str(L"Null Thread Object");
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
wxString null_str(L"Null Thread Object");
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.");
return *m_thread;
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
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.");
return *m_thread;
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
return *m_thread;
}

View File

@ -32,7 +32,7 @@
#undef Yield // release the burden of windows.h global namespace spam.
#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
@ -40,25 +40,25 @@
class ConsoleLogSource_Threading : ConsoleLogSource
{
typedef ConsoleLogSource _parent;
typedef ConsoleLogSource _parent;
public:
using _parent::IsActive;
using _parent::IsActive;
ConsoleLogSource_Threading();
ConsoleLogSource_Threading();
bool Write(const wxString &thrname, const wxChar *msg)
{
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Warn(const wxString &thrname, const wxChar *msg)
{
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Error(const wxString &thrname, const wxChar *msg)
{
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Write(const wxString& thrname, const wxChar* msg)
{
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Warn(const wxString& thrname, const wxChar* msg)
{
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Error(const wxString& thrname, const wxChar* msg)
{
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
};
extern ConsoleLogSource_Threading pxConLog_Thread;
@ -88,97 +88,97 @@ class wxTimeSpan;
namespace Threading
{
class pxThread;
class RwMutex;
class pxThread;
class RwMutex;
extern void pxTestCancel();
extern pxThread *pxGetCurrentThread();
extern wxString pxGetCurrentThreadName();
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
extern void pxTestCancel();
extern pxThread* pxGetCurrentThread();
extern wxString pxGetCurrentThreadName();
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
// Yields the current thread and provides cancellation points if the thread is managed by
// pxThread. Unmanaged threads use standard Sleep.
extern void pxYield(int ms);
}
// Yields the current thread and provides cancellation points if the thread is managed by
// pxThread. Unmanaged threads use standard Sleep.
extern void pxYield(int ms);
} // namespace Threading
namespace Exception
{
class BaseThreadError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
class BaseThreadError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
public:
Threading::pxThread *m_thread;
public:
Threading::pxThread* m_thread;
protected:
BaseThreadError()
{
m_thread = NULL;
}
protected:
BaseThreadError()
{
m_thread = NULL;
}
public:
explicit BaseThreadError(Threading::pxThread *_thread)
{
m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
public:
explicit BaseThreadError(Threading::pxThread* _thread)
{
m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
explicit BaseThreadError(Threading::pxThread &_thread)
{
m_thread = &_thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
explicit BaseThreadError(Threading::pxThread& _thread)
{
m_thread = &_thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
Threading::pxThread &Thread();
const Threading::pxThread &Thread() const;
};
Threading::pxThread& Thread();
const Threading::pxThread& Thread() const;
};
class ThreadCreationError : public BaseThreadError
{
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
class ThreadCreationError : public BaseThreadError
{
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
public:
explicit ThreadCreationError(Threading::pxThread *_thread)
{
m_thread = _thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
public:
explicit ThreadCreationError(Threading::pxThread* _thread)
{
m_thread = _thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
explicit ThreadCreationError(Threading::pxThread &_thread)
{
m_thread = &_thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
};
}
explicit ThreadCreationError(Threading::pxThread& _thread)
{
m_thread = &_thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
};
} // namespace Exception
namespace Threading
{
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
// Releases a timeslice to other threads.
extern void Timeslice();
// Releases a timeslice to other threads.
extern void Timeslice();
// For use in spin/wait loops.
extern void SpinWait();
// For use in spin/wait loops.
extern void SpinWait();
// Optional implementation to enable hires thread/process scheduler for the operating system.
// Needed by Windows, but might not be relevant to other platforms.
extern void EnableHiresScheduler();
extern void DisableHiresScheduler();
// Optional implementation to enable hires thread/process scheduler for the operating system.
// Needed by Windows, but might not be relevant to other platforms.
extern void EnableHiresScheduler();
extern void DisableHiresScheduler();
// sleeps the current thread for the given number of milliseconds.
extern void Sleep(int ms);
// sleeps the current thread for the given number of milliseconds.
extern void Sleep(int ms);
// 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)
@ -196,230 +196,230 @@ extern void Sleep(int ms);
};
#endif
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// 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
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// 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
// it later.
//
class NonblockingMutex
{
protected:
std::atomic_flag val;
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// 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
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// 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
// it later.
//
class NonblockingMutex
{
protected:
std::atomic_flag val;
public:
NonblockingMutex() { val.clear(); }
virtual ~NonblockingMutex() = default;
public:
NonblockingMutex() { val.clear(); }
virtual ~NonblockingMutex() = default;
bool TryAcquire() noexcept
{
return !val.test_and_set();
}
bool TryAcquire() noexcept
{
return !val.test_and_set();
}
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
bool IsLocked()
{
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
return false;
}
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
bool IsLocked()
{
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
return false;
}
void Release()
{
val.clear();
}
};
void Release()
{
val.clear();
}
};
class Semaphore
{
protected:
class Semaphore
{
protected:
#ifdef __APPLE__
semaphore_t m_sema;
int m_counter;
semaphore_t m_sema;
int m_counter;
#else
sem_t m_sema;
sem_t m_sema;
#endif
public:
Semaphore();
virtual ~Semaphore();
public:
Semaphore();
virtual ~Semaphore();
void Reset();
void Post();
void Post(int multiple);
void Reset();
void Post();
void Post(int multiple);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan &timeout);
void WaitNoCancel();
void WaitNoCancel(const wxTimeSpan &timeout);
int Count();
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
void WaitNoCancel();
void WaitNoCancel(const wxTimeSpan& timeout);
int Count();
void Wait();
bool Wait(const wxTimeSpan &timeout);
};
void Wait();
bool Wait(const wxTimeSpan& timeout);
};
class Mutex
{
protected:
pthread_mutex_t m_mutex;
class Mutex
{
protected:
pthread_mutex_t m_mutex;
public:
Mutex();
virtual ~Mutex();
virtual bool IsRecursive() const { return false; }
public:
Mutex();
virtual ~Mutex();
virtual bool IsRecursive() const { return false; }
void Recreate();
bool RecreateIfLocked();
void Detach();
void Recreate();
bool RecreateIfLocked();
void Detach();
void Acquire();
bool Acquire(const wxTimeSpan &timeout);
bool TryAcquire();
void Release();
void Acquire();
bool Acquire(const wxTimeSpan& timeout);
bool TryAcquire();
void Release();
void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan &timeout);
void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan& timeout);
void Wait();
bool Wait(const wxTimeSpan &timeout);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan &timeout);
void Wait();
bool Wait(const wxTimeSpan& timeout);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
protected:
// empty constructor used by MutexLockRecursive
Mutex(bool) {}
};
protected:
// empty constructor used by MutexLockRecursive
Mutex(bool) {}
};
class MutexRecursive : public Mutex
{
public:
MutexRecursive();
virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; }
};
class MutexRecursive : public Mutex
{
public:
MutexRecursive();
virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; }
};
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// 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
// will be automatically released on any return or exit from the function.
//
// Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales:
//
// 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
// *very* important).
//
// 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
// change, and typically those are only used in very special circumstances of their own.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// 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
// will be automatically released on any return or exit from the function.
//
// Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales:
//
// 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
// *very* important).
//
// 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
// change, and typically those are only used in very special circumstances of their own.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
protected:
Mutex *m_lock;
bool m_IsLocked;
protected:
Mutex* m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock();
explicit ScopedLock(const Mutex *locker = NULL);
explicit ScopedLock(const Mutex &locker);
void AssignAndLock(const Mutex &locker);
void AssignAndLock(const Mutex *locker);
public:
virtual ~ScopedLock();
explicit ScopedLock(const Mutex* locker = NULL);
explicit ScopedLock(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 Acquire();
void Release();
void Acquire();
bool IsLocked() const { return m_IsLocked; }
bool IsLocked() const { return m_IsLocked; }
protected:
// Special constructor used by ScopedTryLock
ScopedLock(const Mutex &locker, bool isTryLock);
};
protected:
// Special constructor used by ScopedTryLock
ScopedLock(const Mutex& locker, bool isTryLock);
};
class ScopedTryLock : public ScopedLock
{
public:
ScopedTryLock(const Mutex &locker)
: ScopedLock(locker, true)
{
}
virtual ~ScopedTryLock() = default;
bool Failed() const { return !m_IsLocked; }
};
class ScopedTryLock : public ScopedLock
{
public:
ScopedTryLock(const Mutex& locker)
: ScopedLock(locker, true)
{
}
virtual ~ScopedTryLock() = default;
bool Failed() const { return !m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// ScopedNonblockingLock
// --------------------------------------------------------------------------------------
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
//
class ScopedNonblockingLock
{
DeclareNoncopyableObject(ScopedNonblockingLock);
// --------------------------------------------------------------------------------------
// ScopedNonblockingLock
// --------------------------------------------------------------------------------------
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
//
class ScopedNonblockingLock
{
DeclareNoncopyableObject(ScopedNonblockingLock);
protected:
NonblockingMutex &m_lock;
bool m_IsLocked;
protected:
NonblockingMutex& m_lock;
bool m_IsLocked;
public:
ScopedNonblockingLock(NonblockingMutex &locker)
: m_lock(locker)
, m_IsLocked(m_lock.TryAcquire())
{
}
public:
ScopedNonblockingLock(NonblockingMutex& locker)
: m_lock(locker)
, m_IsLocked(m_lock.TryAcquire())
{
}
virtual ~ScopedNonblockingLock()
{
if (m_IsLocked)
m_lock.Release();
}
virtual ~ScopedNonblockingLock()
{
if (m_IsLocked)
m_lock.Release();
}
bool Failed() const { return !m_IsLocked; }
};
bool Failed() const { return !m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// ScopedLockBool
// --------------------------------------------------------------------------------------
// 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,
// and not actually depended on for thread synchronization...
// --------------------------------------------------------------------------------------
// ScopedLockBool
// --------------------------------------------------------------------------------------
// 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,
// and not actually depended on for thread synchronization...
struct ScopedLockBool
{
ScopedLock m_lock;
std::atomic<bool> &m_bool;
struct ScopedLockBool
{
ScopedLock m_lock;
std::atomic<bool>& m_bool;
ScopedLockBool(Mutex &mutexToLock, std::atomic<bool> &isLockedBool)
: m_lock(mutexToLock)
, m_bool(isLockedBool)
{
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
virtual ~ScopedLockBool()
{
m_bool.store(false, std::memory_order_relaxed);
}
void Acquire()
{
m_lock.Acquire();
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
void Release()
{
m_bool.store(false, std::memory_order_relaxed);
m_lock.Release();
}
};
}
ScopedLockBool(Mutex& mutexToLock, std::atomic<bool>& isLockedBool)
: m_lock(mutexToLock)
, m_bool(isLockedBool)
{
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
virtual ~ScopedLockBool()
{
m_bool.store(false, std::memory_order_relaxed);
}
void Acquire()
{
m_lock.Acquire();
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
void Release()
{
m_bool.store(false, std::memory_order_relaxed);
m_lock.Release();
}
};
} // namespace Threading

View File

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

View File

@ -22,31 +22,31 @@ wxDECLARE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
namespace Threading
{
// --------------------------------------------------------------------------------------
// WaitForTaskDialog
// --------------------------------------------------------------------------------------
// 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
// 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
// to continue to manage threads and process logging).
//
class WaitForTaskDialog : public wxDialogWithHelpers
{
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
// --------------------------------------------------------------------------------------
// WaitForTaskDialog
// --------------------------------------------------------------------------------------
// 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
// 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
// to continue to manage threads and process logging).
//
class WaitForTaskDialog : public wxDialogWithHelpers
{
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
typedef wxDialogWithHelpers _parent;
typedef wxDialogWithHelpers _parent;
protected:
SynchronousActionState m_sync;
protected:
SynchronousActionState m_sync;
public:
WaitForTaskDialog(const wxString &title = wxEmptyString, const wxString &heading = wxEmptyString);
virtual ~WaitForTaskDialog() = default;
virtual int ShowModal();
public:
WaitForTaskDialog(const wxString& title = wxEmptyString, const wxString& heading = wxEmptyString);
virtual ~WaitForTaskDialog() = default;
virtual int ShowModal();
protected:
void OnTaskComplete(wxCommandEvent &evt);
//void OnTimer( wxTimerEvent& evt );
};
}
protected:
void OnTaskComplete(wxCommandEvent& evt);
//void OnTimer( wxTimerEvent& evt );
};
} // namespace Threading

View File

@ -21,10 +21,10 @@
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 bool AllowDeletions();
}
extern void YieldToMain();
extern bool AllowDeletions();
} // namespace Threading

View File

@ -29,20 +29,20 @@
//
struct TraceLogDescriptor
{
// short name, alphanumerics only: used for saving/loading options.
const wxChar *ShortName;
// short name, alphanumerics only: used for saving/loading options.
const wxChar* ShortName;
// Standard UI name for this log source. Used in menus, options dialogs.
const wxChar *Name;
// Standard UI name for this log source. Used in menus, options dialogs.
const wxChar* Name;
// Length description for use as a tooltip or menu item description.
const wxChar *Description;
// Length description for use as a tooltip or menu item description.
const wxChar* Description;
wxString GetShortName() const
{
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
return ShortName ? ShortName : Name;
}
wxString GetShortName() const
{
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
return ShortName ? ShortName : Name;
}
};
// --------------------------------------------------------------------------------------
@ -66,51 +66,51 @@ struct TraceLogDescriptor
class BaseTraceLogSource
{
protected:
const TraceLogDescriptor *m_Descriptor;
const TraceLogDescriptor* m_Descriptor;
public:
// 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
// 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
// should be processed or not.
bool Enabled;
// 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
// 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
// should be processed or not.
bool Enabled;
protected:
BaseTraceLogSource()
: m_Descriptor(NULL)
, Enabled(false)
{
}
BaseTraceLogSource()
: m_Descriptor(NULL)
, Enabled(false)
{
}
public:
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
BaseTraceLogSource(const TraceLogDescriptor *desc)
{
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
Enabled = false;
m_Descriptor = desc;
}
BaseTraceLogSource(const TraceLogDescriptor* desc)
{
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
Enabled = false;
m_Descriptor = desc;
}
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
// (use periods in favor of colons, since they do not require escape characters when
// written to ini/config files).
virtual wxString GetCategory() const { return wxEmptyString; }
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
// (use periods in favor of colons, since they do not require escape characters when
// written to ini/config files).
virtual wxString GetCategory() const { return wxEmptyString; }
// 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
// be used.
virtual bool IsActive() const { return Enabled; }
// 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
// be used.
virtual bool IsActive() const { return Enabled; }
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
virtual const wxChar *GetName() const { return m_Descriptor->Name; }
virtual const wxChar *GetDescription() const
{
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
}
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
virtual const wxChar* GetName() const { return m_Descriptor->Name; }
virtual const wxChar* GetDescription() const
{
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
{
public:
TextFileTraceLog(const TraceLogDescriptor *desc)
: BaseTraceLogSource(desc)
{
}
TextFileTraceLog(const TraceLogDescriptor* desc)
: BaseTraceLogSource(desc)
{
}
bool Write(const char *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
bool Write(const char* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return false;
}
return false;
}
bool WriteV(const char *fmt, va_list list) const
{
FastFormatAscii ascii;
ApplyPrefix(ascii);
ascii.WriteV(fmt, list);
DoWrite(ascii);
return false;
}
bool WriteV(const char* fmt, va_list list) const
{
FastFormatAscii ascii;
ApplyPrefix(ascii);
ascii.WriteV(fmt, list);
DoWrite(ascii);
return false;
}
virtual void ApplyPrefix(FastFormatAscii &ascii) const {}
virtual void DoWrite(const char *fmt) const = 0;
virtual void ApplyPrefix(FastFormatAscii& ascii) const {}
virtual void DoWrite(const char* fmt) const = 0;
};
// --------------------------------------------------------------------------------------
@ -159,130 +159,130 @@ public:
class ConsoleLogSource : public BaseTraceLogSource
{
public:
ConsoleColors DefaultColor;
ConsoleColors DefaultColor;
protected:
ConsoleLogSource()
: DefaultColor(Color_Gray)
{
}
ConsoleLogSource()
: DefaultColor(Color_Gray)
{
}
public:
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
ConsoleLogSource(const TraceLogDescriptor *desc, ConsoleColors defaultColor = Color_Gray)
: BaseTraceLogSource(desc)
{
DefaultColor = defaultColor;
}
ConsoleLogSource(const TraceLogDescriptor* desc, ConsoleColors defaultColor = Color_Gray)
: BaseTraceLogSource(desc)
{
DefaultColor = defaultColor;
}
// 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
// console's default color is Color_Default.
bool Write(const char *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
// 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
// console's default color is Color_Default.
bool Write(const char* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return false;
}
return false;
}
bool Write(const wxChar *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
bool Write(const wxChar* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt, list);
va_end(list);
return false;
}
return false;
}
bool Write(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt.wx_str(), list);
va_end(list);
bool Write(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(fmt.wx_str(), list);
va_end(list);
return false;
}
return false;
}
// Writes to the console using the specified color. This overrides the default color setting
// for this log.
bool Write(ConsoleColors color, const char *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(color, fmt, list);
va_end(list);
// Writes to the console using the specified color. This overrides the default color setting
// for this log.
bool Write(ConsoleColors color, const char* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(color, fmt, list);
va_end(list);
return false;
}
return false;
}
bool Write(ConsoleColors color, const wxChar *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(color, fmt, list);
va_end(list);
bool Write(ConsoleColors color, const wxChar* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(color, fmt, list);
va_end(list);
return false;
}
return false;
}
// Writes to the console using bold yellow text -- overrides the log source's default
// color settings.
bool Warn(const wxChar *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongYellow, fmt, list);
va_end(list);
// Writes to the console using bold yellow text -- overrides the log source's default
// color settings.
bool Warn(const wxChar* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongYellow, fmt, list);
va_end(list);
return false;
}
return false;
}
bool Warn(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongYellow, fmt.wx_str(), list);
va_end(list);
bool Warn(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongYellow, fmt.wx_str(), list);
va_end(list);
return false;
}
return false;
}
// Writes to the console using bold red text -- overrides the log source's default
// color settings.
bool Error(const wxChar *fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongRed, fmt, list);
va_end(list);
// Writes to the console using bold red text -- overrides the log source's default
// color settings.
bool Error(const wxChar* fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongRed, fmt, list);
va_end(list);
return false;
}
return false;
}
bool Error(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongRed, fmt.wx_str(), list);
va_end(list);
bool Error(const wxString fmt, ...) const
{
va_list list;
va_start(list, fmt);
WriteV(Color_StrongRed, fmt.wx_str(), list);
va_end(list);
return false;
}
return false;
}
bool WriteV(const char *fmt, va_list list) const;
bool WriteV(const wxChar *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(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 char* fmt, va_list list) const;
bool WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const;
virtual void DoWrite(const wxChar *msg) const
{
Console.DoWriteLn(msg);
}
virtual void DoWrite(const wxChar* msg) const
{
Console.DoWriteLn(msg);
}
};

View File

@ -22,18 +22,19 @@
template class EventSource<IEventListener_PageFault>;
SrcType_PageFault *Source_PageFault = NULL;
SrcType_PageFault* Source_PageFault = NULL;
Threading::Mutex PageFault_Mutex;
void pxInstallSignalHandler()
{
if (!Source_PageFault) {
Source_PageFault = new SrcType_PageFault();
}
if (!Source_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()
{
pxAssert(Source_PageFault);
Source_PageFault->Add(*this);
pxAssert(Source_PageFault);
Source_PageFault->Add(*this);
}
EventListener_PageFault::~EventListener_PageFault()
{
if (Source_PageFault)
Source_PageFault->Remove(*this);
if (Source_PageFault)
Source_PageFault->Remove(*this);
}
void SrcType_PageFault::Dispatch(const PageFaultInfo &params)
void SrcType_PageFault::Dispatch(const PageFaultInfo& params)
{
m_handled = false;
_parent::Dispatch(params);
m_handled = false;
_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 {
(*iter)->DispatchEvent(evt, m_handled);
} while ((++iter != iend) && !m_handled);
do
{
(*iter)->DispatchEvent(evt, m_handled);
} while ((++iter != iend) && !m_handled);
}
static size_t pageAlign(size_t size)
{
return (size + __pagesize - 1) / __pagesize * __pagesize;
return (size + __pagesize - 1) / __pagesize * __pagesize;
}
// --------------------------------------------------------------------------------------
// VirtualMemoryManager (implementations)
// --------------------------------------------------------------------------------------
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)
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)
{
if (!size) return;
if (!size)
return;
uptr reserved_bytes = pageAlign(size);
m_pages_reserved = reserved_bytes / __pagesize;
uptr reserved_bytes = pageAlign(size);
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))) {
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
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));
SafeSysMunmap(m_baseptr, reserved_bytes);
SafeSysMunmap(m_baseptr, reserved_bytes);
if (base) {
// Let's try again at an OS-picked memory area, and then hope it meets needed
// boundschecking criteria below.
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
}
}
if (base)
{
// Let's try again at an OS-picked memory area, and then hope it meets needed
// boundschecking criteria below.
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
}
}
bool fulfillsRequirements = true;
if (strict && m_baseptr != base)
fulfillsRequirements = false;
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
fulfillsRequirements = false;
if (!fulfillsRequirements) {
SafeSysMunmap(m_baseptr, reserved_bytes);
}
bool fulfillsRequirements = true;
if (strict && m_baseptr != base)
fulfillsRequirements = false;
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
fulfillsRequirements = false;
if (!fulfillsRequirements)
{
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;
uint mbytes = reserved_bytes / _1mb;
if (mbytes)
mbkb.Write("[%umb]", mbytes);
else
mbkb.Write("[%ukb]", reserved_bytes / 1024);
FastFormatUnicode mbkb;
uint mbytes = reserved_bytes / _1mb;
if (mbytes)
mbkb.Write("[%umb]", mbytes);
else
mbkb.Write("[%ukb]", reserved_bytes / 1024);
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());
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());
}
VirtualMemoryManager::~VirtualMemoryManager()
{
if (m_pageuse) delete[] m_pageuse;
if (m_baseptr) HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
if (m_pageuse)
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) {
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
static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
{
size = pageAlign(size);
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
return nullptr;
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
return nullptr;
if (m_baseptr == 0)
return nullptr;
auto puStart = &m_pageuse[offsetLocation / __pagesize];
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize];
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
return nullptr;
return (void *)(m_baseptr + offsetLocation);
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::Free(void *address, size_t size) const
void* VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
{
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");
}
}
size = pageAlign(size);
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
return nullptr;
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
return nullptr;
if (m_baseptr == 0)
return nullptr;
auto puStart = &m_pageuse[offsetLocation / __pagesize];
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
return nullptr;
return (void*)(m_baseptr + offsetLocation);
}
void VirtualMemoryManager::Free(void* address, size_t size) const
{
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::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)
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
if (m_baseptr.load() == 0)
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)
return nullptr;
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
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"))
return nullptr;
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
return nullptr;
return (void *)out;
return (void*)out;
}
// --------------------------------------------------------------------------------------
// VirtualMemoryReserve (implementations)
// --------------------------------------------------------------------------------------
VirtualMemoryReserve::VirtualMemoryReserve(const wxString &name, size_t size)
: m_name(name)
VirtualMemoryReserve::VirtualMemoryReserve(const wxString& name, size_t size)
: m_name(name)
{
m_defsize = size;
m_defsize = size;
m_allocator = nullptr;
m_pages_commited = 0;
m_pages_reserved = 0;
m_baseptr = nullptr;
m_prot_mode = PageAccess_None();
m_allow_writes = true;
m_allocator = nullptr;
m_pages_commited = 0;
m_pages_reserved = 0;
m_baseptr = nullptr;
m_prot_mode = PageAccess_None();
m_allow_writes = true;
}
VirtualMemoryReserve &VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode &mode)
VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode& mode)
{
m_prot_mode = mode;
return *this;
m_prot_mode = mode;
return *this;
}
size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
{
if (!requestedSize)
return pageAlign(m_defsize);
return pageAlign(requestedSize);
if (!requestedSize)
return pageAlign(m_defsize);
return pageAlign(requestedSize);
}
// Notes:
@ -245,84 +267,85 @@ size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
// baseptr - the new base pointer that's about to be assigned
// 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."))
return m_baseptr;
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
return m_baseptr;
if (!size)
return nullptr;
if (!size)
return nullptr;
m_allocator = std::move(allocator);
m_allocator = std::move(allocator);
m_baseptr = baseptr;
m_baseptr = baseptr;
uptr reserved_bytes = pageAlign(size);
m_pages_reserved = reserved_bytes / __pagesize;
uptr reserved_bytes = pageAlign(size);
m_pages_reserved = reserved_bytes / __pagesize;
if (!m_baseptr)
return nullptr;
if (!m_baseptr)
return nullptr;
FastFormatUnicode mbkb;
uint mbytes = reserved_bytes / _1mb;
if (mbytes)
mbkb.Write("[%umb]", mbytes);
else
mbkb.Write("[%ukb]", reserved_bytes / 1024);
FastFormatUnicode mbkb;
uint mbytes = reserved_bytes / _1mb;
if (mbytes)
mbkb.Write("[%umb]", mbytes);
else
mbkb.Write("[%ukb]", reserved_bytes / 1024);
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());
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());
return m_baseptr;
return m_baseptr;
}
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode &newmode)
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode& newmode)
{
if (!m_pages_commited)
return;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
if (!m_pages_commited)
return;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
}
// Clears all committed blocks, restoring the allocation to a reserve only.
void VirtualMemoryReserve::Reset()
{
if (!m_pages_commited)
return;
if (!m_pages_commited)
return;
ReprotectCommittedBlocks(PageAccess_None());
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
m_pages_commited = 0;
ReprotectCommittedBlocks(PageAccess_None());
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
m_pages_commited = 0;
}
void VirtualMemoryReserve::Release()
{
if (!m_baseptr) return;
Reset();
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
m_baseptr = nullptr;
if (!m_baseptr)
return;
Reset();
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
m_baseptr = nullptr;
}
bool VirtualMemoryReserve::Commit()
{
if (!m_pages_reserved)
return false;
if (!pxAssert(!m_pages_commited))
return true;
if (!m_pages_reserved)
return false;
if (!pxAssert(!m_pages_commited))
return true;
m_pages_commited = m_pages_reserved;
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
m_pages_commited = m_pages_reserved;
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
}
void VirtualMemoryReserve::AllowModification()
{
m_allow_writes = true;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
m_allow_writes = true;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
}
void VirtualMemoryReserve::ForbidModification()
{
m_allow_writes = false;
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
m_allow_writes = 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.
bool VirtualMemoryReserve::TryResize(uint newsize)
{
uint newPages = pageAlign(newsize) / __pagesize;
uint newPages = pageAlign(newsize) / __pagesize;
if (newPages > m_pages_reserved) {
uint toReservePages = newPages - m_pages_reserved;
uint toReserveBytes = toReservePages * __pagesize;
if (newPages > m_pages_reserved)
{
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)) {
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);
return false;
}
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);
return false;
}
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
} else if (newPages < m_pages_reserved) {
if (m_pages_commited > newsize)
return false;
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
}
else if (newPages < m_pages_reserved)
{
if (m_pages_commited > newsize)
return false;
uint toRemovePages = m_pages_reserved - newPages;
uint toRemoveBytes = toRemovePages * __pagesize;
uint toRemovePages = m_pages_reserved - newPages;
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),
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
}
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
}
m_pages_reserved = newPages;
return true;
m_pages_reserved = newPages;
return true;
}
// --------------------------------------------------------------------------------------
@ -377,27 +404,27 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
// --------------------------------------------------------------------------------------
wxString PageProtectionMode::ToString() const
{
wxString modeStr;
wxString modeStr;
if (m_read)
modeStr += L"Read";
if (m_write)
modeStr += L"Write";
if (m_exec)
modeStr += L"Exec";
if (m_read)
modeStr += L"Read";
if (m_write)
modeStr += L"Write";
if (m_exec)
modeStr += L"Exec";
if (modeStr.IsEmpty())
return L"NoAccess";
if (modeStr.Length() <= 5)
modeStr += L"Only";
if (modeStr.IsEmpty())
return L"NoAccess";
if (modeStr.Length() <= 5)
modeStr += L"Only";
return modeStr;
return modeStr;
}
// --------------------------------------------------------------------------------------
// 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/PageFaultSource.h"
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
// Note: This exception can be accessed by the EE or MTVU thread
// 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...
Threading::ScopedLock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
// Note: This exception can be accessed by the EE or MTVU thread
// 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...
Threading::ScopedLock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
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.
// 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
// exception.
// 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.
__try {
return DoSysPageFaultExceptionFilter(eps);
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
return EXCEPTION_CONTINUE_SEARCH;
}
// 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
// because Source_PageFault was deallocated), this will allow the debugger to catch the
// exception.
// 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.
__try
{
return DoSysPageFaultExceptionFilter(eps);
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return EXCEPTION_CONTINUE_SEARCH;
}
}
void _platform_InstallSignalHandler()
{
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
#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
// 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
// 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
// microsoft days wasn't a very good coder, me thinks. --air
if (mode.CanExecute()) {
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
} else if (mode.CanRead()) {
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
}
if (mode.CanExecute())
{
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
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));
if (result)
return true;
void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
if (result)
return true;
const DWORD errcode = GetLastError();
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...
} else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) {
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
return false;
}
const DWORD errcode = GetLastError();
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...
}
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
{
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
return false;
}
if (!pxDoOutOfMemory)
return false;
pxDoOutOfMemory(size);
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
if (!pxDoOutOfMemory)
return false;
pxDoOutOfMemory(size);
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)
{
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)
{
if (!base)
return;
//VirtualFree((void*)base, size, MEM_DECOMMIT);
VirtualFree((void *)base, 0, MEM_RELEASE);
if (!base)
return;
//VirtualFree((void*)base, size, MEM_DECOMMIT);
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(
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)",
__pagesize, __pagesize, size, size));
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
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)",
__pagesize, __pagesize, size, size));
DWORD OldProtect; // enjoy my uselessness, yo!
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect)) {
Exception::WinApiError apiError;
DWORD OldProtect; // enjoy my uselessness, yo!
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect))
{
Exception::WinApiError apiError;
apiError.SetDiagMsg(
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
apiError.SetDiagMsg(
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
pxFailDev(apiError.FormatDiagnosticMessage());
}
pxFailDev(apiError.FormatDiagnosticMessage());
}
}
#endif

View File

@ -21,115 +21,118 @@
__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
// improve performance and reduce cpu power consumption.
__fi void Threading::SpinWait()
{
_mm_pause();
_mm_pause();
}
__fi void Threading::EnableHiresScheduler()
{
// 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
// particular may have a scheduler Period of 15 or 20ms to extend battery life.
// 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
// 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()
{
timeEndPeriod(1);
timeEndPeriod(1);
}
// 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).
union FileTimeSucks
{
FILETIME filetime;
u64 u64time;
FILETIME filetime;
u64 u64time;
};
u64 Threading::GetThreadCpuTime()
{
FileTimeSucks user, kernel;
FILETIME dummy;
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time;
FileTimeSucks user, kernel;
FILETIME dummy;
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time;
}
u64 Threading::GetThreadTicksPerSecond()
{
return 10000000;
return 10000000;
}
u64 Threading::pxThread::GetCpuTime() const
{
if (!m_native_handle)
return 0;
if (!m_native_handle)
return 0;
FileTimeSucks user, kernel;
FILETIME dummy;
FileTimeSucks user, kernel;
FILETIME dummy;
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
return user.u64time + kernel.u64time;
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
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()
{
// 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...
// 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...
m_native_id = (uptr)GetCurrentThreadId();
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
m_native_id = (uptr)GetCurrentThreadId();
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()
{
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)
// This code sample was borrowed form some obscure MSDN article.
// In a rare bout of sanity, it's an actual Microsoft-published hack
// that actually works!
// This code sample was borrowed form some obscure MSDN article.
// In a rare bout of sanity, it's an actual Microsoft-published hack
// that actually works!
static const int MS_VC_EXCEPTION = 0x406D1388;
static const int MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8)
struct THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
};
struct THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
};
#pragma pack(pop)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
}

View File

@ -21,10 +21,10 @@
// FreeBSD/OsX need something far more complicated (apparently)
void x86capabilities::CountLogicalCores()
{
// 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
// alternatives, apparently.
LogicalCores = wxThread::GetCPUCount();
// 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
// alternatives, apparently.
LogicalCores = wxThread::GetCPUCount();
}
// Not implemented yet for linux (see cpudetect_internal.h for details)

View File

@ -20,65 +20,66 @@
void x86capabilities::CountLogicalCores()
{
DWORD_PTR vProcessCPUs;
DWORD_PTR vSystemCPUs;
DWORD_PTR vProcessCPUs;
DWORD_PTR vSystemCPUs;
LogicalCores = 1;
LogicalCores = 1;
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
return;
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
return;
uint CPUs = 0;
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
if (vSystemCPUs & bit)
CPUs++;
uint CPUs = 0;
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
if (vSystemCPUs & bit)
CPUs++;
LogicalCores = CPUs;
LogicalCores = CPUs;
}
SingleCoreAffinity::SingleCoreAffinity()
{
s_threadId = nullptr;
s_oldmask = ERROR_INVALID_PARAMETER;
s_threadId = nullptr;
s_oldmask = ERROR_INVALID_PARAMETER;
DWORD_PTR availProcCpus;
DWORD_PTR availSysCpus;
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
return;
DWORD_PTR availProcCpus;
DWORD_PTR availSysCpus;
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
return;
int cpu = 0;
DWORD_PTR affinityMask;
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
if (availProcCpus & affinityMask)
break;
int cpu = 0;
DWORD_PTR affinityMask;
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
if (availProcCpus & affinityMask)
break;
s_threadId = GetCurrentThread();
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
s_threadId = GetCurrentThread();
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
if (s_oldmask == ERROR_INVALID_PARAMETER) {
const int hexWidth = 2 * sizeof(DWORD_PTR);
Console.Warning(
"CpuDetect: SetThreadAffinityMask failed...\n"
"\tSystem Affinity : 0x%0*x\n"
"\tProcess Affinity: 0x%0*x\n"
"\tAttempted Thread Affinity CPU: %i",
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
}
if (s_oldmask == ERROR_INVALID_PARAMETER)
{
const int hexWidth = 2 * sizeof(DWORD_PTR);
Console.Warning(
"CpuDetect: SetThreadAffinityMask failed...\n"
"\tSystem Affinity : 0x%0*x\n"
"\tProcess Affinity: 0x%0*x\n"
"\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
// 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
// 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
// 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.
// 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
// scheduled on a difference cpu/core. However, Windows does not necessarily perform
// 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
// 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.
};
SingleCoreAffinity::~SingleCoreAffinity()
{
if (s_oldmask != ERROR_INVALID_PARAMETER)
SetThreadAffinityMask(s_threadId, s_oldmask);
if (s_oldmask != ERROR_INVALID_PARAMETER)
SetThreadAffinityMask(s_threadId, s_oldmask);
}
#endif

View File

@ -19,17 +19,17 @@
namespace x86Emitter
{
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const
{
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
}
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const
{
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
}
}
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const
{
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
}
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const
{
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)
{
__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)
{
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
}
#endif
@ -46,23 +46,23 @@ using namespace x86Emitter;
__aligned16 x86capabilities x86caps;
x86capabilities::x86capabilities()
: isIdentified(false)
, VendorID(x86Vendor_Unknown)
, FamilyID(0)
, Model(0)
, TypeID(0)
, StepID(0)
, Flags(0)
, Flags2(0)
, EFlags(0)
, EFlags2(0)
, SEFlag(0)
, AllCapabilities(0)
, PhysicalCores(0)
, LogicalCores(0)
: isIdentified(false)
, VendorID(x86Vendor_Unknown)
, FamilyID(0)
, Model(0)
, TypeID(0)
, StepID(0)
, Flags(0)
, Flags2(0)
, EFlags(0)
, EFlags2(0)
, SEFlag(0)
, AllCapabilities(0)
, PhysicalCores(0)
, LogicalCores(0)
{
memzero(VendorName);
memzero(FamilyName);
memzero(VendorName);
memzero(FamilyName);
}
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
@ -72,28 +72,29 @@ x86capabilities::x86capabilities()
// Note: recSSE was deleted
void x86capabilities::SIMD_EstablishMXCSRmask()
{
if (!hasStreamingSIMDExtensions)
return;
if (!hasStreamingSIMDExtensions)
return;
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
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
// and override this.
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
// 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
_fxsave(&targetFXSAVE);
// Work for recent enough GCC/CLANG/MSVC 2012
_fxsave(&targetFXSAVE);
u32 result;
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
if (result != 0)
MXCSR_Mask.bitmask = result;
u32 result;
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
if (result != 0)
MXCSR_Mask.bitmask = result;
}
// 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.
s64 x86capabilities::_CPUSpeedHz(u64 time) const
{
u64 timeStart, timeStop;
s64 startCycle, endCycle;
u64 timeStart, timeStop;
s64 startCycle, endCycle;
if (!hasTimeStampCounter)
return 0;
if (!hasTimeStampCounter)
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 {
timeStart = GetCPUTicks();
startCycle = __rdtsc();
} while (GetCPUTicks() == timeStart);
do
{
timeStart = GetCPUTicks();
startCycle = __rdtsc();
} while (GetCPUTicks() == timeStart);
do {
timeStop = GetCPUTicks();
endCycle = __rdtsc();
} while ((timeStop - timeStart) < time);
do
{
timeStop = GetCPUTicks();
endCycle = __rdtsc();
} while ((timeStop - timeStart) < time);
s64 cycleCount = endCycle - startCycle;
s64 timeCount = timeStop - timeStart;
s64 overrun = timeCount - time;
if (!overrun)
return cycleCount;
s64 cycleCount = endCycle - startCycle;
s64 timeCount = timeStop - timeStart;
s64 overrun = timeCount - time;
if (!overrun)
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 newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
double cyclesPerTick = (double)cycleCount / (double)timeCount;
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
return (s64)newCycleCount;
return (s64)newCycleCount;
}
wxString x86capabilities::GetTypeName() const
{
switch (TypeID) {
case 0:
return L"Standard OEM";
case 1:
return L"Overdrive";
case 2:
return L"Dual";
case 3:
return L"Reserved";
default:
return L"Unknown";
}
switch (TypeID)
{
case 0:
return L"Standard OEM";
case 1:
return L"Overdrive";
case 2:
return L"Dual";
case 3:
return L"Reserved";
default:
return L"Unknown";
}
}
void x86capabilities::CountCores()
{
Identify();
Identify();
s32 regs[4];
u32 cmds;
s32 regs[4];
u32 cmds;
cpuid(regs, 0x80000000);
cmds = regs[0];
cpuid(regs, 0x80000000);
cmds = regs[0];
// detect multicore for AMD cpu
// detect multicore for AMD cpu
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.
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
// not seem to do this) --air
hasMultiThreading = 0;
}
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.
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
// not seem to do this) --air
hasMultiThreading = 0;
}
// This will assign values into LogicalCores and PhysicalCores
CountLogicalCores();
// This will assign values into LogicalCores and PhysicalCores
CountLogicalCores();
}
static const char *tbl_x86vendors[] =
{
"GenuineIntel",
"AuthenticAMD",
"Unknown ",
static const char* tbl_x86vendors[] =
{
"GenuineIntel",
"AuthenticAMD",
"Unknown ",
};
// 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.
void x86capabilities::Identify()
{
if (isIdentified)
return;
isIdentified = true;
if (isIdentified)
return;
isIdentified = true;
s32 regs[4];
u32 cmds;
s32 regs[4];
u32 cmds;
memzero(VendorName);
cpuid(regs, 0);
memzero(VendorName);
cpuid(regs, 0);
cmds = regs[0];
memcpy(&VendorName[0], &regs[1], 4);
memcpy(&VendorName[4], &regs[3], 4);
memcpy(&VendorName[8], &regs[2], 4);
cmds = regs[0];
memcpy(&VendorName[0], &regs[1], 4);
memcpy(&VendorName[4], &regs[3], 4);
memcpy(&VendorName[8], &regs[2], 4);
// Determine Vendor Specifics!
// 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
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
// Determine Vendor Specifics!
// 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
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
int vid;
for (vid = 0; vid < x86Vendor_Unknown; ++vid) {
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
break;
}
VendorID = static_cast<x86VendorType>(vid);
int vid;
for (vid = 0; vid < x86Vendor_Unknown; ++vid)
{
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
break;
}
VendorID = static_cast<x86VendorType>(vid);
if (cmds >= 0x00000001) {
cpuid(regs, 0x00000001);
if (cmds >= 0x00000001)
{
cpuid(regs, 0x00000001);
StepID = regs[0] & 0xf;
Model = (regs[0] >> 4) & 0xf;
FamilyID = (regs[0] >> 8) & 0xf;
TypeID = (regs[0] >> 12) & 0x3;
StepID = regs[0] & 0xf;
Model = (regs[0] >> 4) & 0xf;
FamilyID = (regs[0] >> 8) & 0xf;
TypeID = (regs[0] >> 12) & 0x3;
#ifdef __M_X86_64
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
#endif
Flags = regs[3];
Flags2 = regs[2];
}
Flags = regs[3];
Flags2 = regs[2];
}
if (cmds >= 0x00000007) {
// Note: ECX must be 0 for AVX2 detection.
cpuidex(regs, 0x00000007, 0);
if (cmds >= 0x00000007)
{
// Note: ECX must be 0 for AVX2 detection.
cpuidex(regs, 0x00000007, 0);
SEFlag = regs[1];
}
SEFlag = regs[1];
}
cpuid(regs, 0x80000000);
cmds = regs[0];
if (cmds >= 0x80000001) {
cpuid(regs, 0x80000001);
cpuid(regs, 0x80000000);
cmds = regs[0];
if (cmds >= 0x80000001)
{
cpuid(regs, 0x80000001);
#ifdef __M_X86_64
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
#endif
EFlags2 = regs[2];
EFlags = regs[3];
}
EFlags2 = regs[2];
EFlags = regs[3];
}
memzero(FamilyName);
cpuid((int *)FamilyName, 0x80000002);
cpuid((int *)(FamilyName + 16), 0x80000003);
cpuid((int *)(FamilyName + 32), 0x80000004);
memzero(FamilyName);
cpuid((int*)FamilyName, 0x80000002);
cpuid((int*)(FamilyName + 16), 0x80000003);
cpuid((int*)(FamilyName + 32), 0x80000004);
hasFloatingPointUnit = (Flags >> 0) & 1;
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
hasDebuggingExtensions = (Flags >> 2) & 1;
hasPageSizeExtensions = (Flags >> 3) & 1;
hasTimeStampCounter = (Flags >> 4) & 1;
hasModelSpecificRegisters = (Flags >> 5) & 1;
hasPhysicalAddressExtension = (Flags >> 6) & 1;
hasMachineCheckArchitecture = (Flags >> 7) & 1;
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
hasSEPFastSystemCall = (Flags >> 11) & 1;
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
hasPTEGlobalFlag = (Flags >> 13) & 1;
hasMachineCheckArchitecture = (Flags >> 14) & 1;
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
hasFGPageAttributeTable = (Flags >> 16) & 1;
has36bitPageSizeExtension = (Flags >> 17) & 1;
hasProcessorSerialNumber = (Flags >> 18) & 1;
hasCFLUSHInstruction = (Flags >> 19) & 1;
hasDebugStore = (Flags >> 21) & 1;
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
hasSelfSnoop = (Flags >> 27) & 1;
hasMultiThreading = (Flags >> 28) & 1;
hasThermalMonitor = (Flags >> 29) & 1;
hasIntel64BitArchitecture = (Flags >> 30) & 1;
hasFloatingPointUnit = (Flags >> 0) & 1;
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
hasDebuggingExtensions = (Flags >> 2) & 1;
hasPageSizeExtensions = (Flags >> 3) & 1;
hasTimeStampCounter = (Flags >> 4) & 1;
hasModelSpecificRegisters = (Flags >> 5) & 1;
hasPhysicalAddressExtension = (Flags >> 6) & 1;
hasMachineCheckArchitecture = (Flags >> 7) & 1;
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
hasSEPFastSystemCall = (Flags >> 11) & 1;
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
hasPTEGlobalFlag = (Flags >> 13) & 1;
hasMachineCheckArchitecture = (Flags >> 14) & 1;
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
hasFGPageAttributeTable = (Flags >> 16) & 1;
has36bitPageSizeExtension = (Flags >> 17) & 1;
hasProcessorSerialNumber = (Flags >> 18) & 1;
hasCFLUSHInstruction = (Flags >> 19) & 1;
hasDebugStore = (Flags >> 21) & 1;
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
hasSelfSnoop = (Flags >> 27) & 1;
hasMultiThreading = (Flags >> 28) & 1;
hasThermalMonitor = (Flags >> 29) & 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
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
if ((Flags2 >> 27) & 1) // OSXSAVE
{
// Note: In theory, we should use xgetbv to check OS support
// but all OSes we officially run under support it
// and its intrinsic requires extra compiler flags
hasAVX = (Flags2 >> 28) & 1; //avx
hasFMA = (Flags2 >> 12) & 1; //fma
hasAVX2 = (SEFlag >> 5) & 1; //avx2
}
if ((Flags2 >> 27) & 1) // OSXSAVE
{
// Note: In theory, we should use xgetbv to check OS support
// but all OSes we officially run under support it
// and its intrinsic requires extra compiler flags
hasAVX = (Flags2 >> 28) & 1; //avx
hasFMA = (Flags2 >> 12) & 1; //fma
hasAVX2 = (SEFlag >> 5) & 1; //avx2
}
hasBMI1 = (SEFlag >> 3) & 1;
hasBMI2 = (SEFlag >> 8) & 1;
hasBMI1 = (SEFlag >> 3) & 1;
hasBMI2 = (SEFlag >> 8) & 1;
// Ones only for AMDs:
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
// Ones only for AMDs:
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
isIdentified = true;
isIdentified = true;
}
u32 x86capabilities::CalculateMHz() const
{
InitCPUTicks();
u64 span = GetTickFrequency();
InitCPUTicks();
u64 span = GetTickFrequency();
if ((span % 1000) < 400) // helps minimize rounding errors
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
else
return (u32)(_CPUSpeedHz(span / 500) / 2000);
if ((span % 1000) < 400) // helps minimize rounding errors
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
else
return (u32)(_CPUSpeedHz(span / 500) / 2000);
}

View File

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

View File

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

View File

@ -34,222 +34,237 @@
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
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
// with one of the other overloads).
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess &sibdest, int imm)
{
if (sibdest.Is8BitOp()) {
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
// 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
// with one of the other overloads).
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
{
if (sibdest.Is8BitOp())
{
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
xWrite<s8>(imm);
} else {
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
xWrite<s8>(imm);
}
else
{
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
if (is_s8(imm))
xWrite<s8>(imm);
else
sibdest.xWriteImm(imm);
}
}
if (is_s8(imm))
xWrite<s8>(imm);
else
sibdest.xWriteImm(imm);
}
}
void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from)
{
pxAssert(to.GetOperandSize() == from.GetOperandSize());
void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from)
{
pxAssert(to.GetOperandSize() == from.GetOperandSize());
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, from, to);
}
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, from, to);
}
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid &sibdest, const xRegisterInt &from)
{
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
}
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid& sibdest, const xRegisterInt& from)
{
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
}
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xIndirectVoid &sibsrc)
{
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
}
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xIndirectVoid& sibsrc)
{
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
}
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, int imm)
{
if (!to.Is8BitOp() && is_s8(imm)) {
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
xWrite<s8>(imm);
} else {
if (to.IsAccumulator()) {
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
} else {
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
}
to.xWriteImm(imm);
}
}
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
{
if (!to.Is8BitOp() && is_s8(imm))
{
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
xWrite<s8>(imm);
}
else
{
if (to.IsAccumulator())
{
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
}
else
{
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
}
to.xWriteImm(imm);
}
}
#define ImplementGroup1(g1type, insttype) \
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 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 xIndirect64orLess &sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
#define ImplementGroup1(g1type, insttype) \
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 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 xIndirect64orLess& sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
ImplementGroup1(xImpl_Group1, InstType)
ImplementGroup1(xImpl_G1Logic, InstType)
ImplementGroup1(xImpl_G1Arith, InstType)
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
ImplementGroup1(xImpl_Group1, InstType)
ImplementGroup1(xImpl_G1Logic, InstType)
ImplementGroup1(xImpl_G1Arith, InstType)
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
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 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_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_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
const xImpl_Group1 xADC = {G1Type_ADC};
const xImpl_Group1 xSBB = {G1Type_SBB};
const xImpl_Group1 xADC = {G1Type_ADC};
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
{
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
}
void xImpl_Group2::operator()(const xRegisterInt& to, const xRegisterCL& /* from */) const
{
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
}
void xImpl_Group2::operator()(const xRegisterInt &to, u8 imm) const
{
if (imm == 0)
return;
void xImpl_Group2::operator()(const xRegisterInt& to, u8 imm) const
{
if (imm == 0)
return;
if (imm == 1) {
// special encoding of 1's
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
} else {
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
xWrite8(imm);
}
}
if (imm == 1)
{
// special encoding of 1's
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
}
else
{
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
xWrite8(imm);
}
}
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, const xRegisterCL & /* from */) const
{
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
}
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, const xRegisterCL& /* from */) const
{
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
}
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, u8 imm) const
{
if (imm == 0)
return;
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, u8 imm) const
{
if (imm == 0)
return;
if (imm == 1) {
// special encoding of 1's
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
} else {
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
xWrite8(imm);
}
}
if (imm == 1)
{
// special encoding of 1's
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
}
else
{
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
xWrite8(imm);
}
}
const xImpl_Group2 xROL = {G2Type_ROL};
const xImpl_Group2 xROR = {G2Type_ROR};
const xImpl_Group2 xRCL = {G2Type_RCL};
const xImpl_Group2 xRCR = {G2Type_RCR};
const xImpl_Group2 xSHL = {G2Type_SHL};
const xImpl_Group2 xSHR = {G2Type_SHR};
const xImpl_Group2 xSAR = {G2Type_SAR};
const xImpl_Group2 xROL = {G2Type_ROL};
const xImpl_Group2 xROR = {G2Type_ROR};
const xImpl_Group2 xRCL = {G2Type_RCL};
const xImpl_Group2 xRCR = {G2Type_RCR};
const xImpl_Group2 xSHL = {G2Type_SHL};
const xImpl_Group2 xSHR = {G2Type_SHR};
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)
{
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
}
static void _g3_EmitOp(G3Type InstType, const xRegisterInt& from)
{
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
}
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess &from)
{
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
}
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess& 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 xIndirect64orLess &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_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 xRegisterInt& from) const { _g3_EmitOp(G3Type_iDIV, from); }
void xImpl_iDiv::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iDIV, from); }
template <typename SrcType>
static void _imul_ImmStyle(const xRegisterInt &param1, const SrcType &param2, int imm)
{
pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
template <typename SrcType>
static void _imul_ImmStyle(const xRegisterInt& param1, const SrcType& param2, int imm)
{
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))
xWrite8((u8)imm);
else
param1.xWriteImm(imm);
}
if (is_s8(imm))
xWrite8((u8)imm);
else
param1.xWriteImm(imm);
}
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 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 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 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 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 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 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 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 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 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); }
const xImpl_Group3 xNOT = {G3Type_NOT};
const xImpl_Group3 xNEG = {G3Type_NEG};
const xImpl_Group3 xUMUL = {G3Type_MUL};
const xImpl_Group3 xUDIV = {G3Type_DIV};
const xImpl_Group3 xNOT = {G3Type_NOT};
const xImpl_Group3 xNEG = {G3Type_NEG};
const xImpl_Group3 xUMUL = {G3Type_MUL};
const xImpl_Group3 xUDIV = {G3Type_DIV};
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_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
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
{
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
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 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 xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const
{
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
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 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 xRegister16or32or64 &bitbase, u8 bitoffset) const
{
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
}
void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const
{
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
}
void xImpl_Group8::operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const
{
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
}
void xImpl_Group8::operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const
{
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
}
const xImpl_Group8 xBT = {G8Type_BT};
const xImpl_Group8 xBTR = {G8Type_BTR};
const xImpl_Group8 xBTS = {G8Type_BTS};
const xImpl_Group8 xBTC = {G8Type_BTC};
const xImpl_Group8 xBT = {G8Type_BT};
const xImpl_Group8 xBTR = {G8Type_BTR};
const xImpl_Group8 xBTS = {G8Type_BTS};
const xImpl_Group8 xBTC = {G8Type_BTC};

View File

@ -20,19 +20,19 @@
namespace x86Emitter
{
struct xImplBMI_RVM
{
u8 Prefix;
u8 MbPrefix;
u8 Opcode;
struct xImplBMI_RVM
{
u8 Prefix;
u8 MbPrefix;
u8 Opcode;
// RVM
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
// PDEP Parallel bits deposit
// PEXT Parallel bits extract
// 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 xIndirectVoid &from2) const;
// RVM
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
// PDEP Parallel bits deposit
// PEXT Parallel bits extract
// 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 xIndirectVoid& from2) const;
#if 0
// 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 xIndirectVoid& from, u8 imm) const;
#endif
};
}
};
} // namespace x86Emitter

View File

@ -18,27 +18,27 @@
namespace x86Emitter
{
// Implementations here cover SHLD and SHRD.
// Implementations here cover SHLD and SHRD.
// --------------------------------------------------------------------------------------
// xImpl_DowrdShift
// --------------------------------------------------------------------------------------
// 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).
//
// 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).
//
struct xImpl_DwordShift
{
u16 OpcodeBase;
// --------------------------------------------------------------------------------------
// xImpl_DowrdShift
// --------------------------------------------------------------------------------------
// 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).
//
// 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).
//
struct xImpl_DwordShift
{
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, u8 shiftcnt) const;
};
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, u8 shiftcnt) const;
};
} // End namespace x86Emitter

View File

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

View File

@ -18,32 +18,33 @@
namespace x86Emitter
{
enum G2Type {
G2Type_ROL = 0,
G2Type_ROR,
G2Type_RCL,
G2Type_RCR,
G2Type_SHL,
G2Type_SHR,
G2Type_Unused,
G2Type_SAR
};
enum G2Type
{
G2Type_ROL = 0,
G2Type_ROR,
G2Type_RCL,
G2Type_RCR,
G2Type_SHL,
G2Type_SHR,
G2Type_Unused,
G2Type_SAR
};
// --------------------------------------------------------------------------------------
// xImpl_Group2
// --------------------------------------------------------------------------------------
// Group 2 (shift) instructions have no Sib/ModRM forms.
// 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.
//
struct xImpl_Group2
{
G2Type InstType;
// --------------------------------------------------------------------------------------
// xImpl_Group2
// --------------------------------------------------------------------------------------
// Group 2 (shift) instructions have no Sib/ModRM forms.
// 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.
//
struct xImpl_Group2
{
G2Type InstType;
void operator()(const xRegisterInt &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 xIndirect64orLess &to, u8 imm) const;
void operator()(const xRegisterInt& 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 xIndirect64orLess& to, u8 imm) const;
#if 0
// ------------------------------------------------------------------------
@ -57,6 +58,6 @@ struct xImpl_Group2
_DoI_helpermess( *this, to, from );
}
#endif
};
};
} // End namespace x86Emitter

View File

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

View File

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

View File

@ -20,74 +20,75 @@
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
{
bool isJmp;
// ------------------------------------------------------------------------
struct xImpl_JmpCall
{
bool isJmp;
void operator()(const xAddressReg &absreg) const;
void operator()(const xIndirectNative &src) const;
void operator()(const xAddressReg& absreg) const;
void operator()(const xIndirectNative& src) const;
// Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated.
void operator()(void *func) const
{
if (isJmp)
xJccKnownTarget(Jcc_Unconditional, (void *)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
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).
// Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated.
void operator()(void* func) const
{
if (isJmp)
xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
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).
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
xWrite8(0xe8);
xWrite32(dest);
}
}
};
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
xWrite8(0xe8);
xWrite32(dest);
}
}
};
// 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_JmpCall xCALL;
// 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_JmpCall xCALL;
struct xImpl_FastCall
{
// 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.
struct xImpl_FastCall
{
// 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.
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, const xIndirect32 &a1) const;
void operator()(void *f, u32 a1, u32 a2) const;
void operator()(void *f, void *a1) const;
void operator()(void* f, u32 a1, const xRegister32& a2) const;
void operator()(void* f, const xIndirect32& a1) const;
void operator()(void* f, u32 a1, u32 a2) const;
void operator()(void* f, void* a1) const;
#ifdef __M_X86_64
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, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
void operator()(void* f, u32 a1, const xRegisterLong& a2) const;
#endif
template <typename T>
__fi void operator()(T *func, u32 a1, const xRegisterLong &a2 = xEmptyReg) const
{
(*this)((void *)func, a1, a2);
}
template <typename T>
__fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
{
(*this)((void*)func, a1, a2);
}
template <typename T>
__fi void operator()(T *func, const xIndirect32 &a1) const
{
(*this)((void*)func, a1);
}
template <typename T>
__fi void operator()(T* func, const xIndirect32& a1) const
{
(*this)((void*)func, a1);
}
template <typename T>
__fi void operator()(T *func, u32 a1, u32 a2) const
{
(*this)((void*)func, a1, a2);
}
template <typename T>
__fi void operator()(T* func, u32 a1, u32 a2) const
{
(*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

View File

@ -21,20 +21,20 @@
namespace x86Emitter
{
// --------------------------------------------------------------------------------------
// MovImplAll
// --------------------------------------------------------------------------------------
// MOV instruction Implementation, plus many SIMD sub-mov variants.
//
struct xImpl_Mov
{
xImpl_Mov() {} // Satisfy GCC's whims.
// --------------------------------------------------------------------------------------
// MovImplAll
// --------------------------------------------------------------------------------------
// MOV instruction Implementation, plus many SIMD sub-mov variants.
//
struct xImpl_Mov
{
xImpl_Mov() {} // Satisfy GCC's whims.
void operator()(const xRegisterInt &to, 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 xIndirect64orLess &dest, sptr imm) const;
void operator()(const xRegisterInt &to, sptr imm, bool preserve_flags = false) const;
void operator()(const xRegisterInt& to, 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 xIndirect64orLess& dest, sptr imm) const;
void operator()(const xRegisterInt& to, sptr imm, bool preserve_flags = false) const;
#if 0
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 ) );
}*/
#endif
};
};
#ifdef __M_X86_64
// --------------------------------------------------------------------------------------
// xImpl_MovImm64
// --------------------------------------------------------------------------------------
// Mov with 64-bit immediates (only available on 64-bit platforms)
//
struct xImpl_MovImm64
{
xImpl_MovImm64() {} // Satisfy GCC's whims.
// --------------------------------------------------------------------------------------
// xImpl_MovImm64
// --------------------------------------------------------------------------------------
// Mov with 64-bit immediates (only available on 64-bit platforms)
//
struct xImpl_MovImm64
{
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
// --------------------------------------------------------------------------------------
// xImpl_CMov
// --------------------------------------------------------------------------------------
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
// SETcc !! [more glory, less lack!]
//
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
// realize that it cannot load immediate values into registers. -_-
//
// 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).
//
// --------------------------------------------------------------------------------------
// xImpl_CMov
// --------------------------------------------------------------------------------------
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
// SETcc !! [more glory, less lack!]
//
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
// realize that it cannot load immediate values into registers. -_-
//
// 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).
//
struct xImpl_CMov
{
JccComparisonType ccType;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
struct xImpl_CMov
{
JccComparisonType ccType;
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
};
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
};
struct xImpl_Set
{
JccComparisonType ccType;
struct xImpl_Set
{
JccComparisonType ccType;
void operator()(const xRegister8 &to) const;
void operator()(const xIndirect8 &dest) const;
void operator()(const xRegister8& to) const;
void operator()(const xIndirect8& dest) const;
//void operator()( const xDirectOrIndirect8& dest ) const;
};
//void operator()( const xDirectOrIndirect8& dest ) const;
};
// --------------------------------------------------------------------------------------
// xImpl_MovExtend
// --------------------------------------------------------------------------------------
// Mov with sign/zero extension implementations (movsx / movzx)
//
struct xImpl_MovExtend
{
bool SignExtend;
// --------------------------------------------------------------------------------------
// xImpl_MovExtend
// --------------------------------------------------------------------------------------
// Mov with sign/zero extension implementations (movsx / movzx)
//
struct xImpl_MovExtend
{
bool SignExtend;
void operator()(const xRegister16or32or64 &to, const xRegister8 &from) 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 xIndirect16 &sibsrc) const;
void operator()(const xRegister16or32or64& to, const xRegister8& from) 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 xIndirect16& sibsrc) const;
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
};
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
};
} // End namespace x86Emitter

View File

@ -18,299 +18,299 @@
namespace x86Emitter
{
// --------------------------------------------------------------------------------------
// _SimdShiftHelper
// --------------------------------------------------------------------------------------
struct _SimdShiftHelper
{
u8 Prefix;
u16 Opcode;
u16 OpcodeImm;
u8 Modcode;
// --------------------------------------------------------------------------------------
// _SimdShiftHelper
// --------------------------------------------------------------------------------------
struct _SimdShiftHelper
{
u8 Prefix;
u16 Opcode;
u16 OpcodeImm;
u8 Modcode;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &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, 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.
//
struct xImplSimd_ShiftWithoutQ
{
const _SimdShiftHelper W;
const _SimdShiftHelper D;
};
// Used for PSRA, which lacks the Q form.
//
struct xImplSimd_ShiftWithoutQ
{
const _SimdShiftHelper W;
const _SimdShiftHelper D;
};
// Implements PSRL and PSLL
//
struct xImplSimd_Shift
{
const _SimdShiftHelper W;
const _SimdShiftHelper D;
const _SimdShiftHelper Q;
// Implements PSRL and PSLL
//
struct xImplSimd_Shift
{
const _SimdShiftHelper W;
const _SimdShiftHelper D;
const _SimdShiftHelper Q;
void DQ(const xRegisterSSE &to, u8 imm8) const;
};
void DQ(const xRegisterSSE& to, u8 imm8) const;
};
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_AddSub
{
const xImplSimd_DestRegEither B;
const xImplSimd_DestRegEither W;
const xImplSimd_DestRegEither D;
const xImplSimd_DestRegEither Q;
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_AddSub
{
const xImplSimd_DestRegEither B;
const xImplSimd_DestRegEither W;
const xImplSimd_DestRegEither D;
const xImplSimd_DestRegEither Q;
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SB;
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SB;
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SW;
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither SW;
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USB;
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USB;
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USW;
};
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
const xImplSimd_DestRegEither USW;
};
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_PMul
{
const xImplSimd_DestRegEither LW;
const xImplSimd_DestRegEither HW;
const xImplSimd_DestRegEither HUW;
const xImplSimd_DestRegEither UDQ;
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_PMul
{
const xImplSimd_DestRegEither LW;
const xImplSimd_DestRegEither HW;
const xImplSimd_DestRegEither HUW;
const xImplSimd_DestRegEither UDQ;
// [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
// 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
// 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
// result and packed to the destination operand.
//
// Both operands can be MMX or XMM registers. Source can be register or memory.
//
const xImplSimd_DestRegEither HRSW;
// [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
// 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
// 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
// result and packed to the destination operand.
//
// Both operands can be MMX or XMM registers. Source can be register or memory.
//
const xImplSimd_DestRegEither HRSW;
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
// the low 32 bits of each product in xmm1.
const xImplSimd_DestRegSSE LD;
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
// the low 32 bits of each product in xmm1.
const xImplSimd_DestRegSSE LD;
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
const xImplSimd_DestRegSSE DQ;
};
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
const xImplSimd_DestRegSSE DQ;
};
//////////////////////////////////////////////////////////////////////////////////////////
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
//
struct xImplSimd_rSqrt
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS;
};
//////////////////////////////////////////////////////////////////////////////////////////
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
//
struct xImplSimd_rSqrt
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS;
};
//////////////////////////////////////////////////////////////////////////////////////////
// SQRT has PS/SS/SD forms, but not the PD form.
//
struct xImplSimd_Sqrt
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD;
};
//////////////////////////////////////////////////////////////////////////////////////////
// SQRT has PS/SS/SD forms, but not the PD form.
//
struct xImplSimd_Sqrt
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE SS;
const xImplSimd_DestRegSSE SD;
};
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_AndNot
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD;
};
//////////////////////////////////////////////////////////////////////////////////////////
//
struct xImplSimd_AndNot
{
const xImplSimd_DestRegSSE PS;
const xImplSimd_DestRegSSE PD;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Packed absolute value. [sSSE3 only]
//
struct xImplSimd_PAbsolute
{
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
// in dest, as UNSIGNED.
const xImplSimd_DestRegEither B;
//////////////////////////////////////////////////////////////////////////////////////////
// Packed absolute value. [sSSE3 only]
//
struct xImplSimd_PAbsolute
{
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
// in dest, as UNSIGNED.
const xImplSimd_DestRegEither B;
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
// in dest, as UNSIGNED.
const xImplSimd_DestRegEither W;
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
// in dest, as UNSIGNED.
const xImplSimd_DestRegEither W;
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
// result in dest, as UNSIGNED.
const xImplSimd_DestRegEither D;
};
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
// result in dest, as UNSIGNED.
const xImplSimd_DestRegEither D;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
// corresponding sign in src.
//
struct xImplSimd_PSign
{
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither B;
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
// corresponding sign in src.
//
struct xImplSimd_PSign
{
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither B;
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither W;
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither W;
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither D;
};
// [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
// 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
// dest is set to zero.
const xImplSimd_DestRegEither D;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Multiply and Add!!
//
struct xImplSimd_PMultAdd
{
// Multiplies the individual signed words of dest by the corresponding signed words
// of src, producing temporary signed, doubleword results. The adjacent doubleword
// 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[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
// [.. repeat in the case of XMM src/dest operands ..]
//
const xImplSimd_DestRegEither WD;
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Multiply and Add!!
//
struct xImplSimd_PMultAdd
{
// Multiplies the individual signed words of dest by the corresponding signed words
// of src, producing temporary signed, doubleword results. The adjacent doubleword
// 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[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
// [.. repeat in the case of XMM src/dest operands ..]
//
const xImplSimd_DestRegEither WD;
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
// 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.
// 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
// 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 same operation is performed on the other pairs of adjacent bytes.
//
// In Coder Speak:
// 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] );
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
//
const xImplSimd_DestRegEither UBSW;
};
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
// 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.
// 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
// 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 same operation is performed on the other pairs of adjacent bytes.
//
// In Coder Speak:
// 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] );
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
//
const xImplSimd_DestRegEither UBSW;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Horizontal Add [SSE3 only]
//
struct xImplSimd_HorizAdd
{
// [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
// 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
// stores the result in the second dword of dest.
// * Adds single-precision floating-point values in the first and second dword of *src*
// and stores the result in the third dword of dest.
const xImplSimd_DestRegSSE PS;
//////////////////////////////////////////////////////////////////////////////////////////
// Packed Horizontal Add [SSE3 only]
//
struct xImplSimd_HorizAdd
{
// [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
// 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
// stores the result in the second dword of dest.
// * Adds single-precision floating-point values in the first and second dword of *src*
// and stores the result in the third dword of dest.
const xImplSimd_DestRegSSE PS;
// [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
// 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
// *src* stores the result in the high quadword of dest.
const xImplSimd_DestRegSSE PD;
};
// [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
// 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
// *src* stores the result in the high quadword of dest.
const xImplSimd_DestRegSSE PD;
};
//////////////////////////////////////////////////////////////////////////////////////////
// DotProduct calculation (SSE4.1 only!)
//
struct xImplSimd_DotProduct
{
// [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
// 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
// of 0.0. The four resulting single-precision values are summed into an inter-
// mediate result.
//
// 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
// 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
// the destination is set to zero.
//
xImplSimd_DestRegImmSSE PS;
//////////////////////////////////////////////////////////////////////////////////////////
// DotProduct calculation (SSE4.1 only!)
//
struct xImplSimd_DotProduct
{
// [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
// 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
// of 0.0. The four resulting single-precision values are summed into an inter-
// mediate result.
//
// 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
// 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
// the destination is set to zero.
//
xImplSimd_DestRegImmSSE PS;
// [SSE-4.1]
xImplSimd_DestRegImmSSE PD;
};
// [SSE-4.1]
xImplSimd_DestRegImmSSE PD;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
// (SSE4.1 only!)
struct xImplSimd_Round
{
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE PS;
//////////////////////////////////////////////////////////////////////////////////////////
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
// (SSE4.1 only!)
struct xImplSimd_Round
{
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE PS;
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE PD;
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE PD;
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE SS;
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE SS;
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE SD;
};
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
//
// Imm8 specifies control fields for the rounding operation:
// 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.
// Bits 1:0 - Specifies a rounding mode for this instruction only.
//
// Rounding Mode Reference:
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
//
const xImplSimd_DestRegImmSSE SD;
};
} // End namespace x86Emitter

View File

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

View File

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

View File

@ -18,156 +18,156 @@
namespace x86Emitter
{
// --------------------------------------------------------------------------------------
// xImplSimd_MovHL
// --------------------------------------------------------------------------------------
// Moves to/from high/low portions of an xmm register.
// These instructions cannot be used in reg/reg form.
//
struct xImplSimd_MovHL
{
u16 Opcode;
// --------------------------------------------------------------------------------------
// xImplSimd_MovHL
// --------------------------------------------------------------------------------------
// Moves to/from high/low portions of an xmm register.
// These instructions cannot be used in reg/reg form.
//
struct xImplSimd_MovHL
{
u16 Opcode;
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const;
void PS(const xIndirectVoid &to, const xRegisterSSE &from) const;
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
void PS(const xIndirectVoid& to, const xRegisterSSE& from) const;
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const;
void PD(const xIndirectVoid &to, const xRegisterSSE &from) const;
};
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
void PD(const xIndirectVoid& to, const xRegisterSSE& from) const;
};
// --------------------------------------------------------------------------------------
// xImplSimd_MovHL_RtoR
// --------------------------------------------------------------------------------------
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
// do something kinda different! Fun!
//
struct xImplSimd_MovHL_RtoR
{
u16 Opcode;
// --------------------------------------------------------------------------------------
// xImplSimd_MovHL_RtoR
// --------------------------------------------------------------------------------------
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
// do something kinda different! Fun!
//
struct xImplSimd_MovHL_RtoR
{
u16 Opcode;
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const;
void PD(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;
};
// --------------------------------------------------------------------------------------
// xImplSimd_MoveSSE
// --------------------------------------------------------------------------------------
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
//
// 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
// which can be checked for alignment at runtime.
//
struct xImplSimd_MoveSSE
{
u8 Prefix;
bool isAligned;
// --------------------------------------------------------------------------------------
// xImplSimd_MoveSSE
// --------------------------------------------------------------------------------------
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
//
// 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
// which can be checked for alignment at runtime.
//
struct xImplSimd_MoveSSE
{
u8 Prefix;
bool isAligned;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
void operator()(const xIndirectVoid &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 xIndirectVoid& to, const xRegisterSSE& from) const;
};
// --------------------------------------------------------------------------------------
// xImplSimd_MoveDQ
// --------------------------------------------------------------------------------------
// Implementations for MOVDQA / MOVDQU
//
// 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
// which can be checked for alignment at runtime.
// --------------------------------------------------------------------------------------
// xImplSimd_MoveDQ
// --------------------------------------------------------------------------------------
// Implementations for MOVDQA / MOVDQU
//
// 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
// which can be checked for alignment at runtime.
struct xImplSimd_MoveDQ
{
u8 Prefix;
bool isAligned;
struct xImplSimd_MoveDQ
{
u8 Prefix;
bool isAligned;
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
void operator()(const xIndirectVoid &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 xIndirectVoid& to, const xRegisterSSE& from) const;
};
// --------------------------------------------------------------------------------------
// xImplSimd_Blend
// --------------------------------------------------------------------------------------
// Blend - Conditional copying of values in src into dest.
//
struct xImplSimd_Blend
{
// [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
// dword element in a 128-bit operand.
//
// 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.
//
xImplSimd_DestRegImmSSE PS;
// --------------------------------------------------------------------------------------
// xImplSimd_Blend
// --------------------------------------------------------------------------------------
// Blend - Conditional copying of values in src into dest.
//
struct xImplSimd_Blend
{
// [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
// dword element in a 128-bit operand.
//
// 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.
//
xImplSimd_DestRegImmSSE PS;
// [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
// quadword element in a 128-bit operand.
//
// 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.
//
xImplSimd_DestRegImmSSE PD;
// [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
// quadword element in a 128-bit operand.
//
// 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.
//
xImplSimd_DestRegImmSSE PD;
// [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
// 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
// to dest, else the dword element in dest is left unchanged.
//
xImplSimd_DestRegSSE VPS;
// [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
// 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
// to dest, else the dword element in dest is left unchanged.
//
xImplSimd_DestRegSSE VPS;
// [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
// 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
// to dest, else the dword element in dest is left unchanged.
//
xImplSimd_DestRegSSE VPD;
};
// [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
// 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
// to dest, else the dword element in dest is left unchanged.
//
xImplSimd_DestRegSSE VPD;
};
// --------------------------------------------------------------------------------------
// xImplSimd_PMove
// --------------------------------------------------------------------------------------
// Packed Move with Sign or Zero extension.
//
struct xImplSimd_PMove
{
u16 OpcodeBase;
// --------------------------------------------------------------------------------------
// xImplSimd_PMove
// --------------------------------------------------------------------------------------
// Packed Move with Sign or Zero extension.
//
struct xImplSimd_PMove
{
u16 OpcodeBase;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
// and store them in dest.
void BW(const xRegisterSSE &to, const xRegisterSSE &from) const;
void BW(const xRegisterSSE &to, const xIndirect64 &from) const;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
// and store them in dest.
void BW(const xRegisterSSE& to, const xRegisterSSE& 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
// and store them in dest.
void BD(const xRegisterSSE &to, const xRegisterSSE &from) const;
void BD(const xRegisterSSE &to, const xIndirect32 &from) const;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
// and store them in dest.
void BD(const xRegisterSSE& to, const xRegisterSSE& 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
// and store them in dest.
void BQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
void BQ(const xRegisterSSE &to, const xIndirect16 &from) const;
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
// and store them in dest.
void BQ(const xRegisterSSE& to, const xRegisterSSE& 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
// and store them in dest.
void WD(const xRegisterSSE &to, const xRegisterSSE &from) const;
void WD(const xRegisterSSE &to, const xIndirect64 &from) const;
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
// and store them in dest.
void WD(const xRegisterSSE& to, const xRegisterSSE& 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
// and store them in dest.
void WQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
void WQ(const xRegisterSSE &to, const xIndirect32 &from) const;
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
// and store them in dest.
void WQ(const xRegisterSSE& to, const xRegisterSSE& 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
// and store them in dest.
void DQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
void DQ(const xRegisterSSE &to, const xIndirect64 &from) const;
};
}
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
// and store them in dest.
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
};
} // namespace x86Emitter

View File

@ -18,50 +18,50 @@
namespace x86Emitter
{
// --------------------------------------------------------------------------------------
// xImplSimd_Shuffle
// --------------------------------------------------------------------------------------
struct xImplSimd_Shuffle
{
inline void _selector_assertion_check(u8 selector) const;
// --------------------------------------------------------------------------------------
// xImplSimd_Shuffle
// --------------------------------------------------------------------------------------
struct xImplSimd_Shuffle
{
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 xIndirectVoid &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 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 xRegisterSSE& from, u8 selector) const;
void PD(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
};
// --------------------------------------------------------------------------------------
// xImplSimd_PShuffle
// --------------------------------------------------------------------------------------
struct xImplSimd_PShuffle
{
// Copies doublewords from src and inserts them into dest at dword locations selected
// with the order operand (8 bit immediate).
const xImplSimd_DestRegImmSSE D;
// --------------------------------------------------------------------------------------
// xImplSimd_PShuffle
// --------------------------------------------------------------------------------------
struct xImplSimd_PShuffle
{
// Copies doublewords from src and inserts them into dest at dword locations selected
// with the order operand (8 bit immediate).
const xImplSimd_DestRegImmSSE D;
// 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).
// The high quadword of src is copied to the high quadword of dest.
const xImplSimd_DestRegImmSSE LW;
// 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).
// The high quadword of src is copied to the high quadword of dest.
const xImplSimd_DestRegImmSSE LW;
// 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).
// The low quadword of src is copied to the low quadword of dest.
const xImplSimd_DestRegImmSSE HW;
// 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).
// The low quadword of src is copied to the low quadword of dest.
const xImplSimd_DestRegImmSSE HW;
// [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
// 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
// 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.
//
const xImplSimd_DestRegEither B;
// [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
// 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
// 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.
//
const xImplSimd_DestRegEither B;
// 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
// 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
#if 0
// 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 xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
#endif
};
};
// --------------------------------------------------------------------------------------
// SimdImpl_PUnpack
// --------------------------------------------------------------------------------------
struct SimdImpl_PUnpack
{
// Unpack and interleave low-order bytes from src and dest into dest.
const xImplSimd_DestRegEither LBW;
// Unpack and interleave low-order words from src and dest into dest.
const xImplSimd_DestRegEither LWD;
// Unpack and interleave low-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither LDQ;
// Unpack and interleave low-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE LQDQ;
// --------------------------------------------------------------------------------------
// SimdImpl_PUnpack
// --------------------------------------------------------------------------------------
struct SimdImpl_PUnpack
{
// Unpack and interleave low-order bytes from src and dest into dest.
const xImplSimd_DestRegEither LBW;
// Unpack and interleave low-order words from src and dest into dest.
const xImplSimd_DestRegEither LWD;
// Unpack and interleave low-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither LDQ;
// Unpack and interleave low-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE LQDQ;
// Unpack and interleave high-order bytes from src and dest into dest.
const xImplSimd_DestRegEither HBW;
// Unpack and interleave high-order words from src and dest into dest.
const xImplSimd_DestRegEither HWD;
// Unpack and interleave high-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither HDQ;
// Unpack and interleave high-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE HQDQ;
};
// Unpack and interleave high-order bytes from src and dest into dest.
const xImplSimd_DestRegEither HBW;
// Unpack and interleave high-order words from src and dest into dest.
const xImplSimd_DestRegEither HWD;
// Unpack and interleave high-order doublewords from src and dest into dest.
const xImplSimd_DestRegEither HDQ;
// Unpack and interleave high-order quadwords from src and dest into dest.
const xImplSimd_DestRegSSE HQDQ;
};
// --------------------------------------------------------------------------------------
// SimdImpl_Pack
// --------------------------------------------------------------------------------------
// Pack with Signed or Unsigned Saturation
//
struct SimdImpl_Pack
{
// Converts packed signed word integers from src and dest into packed signed
// byte integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSWB;
// --------------------------------------------------------------------------------------
// SimdImpl_Pack
// --------------------------------------------------------------------------------------
// Pack with Signed or Unsigned Saturation
//
struct SimdImpl_Pack
{
// Converts packed signed word integers from src and dest into packed signed
// byte integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSWB;
// Converts packed signed dword integers from src and dest into packed signed
// word integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSDW;
// Converts packed signed dword integers from src and dest into packed signed
// word integers in dest, using signed saturation.
const xImplSimd_DestRegEither SSDW;
// Converts packed unsigned word integers from src and dest into packed unsigned
// byte integers in dest, using unsigned saturation.
const xImplSimd_DestRegEither USWB;
// Converts packed unsigned word integers from src and dest into packed unsigned
// byte integers in dest, using unsigned saturation.
const xImplSimd_DestRegEither USWB;
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
// unsigned word integers in dest, using signed saturation.
const xImplSimd_DestRegSSE USDW;
};
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
// unsigned word integers in dest, using signed saturation.
const xImplSimd_DestRegSSE USDW;
};
// --------------------------------------------------------------------------------------
// SimdImpl_Unpack
// --------------------------------------------------------------------------------------
struct xImplSimd_Unpack
{
// Unpacks the high doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest[0] <- dest[2]
// dest[1] <- src[2]
// dest[2] <- dest[3]
// dest[3] <- src[3]
//
const xImplSimd_DestRegSSE HPS;
// --------------------------------------------------------------------------------------
// SimdImpl_Unpack
// --------------------------------------------------------------------------------------
struct xImplSimd_Unpack
{
// Unpacks the high doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest[0] <- dest[2]
// dest[1] <- src[2]
// dest[2] <- dest[3]
// dest[3] <- src[3]
//
const xImplSimd_DestRegSSE HPS;
// Unpacks the high quadword [double-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest.lo <- dest.hi
// dest.hi <- src.hi
//
const xImplSimd_DestRegSSE HPD;
// Unpacks the high quadword [double-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest.lo <- dest.hi
// dest.hi <- src.hi
//
const xImplSimd_DestRegSSE HPD;
// Unpacks the low doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest[3] <- src[1]
// dest[2] <- dest[1]
// dest[1] <- src[0]
// dest[0] <- dest[0]
//
const xImplSimd_DestRegSSE LPS;
// Unpacks the low doubleword [single-precision] values from src and dest into
// dest, such that the result of dest looks like this:
// dest[3] <- src[1]
// dest[2] <- dest[1]
// dest[1] <- src[0]
// dest[0] <- dest[0]
//
const xImplSimd_DestRegSSE LPS;
// 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.
// The result of dest is loaded as such:
// dest.hi <- src.lo
// dest.lo <- dest.lo [remains unchanged!]
//
const xImplSimd_DestRegSSE LPD;
};
// 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.
// The result of dest is loaded as such:
// dest.hi <- src.lo
// dest.lo <- dest.lo [remains unchanged!]
//
const xImplSimd_DestRegSSE LPD;
};
struct xImplSimd_InsertExtractHelper
{
u16 Opcode;
struct xImplSimd_InsertExtractHelper
{
u16 Opcode;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
};
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
};
// --------------------------------------------------------------------------------------
// SimdImpl_PInsert
// --------------------------------------------------------------------------------------
// PINSRW/B/D [all but Word form are SSE4.1 only!]
//
struct xImplSimd_PInsert
{
void W(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
void W(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
// --------------------------------------------------------------------------------------
// SimdImpl_PInsert
// --------------------------------------------------------------------------------------
// PINSRW/B/D [all but Word form are SSE4.1 only!]
//
struct xImplSimd_PInsert
{
void W(const xRegisterSSE& to, const xRegister32& 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)
xImplSimd_InsertExtractHelper B;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
xImplSimd_InsertExtractHelper B;
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
xImplSimd_InsertExtractHelper D;
};
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
xImplSimd_InsertExtractHelper D;
};
//////////////////////////////////////////////////////////////////////////////////////////
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
//
// Note: Word form's indirect memory form is only available in SSE4.1.
//
struct SimdImpl_PExtract
{
// 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
// 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!
//
void W(const xRegister32 &to, const xRegisterSSE &from, u8 imm8) const;
void W(const xIndirectVoid &dest, const xRegisterSSE &from, u8 imm8) const;
//////////////////////////////////////////////////////////////////////////////////////////
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
//
// Note: Word form's indirect memory form is only available in SSE4.1.
//
struct SimdImpl_PExtract
{
// 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
// 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!
//
void W(const xRegister32& to, 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
// 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.
const xImplSimd_InsertExtractHelper B;
// [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
// byte value from src into an x86 32 bit register.
const xImplSimd_InsertExtractHelper B;
// [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.
const xImplSimd_InsertExtractHelper D;
};
}
// [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.
const xImplSimd_InsertExtractHelper D;
};
} // namespace x86Emitter

View File

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

View File

@ -20,55 +20,56 @@
namespace x86Emitter
{
// --------------------------------------------------------------------------------------
// xImpl_Test
// --------------------------------------------------------------------------------------
//
struct xImpl_Test
{
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
void operator()(const xIndirect64orLess &dest, int imm) const;
void operator()(const xRegisterInt &to, int imm) const;
};
// --------------------------------------------------------------------------------------
// xImpl_Test
// --------------------------------------------------------------------------------------
//
struct xImpl_Test
{
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
void operator()(const xIndirect64orLess& dest, int imm) const;
void operator()(const xRegisterInt& to, int imm) const;
};
enum G8Type {
G8Type_BT = 4,
G8Type_BTS,
G8Type_BTR,
G8Type_BTC,
};
enum G8Type
{
G8Type_BT = 4,
G8Type_BTS,
G8Type_BTR,
G8Type_BTC,
};
// --------------------------------------------------------------------------------------
// BSF / BSR
// --------------------------------------------------------------------------------------
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
//
struct xImpl_BitScan
{
// 0xbc [fwd] / 0xbd [rev]
u16 Opcode;
// --------------------------------------------------------------------------------------
// BSF / BSR
// --------------------------------------------------------------------------------------
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
//
struct xImpl_BitScan
{
// 0xbc [fwd] / 0xbd [rev]
u16 Opcode;
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
};
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
};
// --------------------------------------------------------------------------------------
// xImpl_Group8
// --------------------------------------------------------------------------------------
// Bit Test Instructions - Valid on 16/32 bit instructions only.
//
struct xImpl_Group8
{
G8Type InstType;
// --------------------------------------------------------------------------------------
// xImpl_Group8
// --------------------------------------------------------------------------------------
// Bit Test Instructions - Valid on 16/32 bit instructions only.
//
struct xImpl_Group8
{
G8Type InstType;
void operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const;
void operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const;
void operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& 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 xIndirect32 &bitbase, u8 bitoffset) const;
void operator()(const xIndirect16 &bitbase, u8 bitoffset) const;
};
void operator()(const xIndirect64& bitbase, u8 bitoffset) const;
void operator()(const xIndirect32& bitbase, u8 bitoffset) const;
void operator()(const xIndirect16& bitbase, u8 bitoffset) const;
};
} // 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)
extern void SimdPrefix(u8 prefix, u16 opcode);
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 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 xIndirectVoid &sib, int extraRIPOffset = 0);
extern void SimdPrefix(u8 prefix, u16 opcode);
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 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 xIndirectVoid& sib, int extraRIPOffset = 0);
extern void EmitRex(uint regfield, const void *address);
extern void EmitRex(uint regfield, const xIndirectVoid &info);
extern void EmitRex(uint 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 xIndirectVoid &sib);
extern void EmitRex(uint regfield, const void* address);
extern void EmitRex(uint regfield, const xIndirectVoid& info);
extern void EmitRex(uint 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 xIndirectVoid& sib);
extern void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from);
extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
template <typename T>
inline void xWrite(T val)
{
*(T *)x86Ptr = val;
x86Ptr += sizeof(T);
}
template <typename T>
inline void xWrite(T val)
{
*(T*)x86Ptr = val;
x86Ptr += sizeof(T);
}
template <typename T1, typename T2>
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1 &param1, const T2 &param2, int extraRIPOffset = 0)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
template <typename T1, typename T2>
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2, int extraRIPOffset = 0)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
xWrite8(opcode);
xWrite8(opcode);
EmitSibMagic(param1, param2, extraRIPOffset);
}
EmitSibMagic(param1, param2, extraRIPOffset);
}
template <typename T1, typename T2>
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1 &param1, const T2 &param2)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
template <typename T1, typename T2>
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
xWrite8(opcode);
}
xWrite8(opcode);
}
//////////////////////////////////////////////////////////////////////////////////////////
// emitter helpers for xmm instruction with prefixes, most of which are using
// the basic opcode format (items inside braces denote optional or conditional
// emission):
//
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
//
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
// 0x3a [and other value will result in assertion failue].
//
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 &param1, const T2 &param2)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
//////////////////////////////////////////////////////////////////////////////////////////
// emitter helpers for xmm instruction with prefixes, most of which are using
// the basic opcode format (items inside braces denote optional or conditional
// emission):
//
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
//
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
// 0x3a [and other value will result in assertion failue].
//
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
SimdPrefix(0, opcode);
SimdPrefix(0, opcode);
EmitSibMagic(param1, param2);
}
EmitSibMagic(param1, param2);
}
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 &param1, const T2 &param2, u8 imm8)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8)
{
if (prefix != 0)
xWrite8(prefix);
EmitRex(param1, param2);
SimdPrefix(0, opcode);
SimdPrefix(0, opcode);
EmitSibMagic(param1, param2, 1);
xWrite8(imm8);
}
EmitSibMagic(param1, param2, 1);
xWrite8(imm8);
}
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1 &param1, const T2 &param2)
{
xOpWrite0F(0, opcode, param1, param2);
}
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2)
{
xOpWrite0F(0, opcode, param1, param2);
}
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1 &param1, const T2 &param2, u8 imm8)
{
xOpWrite0F(0, opcode, param1, param2, imm8);
}
template <typename T1, typename T2>
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2, u8 imm8)
{
xOpWrite0F(0, opcode, param1, param2, imm8);
}
// VEX 2 Bytes Prefix
template <typename T1, typename T2, typename T3>
__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);
// VEX 2 Bytes Prefix
template <typename T1, typename T2, typename T3>
__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);
const xRegisterInt &reg = param1.IsReg() ? param1 : param2;
const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
#ifdef __M_X86_64
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
#else
u8 nR = 0x80;
u8 nR = 0x80;
#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 =
prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 : 0;
u8 p =
prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 :
0;
xWrite8(0xC5);
xWrite8(nR | nv | L | p);
xWrite8(opcode);
EmitSibMagic(param1, param3);
}
xWrite8(0xC5);
xWrite8(nR | nv | L | p);
xWrite8(opcode);
EmitSibMagic(param1, param3);
}
// VEX 3 Bytes Prefix
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)
{
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
// VEX 3 Bytes Prefix
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)
{
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
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
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
u8 nX = 0x40; // likely unused so hardwired to disabled
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
u8 nX = 0x40; // likely unused so hardwired to disabled
#else
u8 nR = 0x80;
u8 nB = 0x20;
u8 nX = 0x40;
u8 nR = 0x80;
u8 nB = 0x20;
u8 nX = 0x40;
#endif
u8 L = reg.IsWideSIMD() ? 4 : 0;
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
0x80 * w; // take directly the W value
u8 L = reg.IsWideSIMD() ? 4 : 0;
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
0x80 * w; // take directly the W value
u8 nv = (~param2.GetId() & 0xF) << 3;
u8 nv = (~param2.GetId() & 0xF) << 3;
u8 p =
prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 : 0;
u8 p =
prefix == 0xF2 ? 3 :
prefix == 0xF3 ? 2 :
prefix == 0x66 ? 1 :
0;
u8 m =
mb_prefix == 0x3A ? 3 :
mb_prefix == 0x38 ? 2 : 1;
u8 m =
mb_prefix == 0x3A ? 3 :
mb_prefix == 0x38 ? 2 :
1;
xWrite8(0xC4);
xWrite8(nR | nX | nB | m);
xWrite8(W | nv | L | p);
xWrite8(opcode);
EmitSibMagic(param1, param3);
}
}
xWrite8(0xC4);
xWrite8(nR | nX | nB | m);
xWrite8(W | nv | L | p);
xWrite8(opcode);
EmitSibMagic(param1, param3);
}
} // namespace x86Emitter

View File

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

View File

@ -29,24 +29,24 @@
emitterT void ModRM(uint mod, uint reg, uint rm)
{
// Note: Following assertions are for legacy support only.
// 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.
pxAssert(mod < 4);
pxAssert(reg < 8);
pxAssert(rm < 8);
xWrite8((mod << 6) | (reg << 3) | rm);
// Note: Following assertions are for legacy support only.
// 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.
pxAssert(mod < 4);
pxAssert(reg < 8);
pxAssert(rm < 8);
xWrite8((mod << 6) | (reg << 3) | rm);
}
emitterT void SibSB(uint ss, uint index, uint base)
{
// Note: Following asserts are for legacy support only.
// 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.
pxAssert(ss < 4);
pxAssert(index < 8);
pxAssert(base < 8);
xWrite8((ss << 6) | (index << 3) | base);
// Note: Following asserts are for legacy support only.
// 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.
pxAssert(ss < 4);
pxAssert(index < 8);
pxAssert(base < 8);
xWrite8((ss << 6) | (index << 3) | base);
}
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(to);
return (u8 *)(x86Ptr - 1);
xWrite8(cc);
xWrite8(to);
return (u8*)(x86Ptr - 1);
}
emitterT u16 *J16Rel(int cc, u32 to)
emitterT u16* J16Rel(int cc, u32 to)
{
xWrite16(0x0F66);
xWrite8(cc);
xWrite16(to);
return (u16 *)(x86Ptr - 2);
xWrite16(0x0F66);
xWrite8(cc);
xWrite16(to);
return (u16*)(x86Ptr - 2);
}
emitterT u32 *J32Rel(int cc, u32 to)
emitterT u32* J32Rel(int cc, u32 to)
{
xWrite8(0x0F);
xWrite8(cc);
xWrite32(to);
return (u32 *)(x86Ptr - 4);
xWrite8(0x0F);
xWrite8(cc);
xWrite32(to);
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
// 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) {
Console.Error("j8 greater than 0x7f!!");
assert(0);
}
*j8 = (u8)jump;
if (jump > 0x7f)
{
Console.Error("j8 greater than 0x7f!!");
assert(0);
}
*j8 = (u8)jump;
}
void x86SetJ8A(u8 *j8)
void x86SetJ8A(u8* j8)
{
u32 jump = (x86Ptr - j8) - 1;
u32 jump = (x86Ptr - j8) - 1;
if (jump > 0x7f) {
Console.Error("j8 greater than 0x7f!!");
assert(0);
}
if (jump > 0x7f)
{
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) {
jump = newjump;
while ((uptr)x86Ptr & 0xf)
*x86Ptr++ = 0x90;
}
}
*j8 = (u8)jump;
if (newjump <= 0x7f)
{
jump = newjump;
while ((uptr)x86Ptr & 0xf)
*x86Ptr++ = 0x90;
}
}
*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)
*x86Ptr++ = 0x90;
x86SetJ32(j32);
while ((uptr)x86Ptr & 0xf)
*x86Ptr++ = 0x90;
x86SetJ32(j32);
}
////////////////////////////////////////////////////
emitterT void x86Align(int bytes)
{
// forward align
x86Ptr = (u8 *)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
// forward align
x86Ptr = (u8*)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
}
/********************/
@ -154,262 +158,262 @@ emitterT void x86Align(int bytes)
////////////////////////////////////
/* jmp rel8 */
emitterT u8 *JMP8(u8 to)
emitterT u8* JMP8(u8 to)
{
xWrite8(0xEB);
xWrite8(to);
return x86Ptr - 1;
xWrite8(0xEB);
xWrite8(to);
return x86Ptr - 1;
}
/* jmp rel32 */
emitterT u32 *JMP32(uptr to)
emitterT u32* JMP32(uptr to)
{
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
xWrite8(0xE9);
xWrite32(to);
return (u32 *)(x86Ptr - 4);
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
xWrite8(0xE9);
xWrite32(to);
return (u32*)(x86Ptr - 4);
}
/* jp rel8 */
emitterT u8 *JP8(u8 to)
emitterT u8* JP8(u8 to)
{
return J8Rel(0x7A, to);
return J8Rel(0x7A, to);
}
/* jnp rel8 */
emitterT u8 *JNP8(u8 to)
emitterT u8* JNP8(u8 to)
{
return J8Rel(0x7B, to);
return J8Rel(0x7B, to);
}
/* je rel8 */
emitterT u8 *JE8(u8 to)
emitterT u8* JE8(u8 to)
{
return J8Rel(0x74, to);
return J8Rel(0x74, to);
}
/* jz rel8 */
emitterT u8 *JZ8(u8 to)
emitterT u8* JZ8(u8 to)
{
return J8Rel(0x74, to);
return J8Rel(0x74, to);
}
/* js rel8 */
emitterT u8 *JS8(u8 to)
emitterT u8* JS8(u8 to)
{
return J8Rel(0x78, to);
return J8Rel(0x78, to);
}
/* jns rel8 */
emitterT u8 *JNS8(u8 to)
emitterT u8* JNS8(u8 to)
{
return J8Rel(0x79, to);
return J8Rel(0x79, to);
}
/* jg rel8 */
emitterT u8 *JG8(u8 to)
emitterT u8* JG8(u8 to)
{
return J8Rel(0x7F, to);
return J8Rel(0x7F, to);
}
/* jge rel8 */
emitterT u8 *JGE8(u8 to)
emitterT u8* JGE8(u8 to)
{
return J8Rel(0x7D, to);
return J8Rel(0x7D, to);
}
/* jl rel8 */
emitterT u8 *JL8(u8 to)
emitterT u8* JL8(u8 to)
{
return J8Rel(0x7C, to);
return J8Rel(0x7C, to);
}
/* 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 */
emitterT u8 *JB8(u8 to)
emitterT u8* JB8(u8 to)
{
return J8Rel(0x72, to);
return J8Rel(0x72, to);
}
/* jbe rel8 */
emitterT u8 *JBE8(u8 to)
emitterT u8* JBE8(u8 to)
{
return J8Rel(0x76, to);
return J8Rel(0x76, to);
}
/* jle rel8 */
emitterT u8 *JLE8(u8 to)
emitterT u8* JLE8(u8 to)
{
return J8Rel(0x7E, to);
return J8Rel(0x7E, to);
}
/* jne rel8 */
emitterT u8 *JNE8(u8 to)
emitterT u8* JNE8(u8 to)
{
return J8Rel(0x75, to);
return J8Rel(0x75, to);
}
/* jnz rel8 */
emitterT u8 *JNZ8(u8 to)
emitterT u8* JNZ8(u8 to)
{
return J8Rel(0x75, to);
return J8Rel(0x75, to);
}
/* jng rel8 */
emitterT u8 *JNG8(u8 to)
emitterT u8* JNG8(u8 to)
{
return J8Rel(0x7E, to);
return J8Rel(0x7E, to);
}
/* jnge rel8 */
emitterT u8 *JNGE8(u8 to)
emitterT u8* JNGE8(u8 to)
{
return J8Rel(0x7C, to);
return J8Rel(0x7C, to);
}
/* jnl rel8 */
emitterT u8 *JNL8(u8 to)
emitterT u8* JNL8(u8 to)
{
return J8Rel(0x7D, to);
return J8Rel(0x7D, to);
}
/* jnle rel8 */
emitterT u8 *JNLE8(u8 to)
emitterT u8* JNLE8(u8 to)
{
return J8Rel(0x7F, to);
return J8Rel(0x7F, to);
}
/* jo rel8 */
emitterT u8 *JO8(u8 to)
emitterT u8* JO8(u8 to)
{
return J8Rel(0x70, to);
return J8Rel(0x70, to);
}
/* jno rel8 */
emitterT u8 *JNO8(u8 to)
emitterT u8* JNO8(u8 to)
{
return J8Rel(0x71, to);
return J8Rel(0x71, to);
}
// jb rel32
emitterT u32 *JB32(u32 to)
emitterT u32* JB32(u32 to)
{
return J32Rel(0x82, to);
return J32Rel(0x82, to);
}
/* je rel32 */
emitterT u32 *JE32(u32 to)
emitterT u32* JE32(u32 to)
{
return J32Rel(0x84, to);
return J32Rel(0x84, to);
}
/* jz rel32 */
emitterT u32 *JZ32(u32 to)
emitterT u32* JZ32(u32 to)
{
return J32Rel(0x84, to);
return J32Rel(0x84, to);
}
/* js rel32 */
emitterT u32 *JS32(u32 to)
emitterT u32* JS32(u32 to)
{
return J32Rel(0x88, to);
return J32Rel(0x88, to);
}
/* jns rel32 */
emitterT u32 *JNS32(u32 to)
emitterT u32* JNS32(u32 to)
{
return J32Rel(0x89, to);
return J32Rel(0x89, to);
}
/* jg rel32 */
emitterT u32 *JG32(u32 to)
emitterT u32* JG32(u32 to)
{
return J32Rel(0x8F, to);
return J32Rel(0x8F, to);
}
/* jge rel32 */
emitterT u32 *JGE32(u32 to)
emitterT u32* JGE32(u32 to)
{
return J32Rel(0x8D, to);
return J32Rel(0x8D, to);
}
/* jl rel32 */
emitterT u32 *JL32(u32 to)
emitterT u32* JL32(u32 to)
{
return J32Rel(0x8C, to);
return J32Rel(0x8C, to);
}
/* jle rel32 */
emitterT u32 *JLE32(u32 to)
emitterT u32* JLE32(u32 to)
{
return J32Rel(0x8E, to);
return J32Rel(0x8E, to);
}
/* ja rel32 */
emitterT u32 *JA32(u32 to)
emitterT u32* JA32(u32 to)
{
return J32Rel(0x87, to);
return J32Rel(0x87, to);
}
/* jae rel32 */
emitterT u32 *JAE32(u32 to)
emitterT u32* JAE32(u32 to)
{
return J32Rel(0x83, to);
return J32Rel(0x83, to);
}
/* jne rel32 */
emitterT u32 *JNE32(u32 to)
emitterT u32* JNE32(u32 to)
{
return J32Rel(0x85, to);
return J32Rel(0x85, to);
}
/* jnz rel32 */
emitterT u32 *JNZ32(u32 to)
emitterT u32* JNZ32(u32 to)
{
return J32Rel(0x85, to);
return J32Rel(0x85, to);
}
/* jng rel32 */
emitterT u32 *JNG32(u32 to)
emitterT u32* JNG32(u32 to)
{
return J32Rel(0x8E, to);
return J32Rel(0x8E, to);
}
/* jnge rel32 */
emitterT u32 *JNGE32(u32 to)
emitterT u32* JNGE32(u32 to)
{
return J32Rel(0x8C, to);
return J32Rel(0x8C, to);
}
/* jnl rel32 */
emitterT u32 *JNL32(u32 to)
emitterT u32* JNL32(u32 to)
{
return J32Rel(0x8D, to);
return J32Rel(0x8D, to);
}
/* jnle rel32 */
emitterT u32 *JNLE32(u32 to)
emitterT u32* JNLE32(u32 to)
{
return J32Rel(0x8F, to);
return J32Rel(0x8F, to);
}
/* jo rel32 */
emitterT u32 *JO32(u32 to)
emitterT u32* JO32(u32 to)
{
return J32Rel(0x80, to);
return J32Rel(0x80, to);
}
/* 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
//------------------------------------------------------------------
ATTR_DEP extern void x86SetPtr(u8 *ptr);
ATTR_DEP extern void x86SetJ8(u8 *j8);
ATTR_DEP extern void x86SetJ8A(u8 *j8);
ATTR_DEP extern void x86SetJ16(u16 *j16);
ATTR_DEP extern void x86SetJ16A(u16 *j16);
ATTR_DEP extern void x86SetJ32(u32 *j32);
ATTR_DEP extern void x86SetJ32A(u32 *j32);
ATTR_DEP extern void x86SetPtr(u8* ptr);
ATTR_DEP extern void x86SetJ8(u8* j8);
ATTR_DEP extern void x86SetJ8A(u8* j8);
ATTR_DEP extern void x86SetJ16(u16* j16);
ATTR_DEP extern void x86SetJ16A(u16* j16);
ATTR_DEP extern void x86SetJ32(u32* j32);
ATTR_DEP extern void x86SetJ32A(u32* j32);
ATTR_DEP extern void x86Align(int bytes);
ATTR_DEP extern void x86AlignExecutable(int align);
//------------------------------------------------------------------
@ -41,55 +41,55 @@ ATTR_DEP extern void x86AlignExecutable(int align);
////////////////////////////////////
// jmp rel8
ATTR_DEP extern u8 *JMP8(u8 to);
ATTR_DEP extern u8* JMP8(u8 to);
// jmp rel32
ATTR_DEP extern u32 *JMP32(uptr to);
ATTR_DEP extern u32* JMP32(uptr to);
// jp rel8
ATTR_DEP extern u8 *JP8(u8 to);
ATTR_DEP extern u8* JP8(u8 to);
// jnp rel8
ATTR_DEP extern u8 *JNP8(u8 to);
ATTR_DEP extern u8* JNP8(u8 to);
// je rel8
ATTR_DEP extern u8 *JE8(u8 to);
ATTR_DEP extern u8* JE8(u8 to);
// jz rel8
ATTR_DEP extern u8 *JZ8(u8 to);
ATTR_DEP extern u8* JZ8(u8 to);
// jg rel8
ATTR_DEP extern u8 *JG8(u8 to);
ATTR_DEP extern u8* JG8(u8 to);
// jge rel8
ATTR_DEP extern u8 *JGE8(u8 to);
ATTR_DEP extern u8* JGE8(u8 to);
// js rel8
ATTR_DEP extern u8 *JS8(u8 to);
ATTR_DEP extern u8* JS8(u8 to);
// jns rel8
ATTR_DEP extern u8 *JNS8(u8 to);
ATTR_DEP extern u8* JNS8(u8 to);
// jl rel8
ATTR_DEP extern u8 *JL8(u8 to);
ATTR_DEP extern u8* JL8(u8 to);
// ja rel8
ATTR_DEP extern u8 *JA8(u8 to);
ATTR_DEP extern u8* JA8(u8 to);
// jae rel8
ATTR_DEP extern u8 *JAE8(u8 to);
ATTR_DEP extern u8* JAE8(u8 to);
// jb rel8
ATTR_DEP extern u8 *JB8(u8 to);
ATTR_DEP extern u8* JB8(u8 to);
// jbe rel8
ATTR_DEP extern u8 *JBE8(u8 to);
ATTR_DEP extern u8* JBE8(u8 to);
// jle rel8
ATTR_DEP extern u8 *JLE8(u8 to);
ATTR_DEP extern u8* JLE8(u8 to);
// jne rel8
ATTR_DEP extern u8 *JNE8(u8 to);
ATTR_DEP extern u8* JNE8(u8 to);
// jnz rel8
ATTR_DEP extern u8 *JNZ8(u8 to);
ATTR_DEP extern u8* JNZ8(u8 to);
// jng rel8
ATTR_DEP extern u8 *JNG8(u8 to);
ATTR_DEP extern u8* JNG8(u8 to);
// jnge rel8
ATTR_DEP extern u8 *JNGE8(u8 to);
ATTR_DEP extern u8* JNGE8(u8 to);
// jnl rel8
ATTR_DEP extern u8 *JNL8(u8 to);
ATTR_DEP extern u8* JNL8(u8 to);
// jnle rel8
ATTR_DEP extern u8 *JNLE8(u8 to);
ATTR_DEP extern u8* JNLE8(u8 to);
// jo rel8
ATTR_DEP extern u8 *JO8(u8 to);
ATTR_DEP extern u8* JO8(u8 to);
// jno rel8
ATTR_DEP extern u8 *JNO8(u8 to);
ATTR_DEP extern u8* JNO8(u8 to);
/*
// jb rel16
@ -103,44 +103,44 @@ ATTR_DEP extern u16* JZ16( u16 to );
*/
// jns rel32
ATTR_DEP extern u32 *JNS32(u32 to);
ATTR_DEP extern u32* JNS32(u32 to);
// js rel32
ATTR_DEP extern u32 *JS32(u32 to);
ATTR_DEP extern u32* JS32(u32 to);
// jb rel32
ATTR_DEP extern u32 *JB32(u32 to);
ATTR_DEP extern u32* JB32(u32 to);
// je rel32
ATTR_DEP extern u32 *JE32(u32 to);
ATTR_DEP extern u32* JE32(u32 to);
// jz rel32
ATTR_DEP extern u32 *JZ32(u32 to);
ATTR_DEP extern u32* JZ32(u32 to);
// jg rel32
ATTR_DEP extern u32 *JG32(u32 to);
ATTR_DEP extern u32* JG32(u32 to);
// jge rel32
ATTR_DEP extern u32 *JGE32(u32 to);
ATTR_DEP extern u32* JGE32(u32 to);
// jl rel32
ATTR_DEP extern u32 *JL32(u32 to);
ATTR_DEP extern u32* JL32(u32 to);
// jle rel32
ATTR_DEP extern u32 *JLE32(u32 to);
ATTR_DEP extern u32* JLE32(u32 to);
// jae rel32
ATTR_DEP extern u32 *JAE32(u32 to);
ATTR_DEP extern u32* JAE32(u32 to);
// jne rel32
ATTR_DEP extern u32 *JNE32(u32 to);
ATTR_DEP extern u32* JNE32(u32 to);
// jnz rel32
ATTR_DEP extern u32 *JNZ32(u32 to);
ATTR_DEP extern u32* JNZ32(u32 to);
// jng rel32
ATTR_DEP extern u32 *JNG32(u32 to);
ATTR_DEP extern u32* JNG32(u32 to);
// jnge rel32
ATTR_DEP extern u32 *JNGE32(u32 to);
ATTR_DEP extern u32* JNGE32(u32 to);
// jnl rel32
ATTR_DEP extern u32 *JNL32(u32 to);
ATTR_DEP extern u32* JNL32(u32 to);
// jnle rel32
ATTR_DEP extern u32 *JNLE32(u32 to);
ATTR_DEP extern u32* JNLE32(u32 to);
// jo rel32
ATTR_DEP extern u32 *JO32(u32 to);
ATTR_DEP extern u32* JO32(u32 to);
// jno rel32
ATTR_DEP extern u32 *JNO32(u32 to);
ATTR_DEP extern u32* JNO32(u32 to);
// js rel32
ATTR_DEP extern u32 *JS32(u32 to);
ATTR_DEP extern u32* JS32(u32 to);
//******************
// FPU instructions

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,11 @@
#include "common/Dependencies.h"
enum x86VendorType {
x86Vendor_Intel = 0,
x86Vendor_AMD = 1,
x86Vendor_Unknown = 2
enum x86VendorType
{
x86Vendor_Intel = 0,
x86Vendor_AMD = 1,
x86Vendor_Unknown = 2
};
// --------------------------------------------------------------------------------------
@ -29,117 +30,120 @@ enum x86VendorType {
class x86capabilities
{
public:
bool isIdentified;
bool isIdentified;
public:
x86VendorType VendorID;
x86VendorType VendorID;
uint FamilyID; // Processor Family
uint Model; // Processor Model
uint TypeID; // Processor Type
uint StepID; // Stepping ID
uint FamilyID; // Processor Family
uint Model; // Processor Model
uint TypeID; // Processor Type
uint StepID; // Stepping ID
u32 Flags; // Feature Flags
u32 Flags2; // More Feature Flags
u32 EFlags; // Extended Feature Flags
u32 EFlags2; // Extended Feature Flags pg2
u32 SEFlag; // Structured Extended Feature Flags Enumeration
u32 Flags; // Feature Flags
u32 Flags2; // More Feature Flags
u32 EFlags; // Extended Feature Flags
u32 EFlags2; // Extended Feature Flags pg2
u32 SEFlag; // Structured Extended Feature Flags Enumeration
char VendorName[16]; // Vendor/Creator ID
char FamilyName[50]; // the original cpu name
char VendorName[16]; // Vendor/Creator ID
char FamilyName[50]; // the original cpu name
// ----------------------------------------------------------------------------
// x86 CPU Capabilities Section (all boolean flags!)
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// x86 CPU Capabilities Section (all boolean flags!)
// ----------------------------------------------------------------------------
union
{
struct
{
u32 hasFloatingPointUnit : 1;
u32 hasVirtual8086ModeEnhancements : 1;
u32 hasDebuggingExtensions : 1;
u32 hasPageSizeExtensions : 1;
u32 hasTimeStampCounter : 1;
u32 hasModelSpecificRegisters : 1;
u32 hasPhysicalAddressExtension : 1;
u32 hasCOMPXCHG8BInstruction : 1;
u32 hasAdvancedProgrammableInterruptController : 1;
u32 hasSEPFastSystemCall : 1;
u32 hasMemoryTypeRangeRegisters : 1;
u32 hasPTEGlobalFlag : 1;
u32 hasMachineCheckArchitecture : 1;
u32 hasConditionalMoveAndCompareInstructions : 1;
u32 hasFGPageAttributeTable : 1;
u32 has36bitPageSizeExtension : 1;
u32 hasProcessorSerialNumber : 1;
u32 hasCFLUSHInstruction : 1;
u32 hasDebugStore : 1;
u32 hasACPIThermalMonitorAndClockControl : 1;
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
u32 hasStreamingSIMDExtensions : 1;
u32 hasStreamingSIMD2Extensions : 1;
u32 hasSelfSnoop : 1;
union
{
struct
{
u32 hasFloatingPointUnit : 1;
u32 hasVirtual8086ModeEnhancements : 1;
u32 hasDebuggingExtensions : 1;
u32 hasPageSizeExtensions : 1;
u32 hasTimeStampCounter : 1;
u32 hasModelSpecificRegisters : 1;
u32 hasPhysicalAddressExtension : 1;
u32 hasCOMPXCHG8BInstruction : 1;
u32 hasAdvancedProgrammableInterruptController : 1;
u32 hasSEPFastSystemCall : 1;
u32 hasMemoryTypeRangeRegisters : 1;
u32 hasPTEGlobalFlag : 1;
u32 hasMachineCheckArchitecture : 1;
u32 hasConditionalMoveAndCompareInstructions : 1;
u32 hasFGPageAttributeTable : 1;
u32 has36bitPageSizeExtension : 1;
u32 hasProcessorSerialNumber : 1;
u32 hasCFLUSHInstruction : 1;
u32 hasDebugStore : 1;
u32 hasACPIThermalMonitorAndClockControl : 1;
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
u32 hasStreamingSIMDExtensions : 1;
u32 hasStreamingSIMD2Extensions : 1;
u32 hasSelfSnoop : 1;
// is TRUE for both multi-core and Hyperthreaded CPUs.
u32 hasMultiThreading : 1;
// is TRUE for both multi-core and Hyperthreaded CPUs.
u32 hasMultiThreading : 1;
u32 hasThermalMonitor : 1;
u32 hasIntel64BitArchitecture : 1;
u32 hasStreamingSIMD3Extensions : 1;
u32 hasSupplementalStreamingSIMD3Extensions : 1;
u32 hasStreamingSIMD4Extensions : 1;
u32 hasStreamingSIMD4Extensions2 : 1;
u32 hasAVX : 1;
u32 hasAVX2 : 1;
u32 hasBMI1 : 1;
u32 hasBMI2 : 1;
u32 hasFMA : 1;
u32 hasThermalMonitor : 1;
u32 hasIntel64BitArchitecture : 1;
u32 hasStreamingSIMD3Extensions : 1;
u32 hasSupplementalStreamingSIMD3Extensions : 1;
u32 hasStreamingSIMD4Extensions : 1;
u32 hasStreamingSIMD4Extensions2 : 1;
u32 hasAVX : 1;
u32 hasAVX2 : 1;
u32 hasBMI1 : 1;
u32 hasBMI2 : 1;
u32 hasFMA : 1;
// AMD-specific CPU Features
u32 hasAMD64BitArchitecture : 1;
u32 hasStreamingSIMD4ExtensionsA : 1;
};
// AMD-specific CPU Features
u32 hasAMD64BitArchitecture : 1;
u32 hasStreamingSIMD4ExtensionsA : 1;
};
u64 AllCapabilities;
};
u64 AllCapabilities;
};
// Core Counts!
u32 PhysicalCores;
u32 LogicalCores;
// Core Counts!
u32 PhysicalCores;
u32 LogicalCores;
public:
x86capabilities();
x86capabilities();
void Identify();
void CountCores();
wxString GetTypeName() const;
void Identify();
void CountCores();
wxString GetTypeName() const;
u32 CalculateMHz() const;
u32 CalculateMHz() const;
void SIMD_EstablishMXCSRmask();
void SIMD_EstablishMXCSRmask();
protected:
s64 _CPUSpeedHz(u64 time) const;
void CountLogicalCores();
s64 _CPUSpeedHz(u64 time) const;
void CountLogicalCores();
};
enum SSE_RoundMode {
SSE_RoundMode_FIRST = 0,
SSEround_Nearest = 0,
SSEround_NegInf,
SSEround_PosInf,
SSEround_Chop,
SSE_RoundMode_COUNT
enum SSE_RoundMode
{
SSE_RoundMode_FIRST = 0,
SSEround_Nearest = 0,
SSEround_NegInf,
SSEround_PosInf,
SSEround_Chop,
SSE_RoundMode_COUNT
};
ImplementEnumOperators(SSE_RoundMode);
// Predeclaration for xIndirect32
namespace x86Emitter {
template <typename T> class xIndirect;
namespace x86Emitter
{
template <typename T>
class xIndirect;
typedef xIndirect<u32> xIndirect32;
}
} // namespace x86Emitter
// --------------------------------------------------------------------------------------
// SSE_MXCSR - Control/Status Register (bitfield)
@ -153,52 +157,52 @@ namespace x86Emitter {
//
union SSE_MXCSR
{
u32 bitmask;
struct
{
u32
InvalidOpFlag : 1,
DenormalFlag : 1,
DivideByZeroFlag : 1,
OverflowFlag : 1,
UnderflowFlag : 1,
PrecisionFlag : 1,
u32 bitmask;
struct
{
u32
InvalidOpFlag : 1,
DenormalFlag : 1,
DivideByZeroFlag : 1,
OverflowFlag : 1,
UnderflowFlag : 1,
PrecisionFlag : 1,
// 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
// LDMXSCR.
DenormalsAreZero : 1,
// 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
// LDMXSCR.
DenormalsAreZero : 1,
InvalidOpMask : 1,
DenormalMask : 1,
DivideByZeroMask : 1,
OverflowMask : 1,
UnderflowMask : 1,
PrecisionMask : 1,
InvalidOpMask : 1,
DenormalMask : 1,
DivideByZeroMask : 1,
OverflowMask : 1,
UnderflowMask : 1,
PrecisionMask : 1,
RoundingControl : 2,
FlushToZero : 1;
};
RoundingControl : 2,
FlushToZero : 1;
};
SSE_RoundMode GetRoundMode() const;
SSE_MXCSR &SetRoundMode(SSE_RoundMode mode);
SSE_MXCSR &ClearExceptionFlags();
SSE_MXCSR &EnableExceptions();
SSE_MXCSR &DisableExceptions();
SSE_RoundMode GetRoundMode() const;
SSE_MXCSR& SetRoundMode(SSE_RoundMode mode);
SSE_MXCSR& ClearExceptionFlags();
SSE_MXCSR& EnableExceptions();
SSE_MXCSR& DisableExceptions();
SSE_MXCSR &ApplyReserveMask();
SSE_MXCSR& ApplyReserveMask();
bool operator==(const SSE_MXCSR &right) const
{
return bitmask == right.bitmask;
}
bool operator==(const SSE_MXCSR& right) const
{
return bitmask == right.bitmask;
}
bool operator!=(const SSE_MXCSR &right) const
{
return bitmask != right.bitmask;
}
bool operator!=(const SSE_MXCSR& right) const
{
return bitmask != right.bitmask;
}
operator x86Emitter::xIndirect32() const;
operator x86Emitter::xIndirect32() const;
};
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::pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext, int flags)
: wxPanelWithHelpers(parent, wxVERTICAL)
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext, int flags)
: wxPanelWithHelpers(parent, wxVERTICAL)
{
Init(label, subtext, flags);
Init(label, subtext, flags);
}
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, int flags)
: wxPanelWithHelpers(parent, wxVERTICAL)
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, int flags)
: 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_subPadding = StdPadding * 2;
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
m_subtext = NULL;
m_subPadding = StdPadding * 2;
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;
if (!subtext.IsEmpty()) {
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
static const int Indentation = 23;
if (!subtext.IsEmpty())
{
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
wxFlexGridSizer &spaced(*new wxFlexGridSizer(3));
spaced.AddGrowableCol(1);
spaced += Indentation;
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
//spaced += pxSizerFlags::StdPadding;
wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
spaced.AddGrowableCol(1);
spaced += Indentation;
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
//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;
if (m_sizerItem_subtext) {
m_sizerItem_subtext->SetBorder(m_subPadding);
Fit();
}
return *this;
m_subPadding = pad;
if (m_sizerItem_subtext)
{
m_sizerItem_subtext->SetBorder(m_subPadding);
Fit();
}
return *this;
}
// 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).
pxCheckBox &pxCheckBox::SetToolTip(const wxString &tip)
pxCheckBox& pxCheckBox::SetToolTip(const wxString& tip)
{
pxSetToolTip(m_checkbox, tip);
pxSetToolTip(m_subtext, tip);
return *this;
pxSetToolTip(m_checkbox, tip);
pxSetToolTip(m_subtext, tip);
return *this;
}
pxCheckBox &pxCheckBox::SetValue(bool val)
pxCheckBox& pxCheckBox::SetValue(bool val)
{
pxAssert(m_checkbox);
m_checkbox->SetValue(val);
return *this;
pxAssert(m_checkbox);
m_checkbox->SetValue(val);
return *this;
}
pxCheckBox &pxCheckBox::SetIndeterminate()
pxCheckBox& pxCheckBox::SetIndeterminate()
{
pxAssert(m_checkbox);
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
return *this;
pxAssert(m_checkbox);
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
return *this;
}
pxCheckBox &pxCheckBox::SetState(wxCheckBoxState state)
pxCheckBox& pxCheckBox::SetState(wxCheckBoxState state)
{
pxAssert(m_checkbox);
m_checkbox->Set3StateValue(state);
return *this;
pxAssert(m_checkbox);
m_checkbox->Set3StateValue(state);
return *this;
}
// 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
// traditional checkbox.
void pxCheckBox::OnCheckpartCommand(wxCommandEvent &evt)
void pxCheckBox::OnCheckpartCommand(wxCommandEvent& evt)
{
evt.Skip();
evt.Skip();
wxCommandEvent newevt(evt);
newevt.SetEventObject(this);
newevt.SetId(GetId());
GetEventHandler()->ProcessEvent(newevt);
wxCommandEvent newevt(evt);
newevt.SetEventObject(this);
newevt.SetId(GetId());
GetEventHandler()->ProcessEvent(newevt);
}
void pxCheckBox::OnSubtextClicked(wxCommandEvent &evt)
void pxCheckBox::OnSubtextClicked(wxCommandEvent& evt)
{
// TODO?
// We can enable the ability to allow clicks on the subtext desc/label to toggle
// the checkmark. Not sure if that's desirable.
// TODO?
// We can enable the ability to allow clicks on the subtext desc/label to toggle
// the checkmark. Not sure if that's desirable.
}
void operator+=(wxSizer &target, pxCheckBox *src)
void operator+=(wxSizer& target, pxCheckBox* src)
{
if (src)
target.Add(src, pxExpand);
if (src)
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
{
protected:
wxCheckBox *m_checkbox;
pxStaticText *m_subtext;
wxCheckBox* m_checkbox;
pxStaticText* m_subtext;
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
int m_subPadding;
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
int m_subPadding;
wxSizerItem *m_sizerItem_subtext;
wxSizerItem* m_sizerItem_subtext;
public:
pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext = wxEmptyString, int flags = wxCHK_2STATE);
pxCheckBox(wxWindow *parent, const wxString &label, int flags);
virtual ~pxCheckBox() = default;
pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext = wxEmptyString, int flags = wxCHK_2STATE);
pxCheckBox(wxWindow* parent, const wxString& label, int flags);
virtual ~pxCheckBox() = default;
bool HasSubText() const { return m_subtext != NULL; }
const pxStaticText *GetSubText() const { return m_subtext; }
bool HasSubText() const { return m_subtext != NULL; }
const pxStaticText* GetSubText() const { return m_subtext; }
pxCheckBox &SetSubPadding(int pad);
pxCheckBox &SetToolTip(const wxString &tip);
pxCheckBox &SetValue(bool val);
pxCheckBox &SetIndeterminate();
pxCheckBox &SetState(wxCheckBoxState state);
pxCheckBox& SetSubPadding(int pad);
pxCheckBox& SetToolTip(const wxString& tip);
pxCheckBox& SetValue(bool val);
pxCheckBox& SetIndeterminate();
pxCheckBox& SetState(wxCheckBoxState state);
wxCheckBoxState GetState() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue();
}
bool GetValue() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->GetValue();
}
bool IsChecked() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->IsChecked();
}
bool IsIndeterminate() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
}
operator wxCheckBox &()
{
pxAssert(m_checkbox != NULL);
return *m_checkbox;
}
operator const wxCheckBox &() const
{
pxAssert(m_checkbox != NULL);
return *m_checkbox;
}
wxCheckBoxState GetState() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue();
}
bool GetValue() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->GetValue();
}
bool IsChecked() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->IsChecked();
}
bool IsIndeterminate() const
{
pxAssert(m_checkbox != NULL);
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
}
operator wxCheckBox&()
{
pxAssert(m_checkbox != NULL);
return *m_checkbox;
}
operator const wxCheckBox&() const
{
pxAssert(m_checkbox != NULL);
return *m_checkbox;
}
wxCheckBox *GetWxPtr() { return m_checkbox; }
const wxCheckBox *GetWxPtr() const { return m_checkbox; }
wxCheckBox* GetWxPtr() { 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:
void Init(const wxString &label, const wxString &subtext, int flags);
void OnCheckpartCommand(wxCommandEvent &evt);
void OnSubtextClicked(wxCommandEvent &evt);
void Init(const wxString& label, const wxString& subtext, int flags);
void OnCheckpartCommand(wxCommandEvent& evt);
void OnSubtextClicked(wxCommandEvent& evt);
};
extern void operator+=(wxSizer &target, pxCheckBox &src);
extern void operator+=(wxSizer& target, pxCheckBox& src);
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
{
DeclareNoncopyableObject(SynchronousActionState);
DeclareNoncopyableObject(SynchronousActionState);
protected:
bool m_posted;
Threading::Semaphore m_sema;
ScopedExcept m_exception;
bool m_posted;
Threading::Semaphore m_sema;
ScopedExcept m_exception;
public:
sptr return_value;
sptr return_value;
SynchronousActionState()
{
m_posted = false;
return_value = 0;
}
SynchronousActionState()
{
m_posted = false;
return_value = 0;
}
virtual ~SynchronousActionState() = default;
virtual ~SynchronousActionState() = default;
void SetException(const BaseException &ex);
void SetException(BaseException *ex);
void SetException(const BaseException& ex);
void SetException(BaseException* ex);
Threading::Semaphore &GetSemaphore() { return m_sema; }
const Threading::Semaphore &GetSemaphore() const { return m_sema; }
Threading::Semaphore& GetSemaphore() { return m_sema; }
const Threading::Semaphore& GetSemaphore() const { return m_sema; }
void RethrowException() const;
int WaitForResult();
int WaitForResult_NoExceptions();
void PostResult(int res);
void ClearResult();
void PostResult();
void RethrowException() const;
int WaitForResult();
int WaitForResult_NoExceptions();
void PostResult(int res);
void ClearResult();
void PostResult();
};
@ -73,21 +73,21 @@ public:
//
class pxSimpleEvent : public wxEvent
{
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
public:
explicit pxSimpleEvent(int evtid = 0)
: wxEvent(0, evtid)
{
}
explicit pxSimpleEvent(int evtid = 0)
: wxEvent(0, evtid)
{
}
pxSimpleEvent(wxWindowID winId, int evtid)
: wxEvent(winId, evtid)
{
}
pxSimpleEvent(wxWindowID winId, int evtid)
: wxEvent(winId, evtid)
{
}
pxSimpleEvent(const pxSimpleEvent&) = default;
virtual wxEvent *Clone() const { return new pxSimpleEvent(*this); }
pxSimpleEvent(const pxSimpleEvent&) = default;
virtual wxEvent* Clone() const { return new pxSimpleEvent(*this); }
};
// --------------------------------------------------------------------------------------
@ -99,41 +99,41 @@ wxDECLARE_EVENT(pxEvt_InvokeAction, pxActionEvent);
class pxActionEvent : public wxEvent
{
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
protected:
SynchronousActionState *m_state;
SynchronousActionState* m_state;
public:
virtual ~pxActionEvent() = default;
virtual pxActionEvent *Clone() const { return new pxActionEvent(*this); }
virtual ~pxActionEvent() = default;
virtual pxActionEvent* Clone() const { return new pxActionEvent(*this); }
explicit pxActionEvent(SynchronousActionState *sema = NULL, int msgtype = pxEvt_InvokeAction);
explicit pxActionEvent(SynchronousActionState &sema, int msgtype = pxEvt_InvokeAction);
pxActionEvent(const pxActionEvent &src);
explicit pxActionEvent(SynchronousActionState* sema = NULL, int msgtype = pxEvt_InvokeAction);
explicit pxActionEvent(SynchronousActionState& sema, int msgtype = pxEvt_InvokeAction);
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; }
SynchronousActionState *GetSyncState() { return m_state; }
const SynchronousActionState* GetSyncState() const { 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);
void SetException(const BaseException &ex);
virtual void SetException(BaseException* ex);
void SetException(const BaseException& ex);
virtual void _DoInvokeEvent();
virtual void _DoInvokeEvent();
protected:
// 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
// thread, and exceptions will be handled automatically.
//
// 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
// from this event, then the exception will be posted to the Main/UI thread instead.
virtual void InvokeEvent() {}
// 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
// thread, and exceptions will be handled automatically.
//
// 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
// from this event, then the exception will be posted to the Main/UI thread instead.
virtual void InvokeEvent() {}
};
@ -142,27 +142,27 @@ protected:
// --------------------------------------------------------------------------------------
class pxExceptionEvent : public pxActionEvent
{
typedef pxActionEvent _parent;
typedef pxActionEvent _parent;
protected:
BaseException *m_except;
BaseException* m_except;
public:
pxExceptionEvent(BaseException *ex = NULL)
{
m_except = ex;
}
pxExceptionEvent(BaseException* ex = NULL)
{
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:
void InvokeEvent();
void InvokeEvent();
};
// --------------------------------------------------------------------------------------
@ -171,29 +171,29 @@ protected:
class pxSynchronousCommandEvent : public wxCommandEvent
{
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
protected:
SynchronousActionState *m_sync;
wxEventType m_realEvent;
SynchronousActionState* m_sync;
wxEventType m_realEvent;
public:
virtual ~pxSynchronousCommandEvent() = default;
virtual pxSynchronousCommandEvent *Clone() const { return new pxSynchronousCommandEvent(*this); }
virtual ~pxSynchronousCommandEvent() = default;
virtual pxSynchronousCommandEvent* Clone() const { return new pxSynchronousCommandEvent(*this); }
pxSynchronousCommandEvent(SynchronousActionState *sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
pxSynchronousCommandEvent(SynchronousActionState &sema, 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, 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; }
wxEventType GetRealEventType() const { return m_realEvent; }
Threading::Semaphore* GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
wxEventType GetRealEventType() const { return m_realEvent; }
void SetException(BaseException *ex);
void SetException(const BaseException &ex);
void SetException(BaseException* ex);
void SetException(const BaseException& ex);
};
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
@ -203,23 +203,23 @@ wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
// --------------------------------------------------------------------------------------
class BaseMessageBoxEvent : public pxActionEvent
{
typedef pxActionEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
typedef pxActionEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
protected:
wxString m_Content;
wxString m_Content;
public:
virtual ~BaseMessageBoxEvent() = default;
virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); }
virtual ~BaseMessageBoxEvent() = default;
virtual BaseMessageBoxEvent* Clone() const { return new BaseMessageBoxEvent(*this); }
explicit BaseMessageBoxEvent(const wxString &content = wxEmptyString, SynchronousActionState *instdata = NULL);
BaseMessageBoxEvent(const wxString &content, SynchronousActionState &instdata);
BaseMessageBoxEvent(const BaseMessageBoxEvent &event);
explicit BaseMessageBoxEvent(const wxString& content = wxEmptyString, SynchronousActionState* instdata = NULL);
BaseMessageBoxEvent(const wxString& content, SynchronousActionState& instdata);
BaseMessageBoxEvent(const BaseMessageBoxEvent& event);
protected:
virtual void InvokeEvent();
virtual int _DoDialog() const;
virtual void InvokeEvent();
virtual int _DoDialog() const;
};
// --------------------------------------------------------------------------------------
@ -228,134 +228,134 @@ protected:
class MsgButtons
{
protected:
BITFIELD32()
bool
m_OK : 1,
m_Cancel : 1,
m_Yes : 1,
m_No : 1,
m_AllowToAll : 1,
m_Apply : 1,
m_Abort : 1,
m_Retry : 1,
m_Ignore : 1,
m_Reset : 1,
m_Close : 1;
BITFIELD_END
BITFIELD32()
bool
m_OK : 1,
m_Cancel : 1,
m_Yes : 1,
m_No : 1,
m_AllowToAll : 1,
m_Apply : 1,
m_Abort : 1,
m_Retry : 1,
m_Ignore : 1,
m_Reset : 1,
m_Close : 1;
BITFIELD_END
wxString m_CustomLabel;
wxString m_CustomLabelId;
wxString m_CustomLabel;
wxString m_CustomLabelId;
public:
MsgButtons() { bitset = 0; }
MsgButtons() { bitset = 0; }
MsgButtons &OK()
{
m_OK = true;
return *this;
}
MsgButtons &Cancel()
{
m_Cancel = true;
return *this;
}
MsgButtons &Apply()
{
m_Apply = true;
return *this;
}
MsgButtons &Yes()
{
m_Yes = true;
return *this;
}
MsgButtons &No()
{
m_No = true;
return *this;
}
MsgButtons &ToAll()
{
m_AllowToAll = true;
return *this;
}
MsgButtons& OK()
{
m_OK = true;
return *this;
}
MsgButtons& Cancel()
{
m_Cancel = true;
return *this;
}
MsgButtons& Apply()
{
m_Apply = true;
return *this;
}
MsgButtons& Yes()
{
m_Yes = true;
return *this;
}
MsgButtons& No()
{
m_No = true;
return *this;
}
MsgButtons& ToAll()
{
m_AllowToAll = true;
return *this;
}
MsgButtons &Abort()
{
m_Abort = true;
return *this;
}
MsgButtons &Retry()
{
m_Retry = true;
return *this;
}
MsgButtons &Ignore()
{
m_Ignore = true;
return *this;
}
MsgButtons &Reset()
{
m_Reset = true;
return *this;
}
MsgButtons &Close()
{
m_Close = true;
return *this;
}
MsgButtons& Abort()
{
m_Abort = true;
return *this;
}
MsgButtons& Retry()
{
m_Retry = true;
return *this;
}
MsgButtons& Ignore()
{
m_Ignore = true;
return *this;
}
MsgButtons& Reset()
{
m_Reset = true;
return *this;
}
MsgButtons& Close()
{
m_Close = true;
return *this;
}
// label - native language label displayed to user
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
MsgButtons &Custom(const wxString &label, const char *id)
{
m_CustomLabel = label;
m_CustomLabelId = fromUTF8(id);
return *this;
}
// label - native language label displayed to user
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
MsgButtons& Custom(const wxString& label, const char* id)
{
m_CustomLabel = label;
m_CustomLabelId = fromUTF8(id);
return *this;
}
MsgButtons &OKCancel()
{
m_OK = m_Cancel = true;
return *this;
}
MsgButtons &YesNo()
{
m_Yes = m_No = true;
return *this;
}
MsgButtons& OKCancel()
{
m_OK = m_Cancel = true;
return *this;
}
MsgButtons& YesNo()
{
m_Yes = m_No = true;
return *this;
}
bool HasOK() const { return m_OK; }
bool HasCancel() const { return m_Cancel; }
bool HasApply() const { return m_Apply; }
bool HasYes() const { return m_Yes; }
bool HasNo() const { return m_No; }
bool AllowsToAll() const { return m_AllowToAll; }
bool HasOK() const { return m_OK; }
bool HasCancel() const { return m_Cancel; }
bool HasApply() const { return m_Apply; }
bool HasYes() const { return m_Yes; }
bool HasNo() const { return m_No; }
bool AllowsToAll() const { return m_AllowToAll; }
bool HasAbort() const { return m_Abort; }
bool HasRetry() const { return m_Retry; }
bool HasIgnore() const { return m_Ignore; }
bool HasReset() const { return m_Reset; }
bool HasClose() const { return m_Close; }
bool HasAbort() const { return m_Abort; }
bool HasRetry() const { return m_Retry; }
bool HasIgnore() const { return m_Ignore; }
bool HasReset() const { return m_Reset; }
bool HasClose() const { return m_Close; }
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
const wxString &GetCustomLabel() const { return m_CustomLabel; }
const wxString &GetCustomLabelId() const { return m_CustomLabelId; }
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
const wxString& GetCustomLabel() const { return m_CustomLabel; }
const wxString& GetCustomLabelId() const { return m_CustomLabelId; }
bool Allows(wxWindowID id) const;
void SetBestFocus(wxWindow *dialog) const;
void SetBestFocus(wxWindow &dialog) const;
bool Allows(wxWindowID id) const;
void SetBestFocus(wxWindow* dialog) const;
void SetBestFocus(wxWindow& dialog) const;
bool operator==(const MsgButtons &right) const
{
return OpEqu(bitset);
}
bool operator==(const MsgButtons& right) const
{
return OpEqu(bitset);
}
bool operator!=(const MsgButtons &right) const
{
return !OpEqu(bitset);
}
bool operator!=(const MsgButtons& right) const
{
return !OpEqu(bitset);
}
};
// --------------------------------------------------------------------------------------
@ -378,24 +378,24 @@ public:
//
class pxMessageBoxEvent : public BaseMessageBoxEvent
{
typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
protected:
wxString m_Title;
MsgButtons m_Buttons;
wxString m_Title;
MsgButtons m_Buttons;
public:
virtual ~pxMessageBoxEvent() = default;
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
virtual ~pxMessageBoxEvent() = default;
virtual pxMessageBoxEvent* Clone() const { return new pxMessageBoxEvent(*this); }
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 = NULL);
pxMessageBoxEvent(const pxMessageBoxEvent &event) = default;
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 = NULL);
pxMessageBoxEvent(const pxMessageBoxEvent& event) = default;
protected:
int _DoDialog() const;
int _DoDialog() const;
};
// --------------------------------------------------------------------------------------
@ -403,22 +403,22 @@ protected:
// --------------------------------------------------------------------------------------
class pxAssertionEvent : public BaseMessageBoxEvent
{
typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
typedef BaseMessageBoxEvent _parent;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
protected:
wxString m_Stacktrace;
wxString m_Stacktrace;
public:
virtual ~pxAssertionEvent() = default;
virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); }
virtual ~pxAssertionEvent() = default;
virtual pxAssertionEvent* Clone() const { return new pxAssertionEvent(*this); }
pxAssertionEvent(const wxString &content = wxEmptyString, const wxString &trace = wxEmptyString, SynchronousActionState *instdata = NULL);
pxAssertionEvent(const wxString &content, const wxString &trace, SynchronousActionState &instdata);
pxAssertionEvent(const pxAssertionEvent &event) = default;
pxAssertionEvent(const wxString& content = wxEmptyString, const wxString& trace = wxEmptyString, SynchronousActionState* instdata = NULL);
pxAssertionEvent(const wxString& content, const wxString& trace, SynchronousActionState& instdata);
pxAssertionEvent(const pxAssertionEvent& event) = default;
pxAssertionEvent &SetStacktrace(const wxString &trace);
pxAssertionEvent& SetStacktrace(const wxString& trace);
protected:
int _DoDialog() const;
int _DoDialog() const;
};

View File

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

View File

@ -24,232 +24,239 @@ template class SafeArray<RadioPanelObjects>;
// ===========================================================================================
#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_IsRealized = false;
m_DefaultIdx = -1;
m_IsRealized = false;
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
m_Indentation = 23;
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
m_Indentation = 23;
for (int i = 0; i < arrsize; ++i)
Append(srcArray[i]);
for (int i = 0; i < arrsize; ++i)
Append(srcArray[i]);
}
pxRadioPanel &pxRadioPanel::Append(const RadioPanelItem &entry)
pxRadioPanel& pxRadioPanel::Append(const RadioPanelItem& entry)
{
m_buttonStrings.push_back(entry);
return *this;
m_buttonStrings.push_back(entry);
return *this;
}
void pxRadioPanel::Reset()
{
m_IsRealized = false;
const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0)
return;
m_IsRealized = false;
const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0)
return;
for (int i = 0; i < numbuttons; ++i) {
safe_delete(m_objects[i].LabelObj);
safe_delete(m_objects[i].SubTextObj);
}
m_buttonStrings.clear();
for (int i = 0; i < numbuttons; ++i)
{
safe_delete(m_objects[i].LabelObj);
safe_delete(m_objects[i].SubTextObj);
}
m_buttonStrings.clear();
}
void pxRadioPanel::Realize()
{
const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0)
return;
if (m_IsRealized)
return;
m_IsRealized = true;
const int numbuttons = m_buttonStrings.size();
if (numbuttons == 0)
return;
if (m_IsRealized)
return;
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
// objects. This ensures the radio buttons have consecutive tab order IDs, which
// 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
// linear tab order).
// 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
// 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
// linear tab order).
// 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);
for (int i = 1; i < numbuttons; ++i)
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
// 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);
for (int i = 1; i < numbuttons; ++i)
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
for (int i = 0; i < numbuttons; ++i) {
m_objects[i].SubTextObj = NULL;
if (m_buttonStrings[i].SubText.IsEmpty())
continue;
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
}
for (int i = 0; i < numbuttons; ++i)
{
m_objects[i].SubTextObj = NULL;
if (m_buttonStrings[i].SubText.IsEmpty())
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) {
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
for (int i = 0; i < numbuttons; ++i)
{
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
if (pxStaticText *subobj = m_objects[i].SubTextObj) {
*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 (pxStaticText* subobj = m_objects[i].SubTextObj)
{
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
*this += 9 + m_padding.GetHeight();
}
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)
woot->SetToolTip(tip);
if (wxRadioButton* woot = m_objects[idx].LabelObj)
woot->SetToolTip(tip);
if (pxStaticText *woot = m_objects[idx].SubTextObj)
woot->SetToolTip(tip);
if (pxStaticText* woot = m_objects[idx].SubTextObj)
woot->SetToolTip(tip);
}
// 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
// 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)
_setToolTipImmediate(idx, tip);
if (m_IsRealized)
_setToolTipImmediate(idx, tip);
return *this;
return *this;
}
pxRadioPanel &pxRadioPanel::SetSelection(int idx)
pxRadioPanel& pxRadioPanel::SetSelection(int idx)
{
if (!VerifyRealizedState())
return *this;
if (!VerifyRealizedState())
return *this;
pxAssert(m_objects[idx].LabelObj != NULL);
m_objects[idx].LabelObj->SetValue(true);
return *this;
pxAssert(m_objects[idx].LabelObj != NULL);
m_objects[idx].LabelObj->SetValue(true);
return *this;
}
void pxRadioPanel::_RealizeDefaultOption()
{
if (m_IsRealized && m_DefaultIdx != -1) {
wxFont def(GetFont());
def.SetWeight(wxFONTWEIGHT_BOLD);
//def.SetStyle( wxFONTSTYLE_ITALIC );
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
}
if (m_IsRealized && m_DefaultIdx != -1)
{
wxFont def(GetFont());
def.SetWeight(wxFONTWEIGHT_BOLD);
//def.SetStyle( wxFONTSTYLE_ITALIC );
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.
// Not intended for restoring default value at later time.
pxRadioPanel &pxRadioPanel::SetDefaultItem(int idx)
pxRadioPanel& pxRadioPanel::SetDefaultItem(int idx)
{
if (idx == m_DefaultIdx)
return *this;
if (idx == m_DefaultIdx)
return *this;
if (m_IsRealized && m_DefaultIdx != -1) {
wxFont def(GetFont());
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
}
if (m_IsRealized && m_DefaultIdx != -1)
{
wxFont def(GetFont());
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
}
m_DefaultIdx = idx;
_RealizeDefaultOption();
m_DefaultIdx = idx;
_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)
m_objects[idx].LabelObj->Enable(enable);
if (m_objects[idx].LabelObj)
m_objects[idx].LabelObj->Enable(enable);
if (m_objects[idx].SubTextObj)
m_objects[idx].SubTextObj->Enable(enable);
if (m_objects[idx].SubTextObj)
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
{
if (!VerifyRealizedState())
return 0;
if (!VerifyRealizedState())
return 0;
for (uint i = 0; i < m_buttonStrings.size(); ++i) {
if (wxRadioButton *woot = m_objects[i].LabelObj)
if (woot->GetValue())
return i;
}
for (uint i = 0; i < m_buttonStrings.size(); ++i)
{
if (wxRadioButton* woot = m_objects[i].LabelObj)
if (woot->GetValue())
return i;
}
// 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
// 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
// default, so that calling code has a "valid" return code in release builds.
// 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
// 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
// default, so that calling code has a "valid" return code in release builds.
pxFailDev("No valid selection was found in this group!");
return 0;
pxFailDev("No valid selection was found in this group!");
return 0;
}
// Returns the wxWindowID for the currently selected radio button.
wxWindowID pxRadioPanel::GetSelectionId() const
{
if (!VerifyRealizedState())
return 0;
return m_objects[GetSelection()].LabelObj->GetId();
if (!VerifyRealizedState())
return 0;
return m_objects[GetSelection()].LabelObj->GetId();
}
bool pxRadioPanel::IsSelected(int idx) const
{
if (!VerifyRealizedState())
return false;
pxAssert(m_objects[idx].LabelObj != NULL);
return m_objects[idx].LabelObj->GetValue();
if (!VerifyRealizedState())
return false;
pxAssert(m_objects[idx].LabelObj != NULL);
return m_objects[idx].LabelObj->GetValue();
}
pxStaticText *pxRadioPanel::GetSubText(int idx)
pxStaticText* pxRadioPanel::GetSubText(int idx)
{
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].SubTextObj;
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].SubTextObj;
}
const pxStaticText *pxRadioPanel::GetSubText(int idx) const
const pxStaticText* pxRadioPanel::GetSubText(int idx) const
{
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].SubTextObj;
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].SubTextObj;
}
wxRadioButton *pxRadioPanel::GetButton(int idx)
wxRadioButton* pxRadioPanel::GetButton(int idx)
{
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].LabelObj;
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].LabelObj;
}
const wxRadioButton *pxRadioPanel::GetButton(int idx) const
const wxRadioButton* pxRadioPanel::GetButton(int idx) const
{
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].LabelObj;
if (!VerifyRealizedState())
return NULL;
return m_objects[idx].LabelObj;
}

View File

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

View File

@ -20,33 +20,33 @@
// --------------------------------------------------------------------------------------
// pxStaticText (implementations)
// --------------------------------------------------------------------------------------
pxStaticText::pxStaticText(wxWindow *parent)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
pxStaticText::pxStaticText(wxWindow* parent)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
{
m_align = wxALIGN_CENTRE_HORIZONTAL;
m_autowrap = true;
m_wrappedWidth = -1;
m_heightInLines = 1;
m_align = wxALIGN_CENTRE_HORIZONTAL;
m_autowrap = true;
m_wrappedWidth = -1;
m_heightInLines = 1;
SetPaddingDefaults();
SetPaddingDefaults();
}
pxStaticText::pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
pxStaticText::pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align)
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
{
m_heightInLines = 1;
m_align = align;
m_heightInLines = 1;
m_align = align;
SetPaddingDefaults();
Init(label);
SetPaddingDefaults();
Init(label);
}
void pxStaticText::Init(const wxString &label)
void pxStaticText::Init(const wxString& label)
{
m_autowrap = true;
m_wrappedWidth = -1;
m_label = label;
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
m_autowrap = true;
m_wrappedWidth = -1;
m_label = label;
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
}
// 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)
void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags)
{
_parent::DoSetSize(x, y, w, h, sizeFlags);
Refresh();
_parent::DoSetSize(x, y, w, h, sizeFlags);
Refresh();
}
void pxStaticText::SetPaddingDefaults()
{
m_paddingPix_horiz = 7;
m_paddingPix_vert = 1;
m_paddingPix_horiz = 7;
m_paddingPix_vert = 1;
m_paddingPct_horiz = 0.0f;
m_paddingPct_vert = 0.0f;
m_paddingPct_horiz = 0.0f;
m_paddingPct_vert = 0.0f;
}
pxStaticText &pxStaticText::SetMinWidth(int width)
pxStaticText& pxStaticText::SetMinWidth(int width)
{
SetMinSize(wxSize(width, GetMinHeight()));
return *this;
SetMinSize(wxSize(width, GetMinHeight()));
return *this;
}
pxStaticText &pxStaticText::SetMinHeight(int height)
pxStaticText& pxStaticText::SetMinHeight(int height)
{
SetMinSize(wxSize(GetMinWidth(), height));
return *this;
SetMinSize(wxSize(GetMinWidth(), height));
return *this;
}
pxStaticText &pxStaticText::SetHeight(int lines)
pxStaticText& pxStaticText::SetHeight(int lines)
{
if (!pxAssert(lines > 0))
lines = 2;
m_heightInLines = lines;
if (!pxAssert(lines > 0))
lines = 2;
m_heightInLines = lines;
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
SetMinSize(wxSize(GetMinWidth(), newHeight));
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
SetMinSize(wxSize(GetMinWidth(), newHeight));
return *this;
return *this;
}
pxStaticText &pxStaticText::Align(wxAlignment align)
pxStaticText& pxStaticText::Align(wxAlignment align)
{
m_align = align;
return *this;
m_align = align;
return *this;
}
pxStaticText &pxStaticText::Bold()
pxStaticText& pxStaticText::Bold()
{
wxFont bold(GetFont());
bold.SetWeight(wxFONTWEIGHT_BOLD);
SetFont(bold);
return *this;
wxFont bold(GetFont());
bold.SetWeight(wxFONTWEIGHT_BOLD);
SetFont(bold);
return *this;
}
pxStaticText &pxStaticText::PaddingPixH(int pixels)
pxStaticText& pxStaticText::PaddingPixH(int pixels)
{
m_paddingPix_horiz = pixels;
UpdateWrapping(false);
Refresh();
return *this;
m_paddingPix_horiz = pixels;
UpdateWrapping(false);
Refresh();
return *this;
}
pxStaticText &pxStaticText::PaddingPixV(int pixels)
pxStaticText& pxStaticText::PaddingPixV(int pixels)
{
m_paddingPix_vert = pixels;
Refresh();
return *this;
m_paddingPix_vert = pixels;
Refresh();
return *this;
}
pxStaticText &pxStaticText::PaddingPctH(float pct)
pxStaticText& pxStaticText::PaddingPctH(float pct)
{
pxAssert(pct < 0.5);
pxAssert(pct < 0.5);
m_paddingPct_horiz = pct;
UpdateWrapping(false);
Refresh();
return *this;
m_paddingPct_horiz = pct;
UpdateWrapping(false);
Refresh();
return *this;
}
pxStaticText &pxStaticText::PaddingPctV(float pct)
pxStaticText& pxStaticText::PaddingPctV(float pct)
{
pxAssert(pct < 0.5);
pxAssert(pct < 0.5);
m_paddingPct_vert = pct;
Refresh();
return *this;
m_paddingPct_vert = pct;
Refresh();
return *this;
}
pxStaticText &pxStaticText::Unwrapped()
pxStaticText& pxStaticText::Unwrapped()
{
m_autowrap = false;
UpdateWrapping(false);
return *this;
m_autowrap = false;
UpdateWrapping(false);
return *this;
}
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
{
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
// valid Minimum sizes.
// Find an ideal(-ish) width, based on a search of all parent controls and their
// valid Minimum sizes.
int idealWidth = wxDefaultCoord;
int parentalAdjust = 0;
double parentalFactor = 1.0;
const wxWindow *millrun = this;
int idealWidth = wxDefaultCoord;
int parentalAdjust = 0;
double parentalFactor = 1.0;
const wxWindow* millrun = this;
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)
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
if (wxIsKindOf(millrun, wxWizard))
break;
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)
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
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))) {
idealWidth = min;
}
if (min > 0 && ((idealWidth < 0) || (min < idealWidth)))
{
idealWidth = min;
}
parentalAdjust += pxSizerFlags::StdPadding * 2;
millrun = millrun->GetParent();
}
parentalAdjust += pxSizerFlags::StdPadding * 2;
millrun = millrun->GetParent();
}
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.
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.
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))
return *this;
if ((width <= 1) || (width == m_wrappedWidth))
return *this;
wxString wrappedLabel;
m_wrappedWidth = width;
wxString wrappedLabel;
m_wrappedWidth = width;
if (width > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
if (width > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
if (m_wrappedLabel != wrappedLabel) {
m_wrappedLabel = wrappedLabel;
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
SetMinSize(wxSize(
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
}
return *this;
if (m_wrappedLabel != wrappedLabel)
{
m_wrappedLabel = wrappedLabel;
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
SetMinSize(wxSize(
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
}
return *this;
}
bool pxStaticText::_updateWrapping(bool textChanged)
{
if (!m_autowrap) {
//m_wrappedLabel = wxEmptyString;
//m_wrappedWidth = -1;
return false;
}
if (!m_autowrap)
{
//m_wrappedLabel = wxEmptyString;
//m_wrappedWidth = -1;
return false;
}
wxString wrappedLabel;
int newWidth = GetSize().GetWidth();
wxString wrappedLabel;
int newWidth = GetSize().GetWidth();
if (!textChanged && (newWidth == m_wrappedWidth))
return false;
if (!textChanged && (newWidth == m_wrappedWidth))
return false;
// 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
// and updates it if needed, in case the control's size isn't figured out prior
// to being painted).
// 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
// and updates it if needed, in case the control's size isn't figured out prior
// to being painted).
m_wrappedWidth = newWidth;
if (m_wrappedWidth > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
m_wrappedWidth = newWidth;
if (m_wrappedWidth > 1)
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
if (m_wrappedLabel == wrappedLabel)
return false;
m_wrappedLabel = wrappedLabel;
if (m_wrappedLabel == wrappedLabel)
return false;
m_wrappedLabel = wrappedLabel;
return true;
return true;
}
void pxStaticText::UpdateWrapping(bool textChanged)
{
if (_updateWrapping(textChanged))
Refresh();
if (_updateWrapping(textChanged))
Refresh();
}
void pxStaticText::SetLabel(const wxString &label)
void pxStaticText::SetLabel(const wxString& label)
{
const bool labelChanged(label != m_label);
if (labelChanged) {
m_label = label;
Refresh();
}
const bool labelChanged(label != m_label);
if (labelChanged)
{
m_label = label;
Refresh();
}
// Always update wrapping, in case window width or something else also changed.
UpdateWrapping(labelChanged);
InvalidateBestSize();
// Always update wrapping, in case window width or something else also changed.
UpdateWrapping(labelChanged);
InvalidateBestSize();
}
wxFont pxStaticText::GetFontOk() const
{
wxFont font(GetFont());
if (!font.Ok())
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
return font;
wxFont font(GetFont());
if (!font.Ok())
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
return font;
}
bool pxStaticText::Enable(bool enabled)
{
if (_parent::Enable(enabled)) {
Refresh();
return true;
}
return false;
if (_parent::Enable(enabled))
{
Refresh();
return true;
}
return false;
}
void pxStaticText::paintEvent(wxPaintEvent &evt)
void pxStaticText::paintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
const int dcWidth = dc.GetSize().GetWidth();
const int dcHeight = dc.GetSize().GetHeight();
if (dcWidth < 1)
return;
dc.SetFont(GetFontOk());
wxPaintDC dc(this);
const int dcWidth = dc.GetSize().GetWidth();
const int dcHeight = dc.GetSize().GetHeight();
if (dcWidth < 1)
return;
dc.SetFont(GetFontOk());
if (IsEnabled())
dc.SetTextForeground(GetForegroundColour());
else
dc.SetTextForeground(*wxLIGHT_GREY);
if (IsEnabled())
dc.SetTextForeground(GetForegroundColour());
else
dc.SetTextForeground(*wxLIGHT_GREY);
pxWindowTextWriter writer(dc);
writer.Align(m_align);
pxWindowTextWriter writer(dc);
writer.Align(m_align);
const wxString &label(m_autowrap ? m_wrappedLabel : m_label);
if (m_autowrap)
_updateWrapping(false);
const wxString& label(m_autowrap ? m_wrappedLabel : m_label);
if (m_autowrap)
_updateWrapping(false);
int tWidth, tHeight;
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
int tWidth, tHeight;
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
writer.Align(m_align);
if (m_align & wxALIGN_CENTER_VERTICAL)
writer.SetY((dcHeight - tHeight) / 2);
else
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
writer.Align(m_align);
if (m_align & wxALIGN_CENTER_VERTICAL)
writer.SetY((dcHeight - tHeight) / 2);
else
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.DrawRectangle(wxPoint(), dc.GetSize());
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
//dc.DrawRectangle(wxPoint(), dc.GetSize());
}
// Overloaded form wxPanel and friends.
wxSize pxStaticText::DoGetBestSize() const
{
wxClientDC dc(const_cast<pxStaticText *>(this));
dc.SetFont(GetFontOk());
wxClientDC dc(const_cast<pxStaticText*>(this));
dc.SetFont(GetFontOk());
wxSize best;
wxSize best;
if (m_autowrap) {
best = GetBestWrappedSize(dc);
//best.x = wxDefaultCoord;
} else {
// No autowrapping, so we can force a specific size here!
best = dc.GetMultiLineTextExtent(GetLabel());
best.x += calcPaddingWidth(best.x);
}
if (m_autowrap)
{
best = GetBestWrappedSize(dc);
//best.x = wxDefaultCoord;
}
else
{
// 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);
return best;
CacheBestSize(best);
return best;
}
// --------------------------------------------------------------------------------------
// pxStaticHeading (implementations)
// --------------------------------------------------------------------------------------
pxStaticHeading::pxStaticHeading(wxWindow *parent, const wxString &label)
: _parent(parent)
pxStaticHeading::pxStaticHeading(wxWindow* parent, const wxString& label)
: _parent(parent)
{
m_align = wxALIGN_CENTER;
m_align = wxALIGN_CENTER;
SetPaddingDefaults();
Init(label);
SetPaddingDefaults();
Init(label);
}
void pxStaticHeading::SetPaddingDefaults()
{
m_paddingPix_horiz = 4;
m_paddingPix_vert = 1;
m_paddingPix_horiz = 4;
m_paddingPix_vert = 1;
m_paddingPct_horiz = 0.08f;
m_paddingPct_vert = 0.0f;
m_paddingPct_horiz = 0.08f;
m_paddingPct_vert = 0.0f;
}
void operator+=(wxSizer &target, pxStaticText *src)
void operator+=(wxSizer& target, pxStaticText* src)
{
if (src)
target.Add(src, pxExpand);
if (src)
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
{
typedef wxControl _parent;
typedef wxControl _parent;
protected:
wxString m_label;
wxString m_wrappedLabel;
wxString m_label;
wxString m_wrappedLabel;
wxAlignment m_align;
bool m_autowrap;
int m_wrappedWidth;
int m_heightInLines;
wxAlignment m_align;
bool m_autowrap;
int m_wrappedWidth;
int m_heightInLines;
int m_paddingPix_horiz;
int m_paddingPix_vert;
float m_paddingPct_horiz;
float m_paddingPct_vert;
int m_paddingPix_horiz;
int m_paddingPix_vert;
float m_paddingPct_horiz;
float m_paddingPct_vert;
protected:
explicit pxStaticText(wxWindow *parent = NULL);
explicit pxStaticText(wxWindow* parent = NULL);
// wxWindow overloads!
bool AcceptsFocus() const { return false; }
bool HasTransparentBackground() { return true; }
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
// wxWindow overloads!
bool AcceptsFocus() const { return false; }
bool HasTransparentBackground() { return true; }
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
public:
pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
pxStaticText(wxWindow *parent, int heightInLines, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
virtual ~pxStaticText() = default;
pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
pxStaticText(wxWindow* parent, int heightInLines, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
virtual ~pxStaticText() = default;
wxFont GetFontOk() const;
bool Enable(bool enabled = true);
wxFont GetFontOk() const;
bool Enable(bool enabled = true);
virtual void SetLabel(const wxString &label);
virtual wxString GetLabel() const { return m_label; }
virtual void SetLabel(const wxString& label);
virtual wxString GetLabel() const { return m_label; }
pxStaticText &SetMinWidth(int width);
pxStaticText &SetMinHeight(int height);
pxStaticText& SetMinWidth(int width);
pxStaticText& SetMinHeight(int height);
pxStaticText &SetHeight(int lines);
pxStaticText &Align(wxAlignment align);
pxStaticText &Bold();
pxStaticText &WrapAt(int width);
pxStaticText& SetHeight(int lines);
pxStaticText& Align(wxAlignment align);
pxStaticText& Bold();
pxStaticText& WrapAt(int width);
pxStaticText &Unwrapped();
pxStaticText& Unwrapped();
pxStaticText &PaddingPixH(int pixels);
pxStaticText &PaddingPixV(int pixels);
pxStaticText& PaddingPixH(int pixels);
pxStaticText& PaddingPixV(int pixels);
pxStaticText &PaddingPctH(float pct);
pxStaticText &PaddingPctV(float pct);
//pxStaticText& DoBestGuessHeight();
pxStaticText& PaddingPctH(float pct);
pxStaticText& PaddingPctV(float pct);
//pxStaticText& DoBestGuessHeight();
protected:
void SetPaddingDefaults();
void Init(const wxString &label);
void SetPaddingDefaults();
void Init(const wxString& label);
wxSize GetBestWrappedSize(const wxClientDC &dc) const;
wxSize DoGetBestSize() const;
wxSize GetBestWrappedSize(const wxClientDC& dc) const;
wxSize DoGetBestSize() const;
int calcPaddingWidth(int newWidth) const;
int calcPaddingHeight(int newHeight) const;
int calcPaddingWidth(int newWidth) const;
int calcPaddingHeight(int newHeight) const;
void paintEvent(wxPaintEvent &evt);
void paintEvent(wxPaintEvent& evt);
void UpdateWrapping(bool textChanged);
bool _updateWrapping(bool textChanged);
void UpdateWrapping(bool textChanged);
bool _updateWrapping(bool textChanged);
};
class pxStaticHeading : public pxStaticText
{
typedef pxStaticText _parent;
typedef pxStaticText _parent;
public:
pxStaticHeading(wxWindow *parent = NULL, const wxString &label = wxEmptyString);
pxStaticHeading(wxWindow *parent, int heightInLines, const wxString &label = wxEmptyString);
virtual ~pxStaticHeading() = default;
pxStaticHeading(wxWindow* parent = NULL, const wxString& label = wxEmptyString);
pxStaticHeading(wxWindow* parent, int heightInLines, const wxString& label = wxEmptyString);
virtual ~pxStaticHeading() = default;
protected:
void SetPaddingDefaults();
void SetPaddingDefaults();
};
extern void operator+=(wxSizer &target, pxStaticText &src);
extern void operator+=(wxSizer& target, pxStaticText& src);
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::pxStreamBase(const wxString &filename)
: m_filename(filename)
pxStreamBase::pxStreamBase(const wxString& filename)
: m_filename(filename)
{
}
bool pxStreamBase::IsOk() const
{
wxStreamBase *woot = GetWxStreamBase();
return woot && woot->IsOk();
wxStreamBase* woot = GetWxStreamBase();
return woot && woot->IsOk();
}
wxFileOffset pxStreamBase::Length() const
{
if (!GetWxStreamBase())
return 0;
return GetWxStreamBase()->GetLength();
if (!GetWxStreamBase())
return 0;
return GetWxStreamBase()->GetLength();
}
// --------------------------------------------------------------------------------------
@ -47,115 +47,117 @@ wxFileOffset pxStreamBase::Length() const
// Interface for reading data from a gzip stream.
//
pxInputStream::pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input)
: pxStreamBase(filename)
, m_stream_in(std::move(input))
pxInputStream::pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input)
: pxStreamBase(filename)
, m_stream_in(std::move(input))
{
}
pxInputStream::pxInputStream(const wxString &filename, wxInputStream *input)
: pxStreamBase(filename)
, m_stream_in(input)
pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input)
: pxStreamBase(filename)
, 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
{
return m_stream_in->TellI();
return m_stream_in->TellI();
}
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_stream_in = std::move(stream);
m_filename = filename;
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_stream_in = std::unique_ptr<wxInputStream>(stream);
m_filename = filename;
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);
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR) {
int err = errno;
if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
m_stream_in->Read(dest, size);
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
{
int err = errno;
if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
ex->Rethrow();
}
ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
ex->Rethrow();
}
// 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
// end-of-stream conditions.
// 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
// end-of-stream conditions.
if ((size_t)m_stream_in->LastRead() < size)
throw Exception::EndOfStream(m_filename);
if ((size_t)m_stream_in->LastRead() < size)
throw Exception::EndOfStream(m_filename);
}
// --------------------------------------------------------------------------------------
// pxOutputStream
// --------------------------------------------------------------------------------------
pxOutputStream::pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output)
: pxStreamBase(filename)
, m_stream_out(std::move(output))
pxOutputStream::pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output)
: pxStreamBase(filename)
, m_stream_out(std::move(output))
{
}
pxOutputStream::pxOutputStream(const wxString &filename, wxOutputStream *output)
: pxStreamBase(filename)
, m_stream_out(output)
pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output)
: pxStreamBase(filename)
, 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
{
return m_stream_out->TellO();
return m_stream_out->TellO();
}
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_stream_out = std::move(stream);
m_filename = filename;
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_stream_out = std::unique_ptr<wxOutputStream>(stream);
m_filename = filename;
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);
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR) {
int err = errno;
if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
m_stream_out->Write(src, size);
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
{
int err = errno;
if (!err)
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
ex->Rethrow();
}
ScopedExcept ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
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.
bool pxReadLine(wxInputStream &input, std::string &dest)
bool pxReadLine(wxInputStream& input, std::string& dest)
{
dest.clear();
bool isUTF8 = false;
while (true) {
char c;
input.Read(&c, sizeof(c));
if (c == 0)
break;
if (input.Eof())
break;
if (c == '\n')
break; // eat on UNIX
if (c == '\r') {
input.Read(&c, sizeof(c));
if (c == 0)
break;
if (input.Eof())
break;
if (c == '\n')
break;
dest.clear();
bool isUTF8 = false;
while (true)
{
char c;
input.Read(&c, sizeof(c));
if (c == 0)
break;
if (input.Eof())
break;
if (c == '\n')
break; // eat on UNIX
if (c == '\r')
{
input.Read(&c, sizeof(c));
if (c == 0)
break;
if (input.Eof())
break;
if (c == '\n')
break;
input.Ungetch(c);
break;
}
dest += c;
if (c & 0x80)
isUTF8 = true;
}
input.Ungetch(c);
break;
}
dest += c;
if (c & 0x80)
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();
if (pxReadLine(input, intermed))
dest = fromUTF8(intermed.c_str());
else {
// Optimized ToAscii conversion.
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
const char *ascii = intermed.c_str();
while (*ascii != 0)
dest += (wchar_t)(unsigned char)*ascii++;
}
dest.clear();
if (pxReadLine(input, intermed))
dest = fromUTF8(intermed.c_str());
else
{
// Optimized ToAscii conversion.
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
const char* ascii = intermed.c_str();
while (*ascii != 0)
dest += (wchar_t)(unsigned char)*ascii++;
}
}
void pxReadLine(wxInputStream &input, wxString &dest)
void pxReadLine(wxInputStream& input, wxString& dest)
{
std::string line;
pxReadLine(input, dest, line);
std::string line;
pxReadLine(input, dest, line);
}
wxString pxReadLine(wxInputStream &input)
wxString pxReadLine(wxInputStream& input)
{
wxString result;
pxReadLine(input, result);
return result;
wxString result;
pxReadLine(input, 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()) {
pxToUTF8 utf8(text);
output.Write(utf8, utf8.Length());
}
pxWriteLine(output);
if (!text.IsEmpty())
{
pxToUTF8 utf8(text);
output.Write(utf8, utf8.Length());
}
pxWriteLine(output);
}
void pxWriteMultiline(wxOutputStream &output, const wxString &src)
void pxWriteMultiline(wxOutputStream& output, const wxString& src)
{
if (src.IsEmpty())
return;
if (src.IsEmpty())
return;
wxString result(src);
result.Replace(L"\r\n", L"\n");
result.Replace(L"\r", L"\n");
wxString result(src);
result.Replace(L"\r\n", L"\n");
result.Replace(L"\r", L"\n");
pxToUTF8 utf8(result);
output.Write(utf8, utf8.Length());
pxToUTF8 utf8(result);
output.Write(utf8, utf8.Length());
}

View File

@ -25,28 +25,28 @@
// --------------------------------------------------------------------------------------
class pxStreamBase
{
DeclareNoncopyableObject(pxStreamBase);
DeclareNoncopyableObject(pxStreamBase);
protected:
// 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
// passed to the exception handlers).
wxString m_filename;
// 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
// passed to the exception handlers).
wxString m_filename;
public:
pxStreamBase(const wxString &filename);
virtual ~pxStreamBase() = default;
pxStreamBase(const wxString& filename);
virtual ~pxStreamBase() = default;
// Implementing classes should return the base wxStream object (usually either a wxInputStream
// or wxOputStream derivative).
virtual wxStreamBase *GetWxStreamBase() const = 0;
virtual void Close() = 0;
virtual wxFileOffset Tell() const = 0;
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
// Implementing classes should return the base wxStream object (usually either a wxInputStream
// or wxOputStream derivative).
virtual wxStreamBase* GetWxStreamBase() const = 0;
virtual void Close() = 0;
virtual wxFileOffset Tell() const = 0;
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
virtual wxFileOffset Length() const;
bool IsOk() const;
wxString GetStreamName() const { return m_filename; }
virtual wxFileOffset Length() const;
bool IsOk() const;
wxString GetStreamName() const { return m_filename; }
};
@ -55,33 +55,33 @@ public:
// --------------------------------------------------------------------------------------
class pxOutputStream : public pxStreamBase
{
DeclareNoncopyableObject(pxOutputStream);
DeclareNoncopyableObject(pxOutputStream);
protected:
std::unique_ptr<wxOutputStream> m_stream_out;
std::unique_ptr<wxOutputStream> m_stream_out;
public:
pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output);
pxOutputStream(const wxString &filename, wxOutputStream *output);
pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output);
pxOutputStream(const wxString& filename, wxOutputStream* output);
virtual ~pxOutputStream() = default;
virtual void Write(const void *data, size_t size);
virtual ~pxOutputStream() = default;
virtual void Write(const void* data, size_t size);
void SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream);
void SetStream(const wxString &filename, wxOutputStream *stream);
void SetStream(const wxString& filename, std::unique_ptr<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>
void Write(const T &data)
{
Write(&data, sizeof(data));
}
template <typename T>
void Write(const T& data)
{
Write(&data, sizeof(data));
}
wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
};
// --------------------------------------------------------------------------------------
@ -89,31 +89,31 @@ public:
// --------------------------------------------------------------------------------------
class pxInputStream : public pxStreamBase
{
DeclareNoncopyableObject(pxInputStream);
DeclareNoncopyableObject(pxInputStream);
protected:
std::unique_ptr<wxInputStream> m_stream_in;
std::unique_ptr<wxInputStream> m_stream_in;
public:
pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input);
pxInputStream(const wxString &filename, wxInputStream *input);
pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input);
pxInputStream(const wxString& filename, wxInputStream* input);
virtual ~pxInputStream() = default;
virtual void Read(void *dest, size_t size);
virtual ~pxInputStream() = default;
virtual void Read(void* dest, size_t size);
void SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream);
void SetStream(const wxString &filename, wxInputStream *stream);
void SetStream(const wxString& filename, std::unique_ptr<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>
void Read(T &dest)
{
Read(&dest, sizeof(dest));
}
template <typename T>
void Read(T& dest)
{
Read(&dest, sizeof(dest));
}
wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
wxFileOffset Tell() const;
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
};

View File

@ -25,12 +25,12 @@ bool pxIsEnglish(int id)
// pxExpandMsg -- an Iconized Text Translator
// 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();
}
const wxChar *__fastcall pxGetTranslation(const wxChar *message)
const wxChar* __fastcall pxGetTranslation(const wxChar* message)
{
return wxGetTranslation(message).wc_str();
}

View File

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

View File

@ -27,21 +27,21 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxSimpleEvent, wxEvent);
ConsoleLogSource_App::ConsoleLogSource_App()
{
static const TraceLogDescriptor myDesc =
{
L"AppEvents", L"App Events",
pxLt("Includes idle event processing and some other uncommon event usages.")};
static const TraceLogDescriptor myDesc =
{
L"AppEvents", L"App Events",
pxLt("Includes idle event processing and some other uncommon event usages.")};
m_Descriptor = &myDesc;
m_Descriptor = &myDesc;
}
ConsoleLogSource_App pxConLog_App;
void BaseDeletableObject::DoDeletion()
{
wxAppWithHelpers *app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
pxAssert(app != NULL);
app->DeleteObject(*this);
wxAppWithHelpers* app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
pxAssert(app != NULL);
app->DeleteObject(*this);
}
@ -49,64 +49,67 @@ void BaseDeletableObject::DoDeletion()
// 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) {
m_exception = ScopedExcept(ex);
} else if (wxTheApp) {
// transport the exception to the main thread, since the message is fully
// 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.
if (!m_posted)
{
m_exception = ScopedExcept(ex);
}
else if (wxTheApp)
{
// transport the exception to the main thread, since the message is fully
// 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);
wxTheApp->AddPendingEvent(ev);
}
pxExceptionEvent ev(ex);
wxTheApp->AddPendingEvent(ev);
}
}
void SynchronousActionState::RethrowException() const
{
if (m_exception)
m_exception->Rethrow();
if (m_exception)
m_exception->Rethrow();
}
int SynchronousActionState::WaitForResult()
{
m_sema.WaitNoCancel();
RethrowException();
return return_value;
m_sema.WaitNoCancel();
RethrowException();
return return_value;
}
int SynchronousActionState::WaitForResult_NoExceptions()
{
m_sema.WaitNoCancel();
return return_value;
m_sema.WaitNoCancel();
return return_value;
}
void SynchronousActionState::PostResult(int res)
{
return_value = res;
PostResult();
return_value = res;
PostResult();
}
void SynchronousActionState::ClearResult()
{
m_posted = false;
m_exception = NULL;
m_posted = false;
m_exception = NULL;
}
void SynchronousActionState::PostResult()
{
if (m_posted)
return;
m_posted = true;
m_sema.Post();
if (m_posted)
return;
m_posted = true;
m_sema.Post();
}
// --------------------------------------------------------------------------------------
@ -115,40 +118,41 @@ void SynchronousActionState::PostResult()
wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent);
pxActionEvent::pxActionEvent(SynchronousActionState *sema, int msgtype)
: wxEvent(0, msgtype)
pxActionEvent::pxActionEvent(SynchronousActionState* sema, int msgtype)
: wxEvent(0, msgtype)
{
m_state = sema;
m_state = sema;
}
pxActionEvent::pxActionEvent(SynchronousActionState &sema, int msgtype)
: wxEvent(0, msgtype)
pxActionEvent::pxActionEvent(SynchronousActionState& sema, int msgtype)
: wxEvent(0, msgtype)
{
m_state = &sema;
m_state = &sema;
}
pxActionEvent::pxActionEvent(const pxActionEvent &src)
: wxEvent(src)
pxActionEvent::pxActionEvent(const pxActionEvent& 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()));
ex->DiagMsg() = prefix + ex->DiagMsg();
const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
ex->DiagMsg() = prefix + ex->DiagMsg();
if (!m_state) {
ScopedExcept exptr(ex); // auto-delete it after handling.
ex->Rethrow();
}
if (!m_state)
{
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);
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
{
m_sync = sema;
m_realEvent = commandType;
m_sync = sema;
m_realEvent = commandType;
}
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand)
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType, int winid)
: wxCommandEvent(pxEvt_SynchronousCommand)
{
m_sync = &sema;
m_realEvent = commandType;
m_sync = &sema;
m_realEvent = commandType;
}
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt)
: wxCommandEvent(evt)
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt)
: wxCommandEvent(evt)
{
m_sync = sema;
m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand);
m_sync = sema;
m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand);
}
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt)
: wxCommandEvent(evt)
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt)
: wxCommandEvent(evt)
{
m_sync = &sema;
m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand);
m_sync = &sema;
m_realEvent = evt.GetEventType();
SetEventType(pxEvt_SynchronousCommand);
}
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src)
: wxCommandEvent(src)
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src)
: wxCommandEvent(src)
{
m_sync = src.m_sync;
m_realEvent = src.m_realEvent;
m_sync = src.m_sync;
m_realEvent = src.m_realEvent;
}
void pxSynchronousCommandEvent::SetException(const BaseException &ex)
void pxSynchronousCommandEvent::SetException(const BaseException& ex)
{
if (!m_sync)
ex.Rethrow();
m_sync->SetException(ex);
if (!m_sync)
ex.Rethrow();
m_sync->SetException(ex);
}
void pxSynchronousCommandEvent::SetException(BaseException *ex)
void pxSynchronousCommandEvent::SetException(BaseException* ex)
{
if (!m_sync) {
ScopedExcept exptr(ex); // auto-delete it after handling.
ex->Rethrow();
}
if (!m_sync)
{
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
{
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
typedef pxActionEvent _parent;
typedef pxActionEvent _parent;
protected:
void (*m_Method)();
void (*m_Method)();
public:
virtual ~pxRpcEvent() = default;
virtual pxRpcEvent *Clone() const { return new pxRpcEvent(*this); }
virtual ~pxRpcEvent() = default;
virtual pxRpcEvent* Clone() const { return new pxRpcEvent(*this); }
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState *sema = NULL)
: pxActionEvent(sema)
{
m_Method = method;
}
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState* sema = NULL)
: pxActionEvent(sema)
{
m_Method = method;
}
explicit pxRpcEvent(void (*method)(), SynchronousActionState &sema)
: pxActionEvent(sema)
{
m_Method = method;
}
explicit pxRpcEvent(void (*method)(), SynchronousActionState& sema)
: pxActionEvent(sema)
{
m_Method = method;
}
pxRpcEvent(const pxRpcEvent &src)
: pxActionEvent(src)
{
m_Method = src.m_Method;
}
pxRpcEvent(const pxRpcEvent& src)
: pxActionEvent(src)
{
m_Method = src.m_Method;
}
void SetMethod(void (*method)())
{
m_Method = method;
}
void SetMethod(void (*method)())
{
m_Method = method;
}
protected:
void InvokeEvent()
{
if (m_Method)
m_Method();
}
void InvokeEvent()
{
if (m_Method)
m_Method();
}
};
wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
@ -266,16 +271,16 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
// --------------------------------------------------------------------------------------
// pxExceptionEvent implementations
// --------------------------------------------------------------------------------------
pxExceptionEvent::pxExceptionEvent(const BaseException &ex)
pxExceptionEvent::pxExceptionEvent(const BaseException& ex)
{
m_except = ex.Clone();
m_except = ex.Clone();
}
void pxExceptionEvent::InvokeEvent()
{
ScopedExcept deleteMe(m_except);
if (deleteMe)
deleteMe->Rethrow();
ScopedExcept deleteMe(m_except);
if (deleteMe)
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
// 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
// main thread.
void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
void wxAppWithHelpers::PostIdleMethod(FnType_Void* method)
{
pxRpcEvent evt(method);
AddIdleEvent(evt);
pxRpcEvent evt(method);
AddIdleEvent(evt);
}
// 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.
//
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void* method)
{
if (wxThread::IsMain())
return false;
if (wxThread::IsMain())
return false;
SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult();
SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult();
return true;
return true;
}
// 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!)
// TRUE if the method was posted.
//
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void *method)
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void* method)
{
if (wxThread::IsMain())
return false;
PostEvent(pxRpcEvent(method));
return true;
if (wxThread::IsMain())
return false;
PostEvent(pxRpcEvent(method));
return true;
}
void wxAppWithHelpers::ProcessMethod(FnType_Void *method)
void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
{
if (wxThread::IsMain()) {
method();
return;
}
if (wxThread::IsMain())
{
method();
return;
}
SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult();
SynchronousActionState sync;
PostEvent(pxRpcEvent(method, sync));
sync.WaitForResult();
}
void wxAppWithHelpers::PostEvent(const wxEvent &evt)
void wxAppWithHelpers::PostEvent(const wxEvent& evt)
{
// Const Cast is OK!
// Truth is, AddPendingEvent should be a const-qualified parameter, as
// 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
// here. -- air
// Const Cast is OK!
// Truth is, AddPendingEvent should be a const-qualified parameter, as
// 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
// 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
// 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
// be lost).
// 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
// struct, and posting the event would require a temporary clone, where changes would
// be lost).
AffinityAssert_AllowFrom_MainUI();
return _parent::ProcessEvent(evt);
AffinityAssert_AllowFrom_MainUI();
return _parent::ProcessEvent(evt);
}
bool wxAppWithHelpers::ProcessEvent(wxEvent *evt)
bool wxAppWithHelpers::ProcessEvent(wxEvent* evt)
{
AffinityAssert_AllowFrom_MainUI();
std::unique_ptr<wxEvent> deleteMe(evt);
return _parent::ProcessEvent(*deleteMe);
AffinityAssert_AllowFrom_MainUI();
std::unique_ptr<wxEvent> deleteMe(evt);
return _parent::ProcessEvent(*deleteMe);
}
bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt)
bool wxAppWithHelpers::ProcessEvent(pxActionEvent& evt)
{
if (wxThread::IsMain())
return _parent::ProcessEvent(evt);
else {
SynchronousActionState sync;
evt.SetSyncState(sync);
AddPendingEvent(evt);
sync.WaitForResult();
return true;
}
if (wxThread::IsMain())
return _parent::ProcessEvent(evt);
else
{
SynchronousActionState sync;
evt.SetSyncState(sync);
AddPendingEvent(evt);
sync.WaitForResult();
return true;
}
}
bool wxAppWithHelpers::ProcessEvent(pxActionEvent *evt)
bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
{
if (wxThread::IsMain()) {
std::unique_ptr<wxEvent> deleteMe(evt);
return _parent::ProcessEvent(*deleteMe);
} else {
SynchronousActionState sync;
evt->SetSyncState(sync);
AddPendingEvent(*evt);
sync.WaitForResult();
return true;
}
if (wxThread::IsMain())
{
std::unique_ptr<wxEvent> deleteMe(evt);
return _parent::ProcessEvent(*deleteMe);
}
else
{
SynchronousActionState sync;
evt->SetSyncState(sync);
AddPendingEvent(*evt);
sync.WaitForResult();
return true;
}
}
void wxAppWithHelpers::CleanUp()
{
// 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
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
// but I like to be tidy. -- air
// 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
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
// but I like to be tidy. -- air
//IdleEventDispatcher( "CleanUp" );
//DeletionDispatcher();
_parent::CleanUp();
//IdleEventDispatcher( "CleanUp" );
//DeletionDispatcher();
_parent::CleanUp();
}
// 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.
void pxActionEvent::_DoInvokeEvent()
{
AffinityAssert_AllowFrom_MainUI();
AffinityAssert_AllowFrom_MainUI();
try {
InvokeEvent();
} catch (BaseException &ex) {
SetException(ex);
} catch (std::runtime_error &ex) {
SetException(new Exception::RuntimeError(ex));
}
try
{
InvokeEvent();
}
catch (BaseException& ex)
{
SetException(ex);
}
catch (std::runtime_error& ex)
{
SetException(new Exception::RuntimeError(ex));
}
if (m_state)
m_state->PostResult();
if (m_state)
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...");
evt.SetEventType(evt.GetRealEventType());
pxAppLog.Write(L"(App) Executing command event synchronously...");
evt.SetEventType(evt.GetRealEventType());
try {
ProcessEvent(evt);
} catch (BaseException &ex) {
evt.SetException(ex);
} catch (std::runtime_error &ex) {
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
}
try
{
ProcessEvent(evt);
}
catch (BaseException& ex)
{
evt.SetException(ex);
}
catch (std::runtime_error& ex)
{
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
}
if (Semaphore *sema = evt.GetSemaphore())
sema->Post();
if (Semaphore* sema = evt.GetSemaphore())
sema->Post();
}
void wxAppWithHelpers::AddIdleEvent(const wxEvent &evt)
void wxAppWithHelpers::AddIdleEvent(const wxEvent& evt)
{
ScopedLock lock(m_IdleEventMutex);
if (m_IdleEventQueue.empty())
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
ScopedLock lock(m_IdleEventMutex);
if (m_IdleEventQueue.empty())
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);
if (!m_IdleEventQueue.empty())
m_IdleEventTimer.Start(100, true);
ScopedLock lock(m_IdleEventMutex);
if (!m_IdleEventQueue.empty())
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 shouldn't hurt anything anyway, since the node system re-creates the iterator
// on each pass)
// 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
// on each pass)
//static int __guard=0;
//RecursionGuard guard(__guard);
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
//static int __guard=0;
//RecursionGuard guard(__guard);
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
wxEventList postponed;
wxEventList::iterator node;
wxEventList postponed;
wxEventList::iterator node;
ScopedLock lock(m_IdleEventMutex);
ScopedLock lock(m_IdleEventMutex);
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end()) {
std::unique_ptr<wxEvent> deleteMe(*node);
m_IdleEventQueue.erase(node);
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end())
{
std::unique_ptr<wxEvent> deleteMe(*node);
m_IdleEventQueue.erase(node);
lock.Release();
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
// 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.
lock.Release();
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
// 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.");
postponed.push_back(deleteMe.release());
} else {
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
}
lock.Acquire();
}
pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
postponed.push_back(deleteMe.release());
}
else
{
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
}
lock.Acquire();
}
m_IdleEventQueue = postponed;
if (!m_IdleEventQueue.empty())
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
m_IdleEventQueue = postponed;
if (!m_IdleEventQueue.empty())
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();
IdleEventDispatcher();
m_IdleEventTimer.Stop();
IdleEventDispatcher();
}
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent &evt)
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent& evt)
{
IdleEventDispatcher(L"[Timeout]");
IdleEventDispatcher(L"[Timeout]");
}
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;
pxActionEvent evt(sync);
AddIdleEvent(evt);
sync.WaitForResult();
SynchronousActionState sync;
pxActionEvent evt(sync);
AddIdleEvent(evt);
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);
evt.SetClientData(clientData);
evt.SetInt(intParam);
evt.SetExtraLong(longParam);
evt.SetString(stringParam);
AddPendingEvent(evt);
wxCommandEvent evt(evtType);
evt.SetClientData(clientData);
evt.SetInt(intParam);
evt.SetExtraLong(longParam);
evt.SetString(stringParam);
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;
pxSynchronousCommandEvent evt(sync, evtType);
SynchronousActionState sync;
pxSynchronousCommandEvent evt(sync, evtType);
evt.SetClientData(clientData);
evt.SetInt(intParam);
evt.SetExtraLong(longParam);
evt.SetString(stringParam);
AddPendingEvent(evt);
sync.WaitForResult();
evt.SetClientData(clientData);
evt.SetInt(intParam);
evt.SetExtraLong(longParam);
evt.SetString(stringParam);
AddPendingEvent(evt);
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()) {
SynchronousActionState sync;
evt.SetSyncState(sync);
AddPendingEvent(evt);
sync.WaitForResult();
} else
evt._DoInvokeEvent();
if (!wxThread::IsMain())
{
SynchronousActionState sync;
evt.SetSyncState(sync);
AddPendingEvent(evt);
sync.WaitForResult();
}
else
evt._DoInvokeEvent();
}
void wxAppWithHelpers::DeleteObject(BaseDeletableObject &obj)
void wxAppWithHelpers::DeleteObject(BaseDeletableObject& obj)
{
pxAssert(!obj.IsBeingDeleted());
wxCommandEvent evt(pxEvt_DeleteObject);
evt.SetClientData((void *)&obj);
AddIdleEvent(evt);
pxAssert(!obj.IsBeingDeleted());
wxCommandEvent evt(pxEvt_DeleteObject);
evt.SetClientData((void*)&obj);
AddIdleEvent(evt);
}
void wxAppWithHelpers::DeleteThread(pxThread &obj)
void wxAppWithHelpers::DeleteThread(pxThread& obj)
{
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
wxCommandEvent evt(pxEvt_DeleteThread);
evt.SetClientData((void *)&obj);
AddIdleEvent(evt);
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
wxCommandEvent evt(pxEvt_DeleteThread);
evt.SetClientData((void*)&obj);
AddIdleEvent(evt);
}
bool wxAppWithHelpers::OnInit()
{
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, 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_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, 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)
return;
delete (BaseDeletableObject *)evt.GetClientData();
if (evt.GetClientData() == NULL)
return;
delete (BaseDeletableObject*)evt.GetClientData();
}
// 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)
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
// 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.
// (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());
if (!thr) {
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
return;
}
std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
if (!thr)
{
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());
thr->RethrowException();
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
thr->RethrowException();
}
wxAppWithHelpers::wxAppWithHelpers()
: m_IdleEventTimer(this)
: m_IdleEventTimer(this)
{
#ifdef __WXMSW__
// 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
// FS segment register won't have been initialized by the main exe, due to tls_insurance
// being optimized away >_< --air
// 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
// FS segment register won't have been initialized by the main exe, due to tls_insurance
// being optimized away >_< --air
static thread_local int tls_insurance = 0;
tls_insurance = 1;
static thread_local int tls_insurance = 0;
tls_insurance = 1;
#endif
}

View File

@ -32,10 +32,10 @@ class pxSynchronousCommandEvent;
class ConsoleLogSource_App : public ConsoleLogSource
{
typedef ConsoleLogSource _parent;
typedef ConsoleLogSource _parent;
public:
ConsoleLogSource_App();
ConsoleLogSource_App();
};
extern ConsoleLogSource_App pxConLog_App;
@ -49,97 +49,97 @@ extern ConsoleLogSource_App pxConLog_App;
class ModalButtonPanel : public wxPanelWithHelpers
{
public:
ModalButtonPanel(wxWindow *window, const MsgButtons &buttons);
virtual ~ModalButtonPanel() = default;
ModalButtonPanel(wxWindow* window, const MsgButtons& buttons);
virtual ~ModalButtonPanel() = default;
virtual void AddActionButton(wxWindowID id);
virtual void AddCustomButton(wxWindowID id, const wxString &label);
virtual void AddActionButton(wxWindowID id);
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
// --------------------------------------------------------------------------------------
class wxAppWithHelpers : public wxApp
{
typedef wxApp _parent;
typedef wxApp _parent;
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
protected:
wxEventList m_IdleEventQueue;
Threading::MutexRecursive m_IdleEventMutex;
wxTimer m_IdleEventTimer;
wxEventList m_IdleEventQueue;
Threading::MutexRecursive m_IdleEventMutex;
wxTimer m_IdleEventTimer;
public:
wxAppWithHelpers();
virtual ~wxAppWithHelpers() {}
wxAppWithHelpers();
virtual ~wxAppWithHelpers() {}
wxAppTraits *CreateTraits();
wxAppTraits* CreateTraits();
void CleanUp();
void CleanUp();
void DeleteObject(BaseDeletableObject &obj);
void DeleteObject(BaseDeletableObject *obj)
{
if (obj == NULL)
return;
DeleteObject(*obj);
}
void DeleteObject(BaseDeletableObject& obj);
void DeleteObject(BaseDeletableObject* obj)
{
if (obj == NULL)
return;
DeleteObject(*obj);
}
void DeleteThread(Threading::pxThread &obj);
void DeleteThread(Threading::pxThread *obj)
{
if (obj == NULL)
return;
DeleteThread(*obj);
}
void DeleteThread(Threading::pxThread& obj);
void DeleteThread(Threading::pxThread* obj)
{
if (obj == NULL)
return;
DeleteThread(*obj);
}
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 PostMethod(FnType_Void *method);
void PostIdleMethod(FnType_Void *method);
void ProcessMethod(FnType_Void *method);
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 PostMethod(FnType_Void* method);
void PostIdleMethod(FnType_Void* method);
void ProcessMethod(FnType_Void* method);
bool Rpc_TryInvoke(FnType_Void *method);
bool Rpc_TryInvokeAsync(FnType_Void *method);
bool Rpc_TryInvoke(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(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);
void ProcessAction(pxActionEvent &evt);
void PostAction(const pxActionEvent &evt);
void ProcessAction(pxActionEvent& evt);
void PostAction(const pxActionEvent& evt);
void Ping();
bool OnInit();
//int OnExit();
void Ping();
bool OnInit();
//int OnExit();
void AddIdleEvent(const wxEvent &evt);
void AddIdleEvent(const wxEvent& evt);
void PostEvent(const wxEvent &evt);
bool ProcessEvent(wxEvent &evt);
bool ProcessEvent(wxEvent *evt);
void PostEvent(const 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:
void IdleEventDispatcher(const wxChar *action = wxEmptyString);
void IdleEventDispatcher(const wxChar* action = wxEmptyString);
void OnIdleEvent(wxIdleEvent &evt);
void OnStartIdleEventTimer(wxCommandEvent &evt);
void OnIdleEventTimeout(wxTimerEvent &evt);
void OnDeleteObject(wxCommandEvent &evt);
void OnDeleteThread(wxCommandEvent &evt);
void OnSynchronousCommand(pxSynchronousCommandEvent &evt);
void OnInvokeAction(pxActionEvent &evt);
void OnIdleEvent(wxIdleEvent& evt);
void OnStartIdleEventTimer(wxCommandEvent& evt);
void OnIdleEventTimeout(wxTimerEvent& evt);
void OnDeleteObject(wxCommandEvent& evt);
void OnDeleteThread(wxCommandEvent& evt);
void OnSynchronousCommand(pxSynchronousCommandEvent& evt);
void OnInvokeAction(pxActionEvent& evt);
};
namespace Msgbox
{
extern int ShowModal(BaseMessageBoxEvent &evt);
extern int ShowModal(const wxString &title, const wxString &content, const MsgButtons &buttons);
}
extern int ShowModal(BaseMessageBoxEvent& evt);
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
// --------------------------------------------------------------------------------------
extern void pxExplore(const wxString &path);
extern void pxExplore(const char *path);
extern void pxExplore(const wxString& path);
extern void pxExplore(const char* path);
extern void pxLaunch(const wxString &path);
extern void pxLaunch(const char *path);
extern void pxLaunch(const wxString& path);
extern void pxLaunch(const char* path);
// --------------------------------------------------------------------------------------
// wxDoNotLogInThisScope
@ -44,28 +44,28 @@ extern void pxLaunch(const char *path);
//
class wxDoNotLogInThisScope
{
DeclareNoncopyableObject(wxDoNotLogInThisScope);
DeclareNoncopyableObject(wxDoNotLogInThisScope);
protected:
bool m_prev;
bool m_prev;
public:
wxDoNotLogInThisScope()
{
m_prev = wxLog::EnableLogging(false);
}
wxDoNotLogInThisScope()
{
m_prev = wxLog::EnableLogging(false);
}
virtual ~wxDoNotLogInThisScope()
{
wxLog::EnableLogging(m_prev);
}
virtual ~wxDoNotLogInThisScope()
{
wxLog::EnableLogging(m_prev);
}
};
extern wxString pxReadLine(wxInputStream &input);
extern void pxReadLine(wxInputStream &input, wxString &dest);
extern void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed);
extern bool pxReadLine(wxInputStream &input, std::string &dest);
extern void pxWriteLine(wxOutputStream &output);
extern void pxWriteLine(wxOutputStream &output, const wxString &text);
extern void pxWriteMultiline(wxOutputStream &output, const wxString &src);
extern wxString pxReadLine(wxInputStream& input);
extern void pxReadLine(wxInputStream& input, wxString& dest);
extern void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed);
extern bool pxReadLine(wxInputStream& input, std::string& dest);
extern void pxWriteLine(wxOutputStream& output);
extern void pxWriteLine(wxOutputStream& output, const wxString& text);
extern void pxWriteMultiline(wxOutputStream& output, const wxString& src);

View File

@ -22,171 +22,173 @@
#include <wx/display.h>
const pxAlignmentType
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
pxCenter = pxCentre,
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
pxCenter = pxCentre,
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
pxAlignLeft = {pxAlignmentType::Left},
pxAlignRight = {pxAlignmentType::Right},
pxAlignTop = {pxAlignmentType::Top},
pxAlignBottom = {pxAlignmentType::Bottom};
pxAlignLeft = {pxAlignmentType::Left},
pxAlignRight = {pxAlignmentType::Right},
pxAlignTop = {pxAlignmentType::Top},
pxAlignBottom = {pxAlignmentType::Bottom};
const pxStretchType
pxShrink = {pxStretchType::Shrink},
pxExpand = {pxStretchType::Expand},
pxShaped = {pxStretchType::Shaped},
pxReserveHidden = {pxStretchType::ReserveHidden},
pxFixedMinimum = {pxStretchType::FixedMinimum};
pxShrink = {pxStretchType::Shrink},
pxExpand = {pxStretchType::Expand},
pxShaped = {pxStretchType::Shaped},
pxReserveHidden = {pxStretchType::ReserveHidden},
pxFixedMinimum = {pxStretchType::FixedMinimum};
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
{
switch (intval) {
case Centre:
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
break;
switch (intval)
{
case Centre:
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
break;
case Middle:
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
break;
case Middle:
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
break;
case Left:
flags.Left();
break;
case Left:
flags.Left();
break;
case Right:
flags.Right();
break;
case Right:
flags.Right();
break;
case Top:
flags.Top();
break;
case Top:
flags.Top();
break;
case Bottom:
flags.Bottom();
break;
}
return flags;
case Bottom:
flags.Bottom();
break;
}
return flags;
}
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
{
switch (intval) {
case Shrink:
//pxFail( "wxSHRINK is an ignored stretch flag." );
break;
switch (intval)
{
case Shrink:
//pxFail( "wxSHRINK is an ignored stretch flag." );
break;
case Expand:
flags.Expand();
break;
case Expand:
flags.Expand();
break;
case Shaped:
flags.Shaped();
break;
case Shaped:
flags.Shaped();
break;
case ReserveHidden:
flags.ReserveSpaceEvenIfHidden();
break;
case ReserveHidden:
flags.ReserveSpaceEvenIfHidden();
break;
case FixedMinimum:
flags.FixedMinSize();
break;
case FixedMinimum:
flags.FixedMinSize();
break;
//case Tile:
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
//break;
}
return flags;
//case Tile:
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
//break;
}
return flags;
}
wxSizerFlags operator&(const wxSizerFlags &_flgs, const wxSizerFlags &_flgs2)
wxSizerFlags operator&(const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2)
{
//return align.Apply( _flgs );
wxSizerFlags retval;
//return align.Apply( _flgs );
wxSizerFlags retval;
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
retval.Align(allflags & wxALIGN_MASK);
if (allflags & wxEXPAND)
retval.Expand();
if (allflags & wxSHAPED)
retval.Shaped();
if (allflags & wxFIXED_MINSIZE)
retval.FixedMinSize();
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
retval.ReserveSpaceEvenIfHidden();
retval.Align(allflags & wxALIGN_MASK);
if (allflags & wxEXPAND)
retval.Expand();
if (allflags & wxSHAPED)
retval.Shaped();
if (allflags & wxFIXED_MINSIZE)
retval.FixedMinSize();
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
retval.ReserveSpaceEvenIfHidden();
// Compounding borders is probably a fair approach:
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
// Compounding borders is probably a fair approach:
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
// Compounding proportions works as well, I figure.
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
// Compounding proportions works as well, I figure.
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
return retval;
return retval;
}
// ----------------------------------------------------------------------------
// 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))
return;
target.GetSizer()->AddSpacer(spacer);
if (!pxAssert(target.GetSizer() != NULL))
return;
target.GetSizer()->AddSpacer(spacer);
}
void operator+=(wxWindow &target, const pxStretchSpacer &spacer)
void operator+=(wxWindow& target, const pxStretchSpacer& spacer)
{
if (!pxAssert(target.GetSizer() != NULL))
return;
target.GetSizer()->AddStretchSpacer(spacer.proportion);
if (!pxAssert(target.GetSizer() != NULL))
return;
target.GetSizer()->AddStretchSpacer(spacer.proportion);
}
// ----------------------------------------------------------------------------
// 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.
void operator+=(wxSizer *target, wxWindow &src)
void operator+=(wxSizer* target, wxWindow& src)
{
if (!pxAssert(target != NULL))
return;
target->Add(&src);
if (!pxAssert(target != NULL))
return;
target->Add(&src);
}
void operator+=(wxSizer *target, wxSizer &src)
void operator+=(wxSizer* target, wxSizer& src)
{
if (!pxAssert(target != NULL))
return;
target->Add(&src);
if (!pxAssert(target != NULL))
return;
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
// bar is most likely not easily grabble. Such a window should be moved to a valid or
// 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
// 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...
// 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
// 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++)
{
const auto rect = wxDisplay(i).GetGeometry();
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
{
const auto rect = wxDisplay(i).GetGeometry();
if (rect.Contains(wxRect(windowPos, sizeMatters)))
return true;
}
if (rect.Contains(wxRect(windowPos, sizeMatters)))
return true;
}
return false;
return false;
}
// 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).
wxRect wxGetDisplayArea()
{
return wxRect(wxPoint(), wxGetDisplaySize());
return wxRect(wxPoint(), wxGetDisplaySize());
}
// --------------------------------------------------------------------------------------
@ -234,17 +236,17 @@ wxRect wxGetDisplayArea()
//
wxSizerFlags pxSizerFlags::StdSpace()
{
return wxSizerFlags().Border(wxALL, StdPadding);
return wxSizerFlags().Border(wxALL, StdPadding);
}
wxSizerFlags pxSizerFlags::StdCenter()
{
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
}
wxSizerFlags pxSizerFlags::StdExpand()
{
return StdSpace().Expand();
return StdSpace().Expand();
}
// 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.
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
@ -261,9 +263,9 @@ wxSizerFlags pxSizerFlags::TopLevelBox()
// "tight").
wxSizerFlags pxSizerFlags::SubGroup()
{
// Groups look better with a slightly smaller margin than standard.
// (basically this accounts for the group's frame)
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
// Groups look better with a slightly smaller margin than standard.
// (basically this accounts for the group's frame)
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
}
// 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!
wxSizerFlags pxSizerFlags::StdButton()
{
return pxBorder().Align(wxALIGN_RIGHT);
return pxBorder().Align(wxALIGN_RIGHT);
}
wxSizerFlags pxSizerFlags::Checkbox()
{
return StdExpand();
return StdExpand();
}
void pxSizerFlags::SetBestPadding()
{
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
StdPadding = 4;
else
StdPadding = 1;
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
StdPadding = 4;
else
StdPadding = 1;
}
// --------------------------------------------------------------------------------------
@ -293,44 +295,44 @@ void pxSizerFlags::SetBestPadding()
static bool is_cjk_char(const uint ch)
{
/**
/**
* You can check these range at http://unicode.org/charts/
* 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.
*/
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
// characters are used today.
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
// characters are used today.
if (ch < 0x2e80)
return false; // shortcut for common non-CJK
if (ch < 0x2e80)
return false; // shortcut for common non-CJK
return
// Han Ideographs: all except Supplement
(ch >= 0x4e00 && ch < 0x9fcf) ||
(ch >= 0x3400 && ch < 0x4dbf) ||
(ch >= 0x20000 && ch < 0x2a6df) ||
(ch >= 0xf900 && ch < 0xfaff) ||
(ch >= 0x3190 && ch < 0x319f) ||
return
// Han Ideographs: all except Supplement
(ch >= 0x4e00 && ch < 0x9fcf) ||
(ch >= 0x3400 && ch < 0x4dbf) ||
(ch >= 0x20000 && ch < 0x2a6df) ||
(ch >= 0xf900 && ch < 0xfaff) ||
(ch >= 0x3190 && ch < 0x319f) ||
// Radicals: all except Ideographic Description
(ch >= 0x2e80 && ch < 0x2eff) ||
(ch >= 0x2f00 && ch < 0x2fdf) ||
(ch >= 0x31c0 && ch < 0x31ef) ||
// Radicals: all except Ideographic Description
(ch >= 0x2e80 && ch < 0x2eff) ||
(ch >= 0x2f00 && ch < 0x2fdf) ||
(ch >= 0x31c0 && ch < 0x31ef) ||
// Chinese-specific: Bopomofo
(ch >= 0x3000 && ch < 0x303f) ||
// Chinese-specific: Bopomofo
(ch >= 0x3000 && ch < 0x303f) ||
// Japanese-specific: Halfwidth Katakana
(ch >= 0xff00 && ch < 0xffef) ||
// Japanese-specific: Halfwidth Katakana
(ch >= 0xff00 && ch < 0xffef) ||
// Japanese-specific: Hiragana, Katakana
(ch >= 0x3040 && ch <= 0x309f) ||
(ch >= 0x30a0 && ch <= 0x30ff) ||
// Japanese-specific: Hiragana, Katakana
(ch >= 0x3040 && ch <= 0x309f) ||
(ch >= 0x30a0 && ch <= 0x30ff) ||
// Korean-specific: Hangul Syllables, Halfwidth Jamo
(ch >= 0xac00 && ch < 0xd7af) ||
(ch >= 0xff00 && ch < 0xffef);
// Korean-specific: Hangul Syllables, Halfwidth Jamo
(ch >= 0xac00 && ch < 0xd7af) ||
(ch >= 0xff00 && ch < 0xffef);
}
/*
@ -350,7 +352,7 @@ static bool is_cjk_char(const uint ch)
*/
static bool no_break_after(const uint ch)
{
// clang-format off
// clang-format off
switch (ch) {
/**
* don't break after these Japanese/Chinese characters
@ -366,14 +368,14 @@ static bool no_break_after(const uint ch)
return true;
}
// clang-format on
// clang-format on
return false;
return false;
}
static bool no_break_before(const uint ch)
{
// clang-format off
// clang-format off
switch (ch) {
/**
* don't break before these Japanese characters
@ -403,84 +405,94 @@ static bool no_break_before(const uint ch)
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())
return *this;
if (text.empty())
return *this;
bool wasWrapped = false;
bool wasWrapped = false;
wxString line;
line.reserve(text.length() + 12);
wxString line;
line.reserve(text.length() + 12);
wxString::const_iterator lastSpace = text.end();
wxString::const_iterator lineStart = text.begin();
for (wxString::const_iterator p = lineStart;; ++p) {
if (IsStartOfNewLine()) {
OnNewLine();
wxString::const_iterator lastSpace = text.end();
wxString::const_iterator lineStart = text.begin();
for (wxString::const_iterator p = lineStart;; ++p)
{
if (IsStartOfNewLine())
{
OnNewLine();
lastSpace = text.end();
lineStart = p;
lastSpace = text.end();
lineStart = p;
if (wasWrapped)
line = m_indent;
else
line.clear();
}
if (wasWrapped)
line = m_indent;
else
line.clear();
}
if (p == text.end() || *p == L'\n') {
wasWrapped = false;
DoOutputLine(line);
if (p == text.end() || *p == L'\n')
{
wasWrapped = false;
DoOutputLine(line);
if (p == text.end())
break;
} else { // not EOL
if (is_cjk_char(*p)) {
if (!no_break_before(*p)) {
if (p == lineStart || !no_break_after(*(p - 1)))
lastSpace = p;
}
} else if (*p == L' ' || *p == L',' || *p == L'/')
lastSpace = p;
if (p == text.end())
break;
}
else
{ // not EOL
if (is_cjk_char(*p))
{
if (!no_break_before(*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()) {
int width;
win.GetTextExtent(line, &width, NULL);
if (widthMax >= 0 && lastSpace != text.end())
{
int width;
win.GetTextExtent(line, &width, NULL);
if (width > widthMax) {
wasWrapped = true;
if (width > widthMax)
{
wasWrapped = true;
// remove the last word from this line
line.erase(lastSpace - lineStart, p + 1 - lineStart);
DoOutputLine(line);
// remove the last word from this line
line.erase(lastSpace - lineStart, p + 1 - lineStart);
DoOutputLine(line);
// go back to the last word of this line which we didn't
// output yet
p = lastSpace;
// go back to the last word of this line which we didn't
// output yet
p = lastSpace;
if (*p != L' ')
p--;
}
}
//else: no wrapping at all or impossible to wrap
}
}
if (*p != L' ')
p--;
}
}
//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);
m_linecount++;
m_eol = true;
OnOutputLine(line);
m_linecount++;
m_eol = true;
}
// this function is a destructive inspector: when it returns true it also
@ -488,34 +500,34 @@ void pxTextWrapperBase::DoOutputLine(const wxString &line)
// more
bool pxTextWrapperBase::IsStartOfNewLine()
{
if (!m_eol)
return false;
if (!m_eol)
return false;
m_eol = false;
return true;
m_eol = false;
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);
return *this;
_parent::Wrap(win, text, widthMax);
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)
_parent::Wrap(*win, text, widthMax);
return *this;
if (win)
_parent::Wrap(*win, text, widthMax);
return *this;
}
void pxTextWrapper::OnOutputLine(const wxString &line)
void pxTextWrapper::OnOutputLine(const wxString& line)
{
m_text += line;
m_text += line;
}
void pxTextWrapper::OnNewLine()
{
m_text += L'\n';
m_text += L'\n';
}
// --------------------------------------------------------------------------------------
@ -527,67 +539,69 @@ BusyCursorType ScopedBusyCursor::m_defBusyType;
ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype)
{
pxAssert(wxTheApp != NULL);
pxAssert(wxTheApp != NULL);
BusyCursorType curtype = Cursor_NotBusy;
if (!m_cursorStack.empty())
curtype = m_cursorStack.top();
BusyCursorType curtype = Cursor_NotBusy;
if (!m_cursorStack.empty())
curtype = m_cursorStack.top();
if (curtype < busytype)
SetManualBusyCursor(curtype = busytype);
if (curtype < busytype)
SetManualBusyCursor(curtype = busytype);
m_cursorStack.push(curtype);
m_cursorStack.push(curtype);
}
ScopedBusyCursor::~ScopedBusyCursor()
{
if (!pxAssert(wxTheApp != NULL))
return;
if (!pxAssert(wxTheApp != NULL))
return;
if (!pxAssert(!m_cursorStack.empty())) {
SetManualBusyCursor(m_defBusyType);
return;
}
if (!pxAssert(!m_cursorStack.empty()))
{
SetManualBusyCursor(m_defBusyType);
return;
}
BusyCursorType curtype = m_cursorStack.top();
m_cursorStack.pop();
BusyCursorType curtype = m_cursorStack.top();
m_cursorStack.pop();
if (m_cursorStack.empty())
SetManualBusyCursor(m_defBusyType);
else if (m_cursorStack.top() != curtype)
SetManualBusyCursor(m_cursorStack.top());
if (m_cursorStack.empty())
SetManualBusyCursor(m_defBusyType);
else if (m_cursorStack.top() != curtype)
SetManualBusyCursor(m_cursorStack.top());
}
void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
{
if (busytype == m_defBusyType)
return;
m_defBusyType = busytype;
if (busytype == m_defBusyType)
return;
m_defBusyType = busytype;
if (m_cursorStack.empty())
SetManualBusyCursor(busytype);
if (m_cursorStack.empty())
SetManualBusyCursor(busytype);
}
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
{
switch (busytype) {
case Cursor_NotBusy:
wxSetCursor(wxNullCursor);
break;
case Cursor_KindaBusy:
wxSetCursor(StockCursors.GetArrowWait());
break;
case Cursor_ReallyBusy:
wxSetCursor(*wxHOURGLASS_CURSOR);
break;
}
switch (busytype)
{
case Cursor_NotBusy:
wxSetCursor(wxNullCursor);
break;
case Cursor_KindaBusy:
wxSetCursor(StockCursors.GetArrowWait());
break;
case Cursor_ReallyBusy:
wxSetCursor(*wxHOURGLASS_CURSOR);
break;
}
}
const wxCursor &MoreStockCursors::GetArrowWait()
const wxCursor& MoreStockCursors::GetArrowWait()
{
if (!m_arrowWait)
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
return *m_arrowWait;
if (!m_arrowWait)
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
return *m_arrowWait;
}
MoreStockCursors StockCursors;
@ -599,39 +613,39 @@ MoreStockCursors StockCursors;
// extends the tooltip time to the maximum possible. GTK seems to have indefinite
// 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)
return; // Silently ignore nulls
wind->SetToolTip(src);
if (wind == NULL)
return; // Silently ignore nulls
wind->SetToolTip(src);
// Make tooltips show for as long as possible on Windows. Linux (GTK) can
// show tooltips indefinitely.
#ifdef __WXMSW__
wind->GetToolTip()->SetAutoPop(32767);
wind->GetToolTip()->SetAutoPop(32767);
#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)
{
return wxFont(
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
return wxFont(
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
#ifdef __WXMSW__
,
L"Lucida Console" // better than courier new (win32 only)
,
L"Lucida Console" // better than courier new (win32 only)
#endif
);
);
}
wxString pxGetAppName()
{
pxAssert(wxTheApp);
return wxTheApp->GetAppName();
pxAssert(wxTheApp);
return wxTheApp->GetAppName();
}

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