mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
f9bf87f50d
commit
13dfceff48
|
@ -39,7 +39,8 @@ void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t ali
|
||||||
|
|
||||||
void* newbuf = _aligned_malloc(new_size, align);
|
void* newbuf = _aligned_malloc(new_size, align);
|
||||||
|
|
||||||
if (newbuf != NULL && handle != NULL) {
|
if (newbuf != NULL && handle != NULL)
|
||||||
|
{
|
||||||
memcpy(newbuf, handle, std::min(old_size, new_size));
|
memcpy(newbuf, handle, std::min(old_size, new_size));
|
||||||
_aligned_free(handle);
|
_aligned_free(handle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,10 +159,13 @@ extern pxDoAssertFnType *pxDoAssert;
|
||||||
#define pxAssumeDev(cond, msg) (__assume(cond))
|
#define pxAssumeDev(cond, msg) (__assume(cond))
|
||||||
|
|
||||||
#define pxFail(msg) \
|
#define pxFail(msg) \
|
||||||
do { \
|
do \
|
||||||
|
{ \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define pxFailDev(msg) \
|
#define pxFailDev(msg) \
|
||||||
do { \
|
do \
|
||||||
|
{ \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -202,7 +205,8 @@ extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
|
||||||
//
|
//
|
||||||
#ifndef jNO_DEFAULT
|
#ifndef jNO_DEFAULT
|
||||||
#define jNO_DEFAULT \
|
#define jNO_DEFAULT \
|
||||||
default: { \
|
default: \
|
||||||
|
{ \
|
||||||
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@ void CheckedStaticBox::SetValue(bool val)
|
||||||
{
|
{
|
||||||
wxWindowList& list = GetChildren();
|
wxWindowList& list = GetChildren();
|
||||||
|
|
||||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||||
|
{
|
||||||
wxWindow* current = *iter;
|
wxWindow* current = *iter;
|
||||||
if (current != &ThisToggle)
|
if (current != &ThisToggle)
|
||||||
current->Enable(IsEnabled() && val);
|
current->Enable(IsEnabled() && val);
|
||||||
|
@ -66,7 +67,8 @@ bool CheckedStaticBox::Enable(bool enable)
|
||||||
bool val = enable && ThisToggle.GetValue();
|
bool val = enable && ThisToggle.GetValue();
|
||||||
wxWindowList& list = GetChildren();
|
wxWindowList& list = GetChildren();
|
||||||
|
|
||||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||||
|
{
|
||||||
wxWindow* current = *iter;
|
wxWindow* current = *iter;
|
||||||
if (current != &ThisToggle)
|
if (current != &ThisToggle)
|
||||||
current->Enable(val);
|
current->Enable(val);
|
||||||
|
|
|
@ -102,7 +102,8 @@ const IConsoleWriter ConsoleWriter_Null =
|
||||||
#if defined(__unix__)
|
#if defined(__unix__)
|
||||||
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
|
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
|
||||||
{
|
{
|
||||||
switch (color) {
|
switch (color)
|
||||||
|
{
|
||||||
case Color_Black:
|
case Color_Black:
|
||||||
case Color_StrongBlack:
|
case Color_StrongBlack:
|
||||||
return "\033[30m\033[1m";
|
return "\033[30m\033[1m";
|
||||||
|
@ -470,7 +471,8 @@ ConsoleColorScope::~ConsoleColorScope()
|
||||||
|
|
||||||
void ConsoleColorScope::EnterScope()
|
void ConsoleColorScope::EnterScope()
|
||||||
{
|
{
|
||||||
if (!m_IsScoped) {
|
if (!m_IsScoped)
|
||||||
|
{
|
||||||
m_old_color = Console.GetColor();
|
m_old_color = Console.GetColor();
|
||||||
Console.SetColor(m_newcolor);
|
Console.SetColor(m_newcolor);
|
||||||
m_IsScoped = true;
|
m_IsScoped = true;
|
||||||
|
@ -491,7 +493,8 @@ ConsoleIndentScope::ConsoleIndentScope(int tabs)
|
||||||
|
|
||||||
ConsoleIndentScope::~ConsoleIndentScope()
|
ConsoleIndentScope::~ConsoleIndentScope()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
LeaveScope();
|
LeaveScope();
|
||||||
}
|
}
|
||||||
DESTRUCTOR_CATCHALL
|
DESTRUCTOR_CATCHALL
|
||||||
|
@ -517,7 +520,8 @@ ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
|
||||||
|
|
||||||
ConsoleAttrScope::~ConsoleAttrScope()
|
ConsoleAttrScope::~ConsoleAttrScope()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Console.SetColor(m_old_color);
|
Console.SetColor(m_old_color);
|
||||||
Console.SetIndent(-m_tabsize);
|
Console.SetIndent(-m_tabsize);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "StringHelpers.h"
|
#include "common/StringHelpers.h"
|
||||||
|
|
||||||
enum ConsoleColors {
|
enum ConsoleColors
|
||||||
|
{
|
||||||
Color_Current = -1,
|
Color_Current = -1,
|
||||||
|
|
||||||
Color_Default = 0,
|
Color_Default = 0,
|
||||||
|
|
|
@ -45,11 +45,13 @@ u64 GetPhysicalMemory()
|
||||||
// doesn't change during the course of the program. Thread-safety is
|
// doesn't change during the course of the program. Thread-safety is
|
||||||
// ensured by atomic operations with full-barriers (usually compiled
|
// ensured by atomic operations with full-barriers (usually compiled
|
||||||
// down to XCHG on x86).
|
// down to XCHG on x86).
|
||||||
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0)
|
||||||
|
{
|
||||||
u64 getmem = 0;
|
u64 getmem = 0;
|
||||||
size_t len = sizeof(getmem);
|
size_t len = sizeof(getmem);
|
||||||
int mib[] = {CTL_HW, HW_MEMSIZE};
|
int mib[] = {CTL_HW, HW_MEMSIZE};
|
||||||
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) {
|
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0)
|
||||||
|
{
|
||||||
perror("sysctl:");
|
perror("sysctl:");
|
||||||
}
|
}
|
||||||
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
||||||
|
@ -76,14 +78,16 @@ u64 GetTickFrequency()
|
||||||
|
|
||||||
// by the time denom is not 0, the structure will have been fully
|
// by the time denom is not 0, the structure will have been fully
|
||||||
// updated and no more atomic accesses are necessary.
|
// updated and no more atomic accesses are necessary.
|
||||||
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0)
|
||||||
|
{
|
||||||
mach_timebase_info_data_t info;
|
mach_timebase_info_data_t info;
|
||||||
|
|
||||||
// mach_timebase_info() is a syscall, very slow, that's why we take
|
// mach_timebase_info() is a syscall, very slow, that's why we take
|
||||||
// pains to only do it once. On x86(-64), the result is guaranteed
|
// pains to only do it once. On x86(-64), the result is guaranteed
|
||||||
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
||||||
// which means GetCPUTicks is just nanoseconds).
|
// which means GetCPUTicks is just nanoseconds).
|
||||||
if (mach_timebase_info(&info) != KERN_SUCCESS) {
|
if (mach_timebase_info(&info) != KERN_SUCCESS)
|
||||||
|
{
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +113,15 @@ wxString GetOSVersionString()
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
|
|
||||||
// fetch the OS description only once (thread-safely)
|
// fetch the OS description only once (thread-safely)
|
||||||
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) {
|
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0)
|
||||||
|
{
|
||||||
char type[32] = {0};
|
char type[32] = {0};
|
||||||
char release[32] = {0};
|
char release[32] = {0};
|
||||||
char arch[32] = {0};
|
char arch[32] = {0};
|
||||||
|
|
||||||
#define SYSCTL_GET(var, base, name) \
|
#define SYSCTL_GET(var, base, name) \
|
||||||
do { \
|
do \
|
||||||
|
{ \
|
||||||
int mib[] = {base, name}; \
|
int mib[] = {base, name}; \
|
||||||
size_t len = sizeof(var); \
|
size_t len = sizeof(var); \
|
||||||
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
||||||
|
|
|
@ -45,8 +45,10 @@
|
||||||
|
|
||||||
static void MACH_CHECK(kern_return_t mach_retval)
|
static void MACH_CHECK(kern_return_t mach_retval)
|
||||||
{
|
{
|
||||||
switch (mach_retval) {
|
switch (mach_retval)
|
||||||
case KERN_SUCCESS: break;
|
{
|
||||||
|
case KERN_SUCCESS:
|
||||||
|
break;
|
||||||
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
|
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
|
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
|
||||||
// fallthrough
|
// fallthrough
|
||||||
|
@ -85,7 +87,8 @@ void Threading::Semaphore::Post()
|
||||||
|
|
||||||
void Threading::Semaphore::Post(int multiple)
|
void Threading::Semaphore::Post(int multiple)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < multiple; ++i) {
|
for (int i = 0; i < multiple; ++i)
|
||||||
|
{
|
||||||
MACH_CHECK(semaphore_signal(m_sema));
|
MACH_CHECK(semaphore_signal(m_sema));
|
||||||
}
|
}
|
||||||
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
||||||
|
@ -115,8 +118,10 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
mach_timespec_t ts;
|
mach_timespec_t ts;
|
||||||
kern_return_t kr = KERN_ABORTED;
|
kern_return_t kr = KERN_ABORTED;
|
||||||
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
||||||
kr == KERN_ABORTED; now = mach_absolute_time()) {
|
kr == KERN_ABORTED; now = mach_absolute_time())
|
||||||
if (now > deadline) {
|
{
|
||||||
|
if (now > deadline)
|
||||||
|
{
|
||||||
// timed out by definition
|
// timed out by definition
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +140,8 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
kr = semaphore_timedwait(m_sema, ts);
|
kr = semaphore_timedwait(m_sema, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kr == KERN_OPERATION_TIMED_OUT) {
|
if (kr == KERN_OPERATION_TIMED_OUT)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,13 +161,19 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
void Threading::Semaphore::Wait()
|
void Threading::Semaphore::Wait()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
WaitWithoutYield();
|
WaitWithoutYield();
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
WaitWithoutYield();
|
WaitWithoutYield();
|
||||||
} else {
|
}
|
||||||
while (!WaitWithoutYield(def_yieldgui_interval)) {
|
else
|
||||||
|
{
|
||||||
|
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||||
|
{
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,16 +194,22 @@ void Threading::Semaphore::Wait()
|
||||||
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
wxTimeSpan countdown((timeout));
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if (WaitWithoutYield(def_yieldgui_interval))
|
if (WaitWithoutYield(def_yieldgui_interval))
|
||||||
break;
|
break;
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
|
|
@ -70,7 +70,8 @@ static u64 getthreadtime(thread_port_t thread)
|
||||||
|
|
||||||
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
||||||
(thread_info_t)&info, &count);
|
(thread_info_t)&info, &count);
|
||||||
if (kr != KERN_SUCCESS) {
|
if (kr != KERN_SUCCESS)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +104,8 @@ u64 Threading::pxThread::GetCpuTime() const
|
||||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||||
// which typically would be an OS-provided scalar or some sort).
|
// which typically would be an OS-provided scalar or some sort).
|
||||||
if (!m_native_id) {
|
if (!m_native_id)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,17 +67,20 @@
|
||||||
src = (enumName)((int)src + 1); \
|
src = (enumName)((int)src + 1); \
|
||||||
return src; \
|
return src; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
static __fi enumName& operator--(enumName& src) \
|
static __fi enumName& operator--(enumName& src) \
|
||||||
{ \
|
{ \
|
||||||
src = (enumName)((int)src - 1); \
|
src = (enumName)((int)src - 1); \
|
||||||
return src; \
|
return src; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
static __fi enumName operator++(enumName& src, int) \
|
static __fi enumName operator++(enumName& src, int) \
|
||||||
{ \
|
{ \
|
||||||
enumName orig = src; \
|
enumName orig = src; \
|
||||||
src = (enumName)((int)src + 1); \
|
src = (enumName)((int)src + 1); \
|
||||||
return orig; \
|
return orig; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
static __fi enumName operator--(enumName& src, int) \
|
static __fi enumName operator--(enumName& src, int) \
|
||||||
{ \
|
{ \
|
||||||
enumName orig = src; \
|
enumName orig = src; \
|
||||||
|
@ -93,6 +96,7 @@
|
||||||
{ \
|
{ \
|
||||||
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
static __fi void EnumAssert(enumName id) \
|
static __fi void EnumAssert(enumName id) \
|
||||||
{ \
|
{ \
|
||||||
pxAssert(EnumIsValid(id)); \
|
pxAssert(EnumIsValid(id)); \
|
||||||
|
|
|
@ -52,7 +52,8 @@ protected:
|
||||||
//
|
//
|
||||||
void _loadImage()
|
void _loadImage()
|
||||||
{
|
{
|
||||||
if (!m_Image.Ok()) {
|
if (!m_Image.Ok())
|
||||||
|
{
|
||||||
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
||||||
m_Image.LoadFile(joe, ImageType::GetFormat());
|
m_Image.LoadFile(joe, ImageType::GetFormat());
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,11 @@ typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::
|
||||||
ScopedLock locker(m_listeners_lock);
|
ScopedLock locker(m_listeners_lock);
|
||||||
|
|
||||||
// Check for duplicates before adding the event.
|
// Check for duplicates before adding the event.
|
||||||
if (IsDebugBuild) {
|
if (IsDebugBuild)
|
||||||
|
{
|
||||||
ListenerIterator iter = m_listeners.begin();
|
ListenerIterator iter = m_listeners.begin();
|
||||||
while (iter != m_listeners.end()) {
|
while (iter != m_listeners.end())
|
||||||
|
{
|
||||||
if ((*iter) == &listener)
|
if ((*iter) == &listener)
|
||||||
return iter;
|
return iter;
|
||||||
++iter;
|
++iter;
|
||||||
|
@ -64,17 +66,27 @@ typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
||||||
{
|
{
|
||||||
while (iter != iend) {
|
while (iter != iend)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
(*iter)->DispatchEvent(evtparams);
|
(*iter)->DispatchEvent(evtparams);
|
||||||
} catch (Exception::RuntimeError &ex) {
|
}
|
||||||
if (IsDevBuild) {
|
catch (Exception::RuntimeError& ex)
|
||||||
|
{
|
||||||
|
if (IsDevBuild)
|
||||||
|
{
|
||||||
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||||
}
|
}
|
||||||
} catch (BaseException &ex) {
|
}
|
||||||
if (IsDevBuild) {
|
catch (BaseException& ex)
|
||||||
|
{
|
||||||
|
if (IsDevBuild)
|
||||||
|
{
|
||||||
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +99,8 @@ __fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const L
|
||||||
template <typename ListenerType>
|
template <typename ListenerType>
|
||||||
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
||||||
{
|
{
|
||||||
if (!m_cache_valid) {
|
if (!m_cache_valid)
|
||||||
|
{
|
||||||
m_cache_copy = m_listeners;
|
m_cache_copy = m_listeners;
|
||||||
m_cache_valid = true;
|
m_cache_valid = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,8 @@ DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin &origin, const wxString
|
||||||
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
||||||
|
|
||||||
RecursionGuard guard(s_assert_guard);
|
RecursionGuard guard(s_assert_guard);
|
||||||
if (guard.Counter > 2) {
|
if (guard.Counter > 2)
|
||||||
|
{
|
||||||
return pxTrap();
|
return pxTrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,14 +115,18 @@ DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin &origin, const wxString
|
||||||
|
|
||||||
bool trapit;
|
bool trapit;
|
||||||
|
|
||||||
if (pxDoAssert == NULL) {
|
if (pxDoAssert == NULL)
|
||||||
|
{
|
||||||
// Note: Format uses MSVC's syntax for output window hotlinking.
|
// Note: Format uses MSVC's syntax for output window hotlinking.
|
||||||
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
trapit = pxDoAssert(origin, msg.wc_str());
|
trapit = pxDoAssert(origin, msg.wc_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trapit) {
|
if (trapit)
|
||||||
|
{
|
||||||
pxTrap();
|
pxTrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,7 +394,8 @@ BaseException *Exception::FromErrno(const wxString &streamname, int errcode)
|
||||||
{
|
{
|
||||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||||
|
|
||||||
switch (errcode) {
|
switch (errcode)
|
||||||
|
{
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
pxFailDev(L"Invalid argument");
|
pxFailDev(L"Invalid argument");
|
||||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
||||||
|
|
|
@ -35,19 +35,25 @@ void pxTrap();
|
||||||
#define __DESTRUCTOR_CATCHALL(funcname) \
|
#define __DESTRUCTOR_CATCHALL(funcname) \
|
||||||
catch (BaseException & ex) \
|
catch (BaseException & ex) \
|
||||||
{ \
|
{ \
|
||||||
try { \
|
try \
|
||||||
|
{ \
|
||||||
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
||||||
Console.Error(ex.FormatDiagnosticMessage()); \
|
Console.Error(ex.FormatDiagnosticMessage()); \
|
||||||
} catch (...) { \
|
} \
|
||||||
|
catch (...) \
|
||||||
|
{ \
|
||||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
catch (std::exception & ex) \
|
catch (std::exception & ex) \
|
||||||
{ \
|
{ \
|
||||||
try { \
|
try \
|
||||||
|
{ \
|
||||||
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
||||||
Console.Error(ex.what()); \
|
Console.Error(ex.what()); \
|
||||||
} catch (...) { \
|
} \
|
||||||
|
catch (...) \
|
||||||
|
{ \
|
||||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -162,8 +168,16 @@ private: \
|
||||||
\
|
\
|
||||||
public: \
|
public: \
|
||||||
virtual ~classname() = default; \
|
virtual ~classname() = default; \
|
||||||
virtual void Rethrow() const { throw * this; } \
|
\
|
||||||
virtual classname *Clone() const { return new classname(*this); }
|
virtual void Rethrow() const \
|
||||||
|
{ \
|
||||||
|
throw *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
virtual classname* Clone() const \
|
||||||
|
{ \
|
||||||
|
return new classname(*this); \
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
||||||
public: \
|
public: \
|
||||||
|
@ -172,11 +186,13 @@ public: \
|
||||||
BaseException::SetBothMsgs(msg_diag); \
|
BaseException::SetBothMsgs(msg_diag); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
classname& SetDiagMsg(const wxString& msg_diag) \
|
classname& SetDiagMsg(const wxString& msg_diag) \
|
||||||
{ \
|
{ \
|
||||||
m_message_diag = msg_diag; \
|
m_message_diag = msg_diag; \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
classname& SetUserMsg(const wxString& msg_user) \
|
classname& SetUserMsg(const wxString& msg_user) \
|
||||||
{ \
|
{ \
|
||||||
m_message_user = msg_user; \
|
m_message_user = msg_user; \
|
||||||
|
@ -185,7 +201,10 @@ public: \
|
||||||
|
|
||||||
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
||||||
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||||
classname() { SetDiagMsg(message); } \
|
classname() \
|
||||||
|
{ \
|
||||||
|
SetDiagMsg(message); \
|
||||||
|
} \
|
||||||
DEFINE_EXCEPTION_MESSAGES(classname)
|
DEFINE_EXCEPTION_MESSAGES(classname)
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,6 +313,7 @@ public:
|
||||||
StreamName = name; \
|
StreamName = name; \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
virtual classname& SetStreamName(const char* name) \
|
virtual classname& SetStreamName(const char* name) \
|
||||||
{ \
|
{ \
|
||||||
StreamName = fromUTF8(name); \
|
StreamName = fromUTF8(name); \
|
||||||
|
@ -390,7 +410,7 @@ public:
|
||||||
virtual wxString FormatDiagnosticMessage() const;
|
virtual wxString FormatDiagnosticMessage() const;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace Exception
|
||||||
|
|
||||||
using Exception::BaseException;
|
using Exception::BaseException;
|
||||||
using Exception::ScopedExcept;
|
using Exception::ScopedExcept;
|
||||||
|
|
|
@ -33,15 +33,15 @@ template class SafeAlignedArray<u8, 16>;
|
||||||
// system deadlock.
|
// system deadlock.
|
||||||
static const int MaxFormattedStringLength = 0x80000;
|
static const int MaxFormattedStringLength = 0x80000;
|
||||||
|
|
||||||
static
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
__ri
|
static __ri void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||||
|
#else
|
||||||
|
static void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||||
#endif
|
#endif
|
||||||
void
|
|
||||||
format_that_ascii_mess(CharBufferType &buffer, uint writepos, const char *fmt, va_list argptr)
|
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
int size = buffer.GetLength();
|
int size = buffer.GetLength();
|
||||||
|
|
||||||
va_copy(args, argptr);
|
va_copy(args, argptr);
|
||||||
|
@ -74,15 +74,15 @@ static
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the length of the formatted string, in characters (wxChars).
|
// returns the length of the formatted string, in characters (wxChars).
|
||||||
static
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
__ri
|
static __ri uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||||
|
#else
|
||||||
|
static uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||||
#endif
|
#endif
|
||||||
uint
|
|
||||||
format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr)
|
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
int size = buffer.GetLength() / sizeof(wxChar);
|
int size = buffer.GetLength() / sizeof(wxChar);
|
||||||
|
|
||||||
va_copy(args, argptr);
|
va_copy(args, argptr);
|
||||||
|
|
|
@ -33,10 +33,8 @@
|
||||||
{
|
{
|
||||||
|
|
||||||
#define BITFIELD_END \
|
#define BITFIELD_END \
|
||||||
} \
|
}; \
|
||||||
; \
|
};
|
||||||
} \
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
@ -257,7 +255,7 @@ void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode &mode)
|
||||||
{
|
{
|
||||||
MemProtect(arr, size, mode);
|
MemProtect(arr, size, mode);
|
||||||
}
|
}
|
||||||
}
|
} // namespace HostSys
|
||||||
|
|
||||||
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
||||||
#define SafeSysMunmap(ptr, size) \
|
#define SafeSysMunmap(ptr, size) \
|
||||||
|
|
|
@ -29,7 +29,8 @@ void SetFullBaseDir(wxDirName appRoot)
|
||||||
static int _calcEnumLength(const wxChar* const* enumArray)
|
static int _calcEnumLength(const wxChar* const* enumArray)
|
||||||
{
|
{
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
while (*enumArray != NULL) {
|
while (*enumArray != NULL)
|
||||||
|
{
|
||||||
enumArray++;
|
enumArray++;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +120,8 @@ void IniLoader::Entry(const wxString &var, wxDirName &value, const wxDirName def
|
||||||
|
|
||||||
if (dest.IsEmpty())
|
if (dest.IsEmpty())
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
value = dest;
|
value = dest;
|
||||||
if (isAllowRelative)
|
if (isAllowRelative)
|
||||||
value = g_fullBaseDirName + value;
|
value = g_fullBaseDirName + value;
|
||||||
|
@ -203,7 +205,8 @@ void IniLoader::Entry(const wxString &var, double& value, const double defvalue)
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
void IniLoader::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
|
{
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +215,8 @@ void IniLoader::Entry(const wxString &var, wxPoint &value, const wxPoint defvalu
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
void IniLoader::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
|
{
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +225,8 @@ void IniLoader::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
|
||||||
|
|
||||||
void IniLoader::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
void IniLoader::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
||||||
{
|
{
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
|
{
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -233,14 +238,16 @@ void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const
|
||||||
// Confirm default value sanity...
|
// Confirm default value sanity...
|
||||||
|
|
||||||
const int cnt = _calcEnumLength(enumArray);
|
const int cnt = _calcEnumLength(enumArray);
|
||||||
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) {
|
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt))
|
||||||
|
{
|
||||||
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
||||||
defvalue = cnt - 1;
|
defvalue = cnt - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity confirmed, proceed with craziness!
|
// Sanity confirmed, proceed with craziness!
|
||||||
|
|
||||||
if (!m_Config) {
|
if (!m_Config)
|
||||||
|
{
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -252,11 +259,13 @@ void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const
|
||||||
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (enumArray[i] == NULL) {
|
if (enumArray[i] == NULL)
|
||||||
|
{
|
||||||
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
|
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]);
|
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
|
||||||
value = defvalue;
|
value = defvalue;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
value = i;
|
value = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +399,8 @@ void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *
|
||||||
|
|
||||||
// Confirm default value sanity...
|
// Confirm default value sanity...
|
||||||
|
|
||||||
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt)) {
|
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt))
|
||||||
|
{
|
||||||
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
||||||
defvalue = cnt - 1;
|
defvalue = cnt - 1;
|
||||||
}
|
}
|
||||||
|
@ -398,7 +408,8 @@ void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *
|
||||||
if (!m_Config)
|
if (!m_Config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (value >= cnt) {
|
if (value >= cnt)
|
||||||
|
{
|
||||||
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
||||||
Console.Indent().Warning(
|
Console.Indent().Warning(
|
||||||
L"Illegal Value: %d\n"
|
L"Illegal Value: %d\n"
|
||||||
|
|
|
@ -64,7 +64,8 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t *siginfo, void *)
|
||||||
if (Source_PageFault->WasHandled())
|
if (Source_PageFault->WasHandled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!wxThread::IsMain()) {
|
if (!wxThread::IsMain())
|
||||||
|
{
|
||||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +127,8 @@ static bool _memprotect(void *baseaddr, size_t size, const PageProtectionMode &m
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (errno) {
|
switch (errno)
|
||||||
|
{
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||||
|
@ -218,7 +220,8 @@ void HostSys::Munmap(uptr base, size_t size)
|
||||||
|
|
||||||
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
if (!_memprotect(baseaddr, size, mode)) {
|
if (!_memprotect(baseaddr, size, mode))
|
||||||
|
{
|
||||||
throw Exception::OutOfMemory(L"MemProtect")
|
throw Exception::OutOfMemory(L"MemProtect")
|
||||||
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||||
|
|
|
@ -71,11 +71,14 @@ u64 Threading::GetThreadTicksPerSecond()
|
||||||
static u64 get_thread_time(uptr id = 0)
|
static u64 get_thread_time(uptr id = 0)
|
||||||
{
|
{
|
||||||
clockid_t cid;
|
clockid_t cid;
|
||||||
if (id) {
|
if (id)
|
||||||
|
{
|
||||||
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
||||||
if (err)
|
if (err)
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cid = CLOCK_THREAD_CPUTIME_ID;
|
cid = CLOCK_THREAD_CPUTIME_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,15 +26,18 @@ __noinline void memset_sse_a(void *dest, const size_t size)
|
||||||
|
|
||||||
__m128 srcreg;
|
__m128 srcreg;
|
||||||
|
|
||||||
if (data != 0) {
|
if (data != 0)
|
||||||
|
{
|
||||||
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
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);
|
srcreg = _mm_loadh_pi(_mm_load_ps((float*)loadval), (__m64*)loadval);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
srcreg = _mm_setzero_ps();
|
srcreg = _mm_setzero_ps();
|
||||||
|
|
||||||
float(*destxmm)[4] = (float(*)[4])dest;
|
float(*destxmm)[4] = (float(*)[4])dest;
|
||||||
|
|
||||||
switch (MZFqwc & 0x07) {
|
switch (MZFqwc & 0x07)
|
||||||
|
{
|
||||||
case 0x07:
|
case 0x07:
|
||||||
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
||||||
// Fall through
|
// Fall through
|
||||||
|
@ -59,7 +62,8 @@ __noinline void memset_sse_a(void *dest, const size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
destxmm += (MZFqwc & 0x07);
|
destxmm += (MZFqwc & 0x07);
|
||||||
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8) {
|
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8)
|
||||||
|
{
|
||||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Threading
|
||||||
{
|
{
|
||||||
static std::atomic<int> _attr_refcount(0);
|
static std::atomic<int> _attr_refcount(0);
|
||||||
static pthread_mutexattr_t _attr_recursive;
|
static pthread_mutexattr_t _attr_recursive;
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Mutex Implementations
|
// Mutex Implementations
|
||||||
|
@ -57,14 +57,14 @@ static int xpthread_mutex_timedlock(
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
while ((err = pthread_mutex_trylock(mutex)) == EBUSY) {
|
while ((err = pthread_mutex_trylock(mutex)) == EBUSY)
|
||||||
|
{
|
||||||
// check if the timeout has expired, gettimeofday() is implemented
|
// check if the timeout has expired, gettimeofday() is implemented
|
||||||
// efficiently (in userspace) on OSX
|
// efficiently (in userspace) on OSX
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
if (now.tv_sec > abs_timeout->tv_sec
|
if (now.tv_sec > abs_timeout->tv_sec || (now.tv_sec == abs_timeout->tv_sec && (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec))
|
||||||
|| (now.tv_sec == abs_timeout->tv_sec
|
{
|
||||||
&& (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec)) {
|
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,8 @@ static int xpthread_mutex_timedlock(
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
ts.tv_sec = 0;
|
ts.tv_sec = 0;
|
||||||
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
||||||
while (nanosleep(&ts, &ts) == -1);
|
while (nanosleep(&ts, &ts) == -1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -91,7 +92,8 @@ void Threading::Mutex::Detach()
|
||||||
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsRecursive()) {
|
if (IsRecursive())
|
||||||
|
{
|
||||||
// Sanity check: Recursive locks could be held by our own thread, which would
|
// Sanity check: Recursive locks could be held by our own thread, which would
|
||||||
// be considered an assertion failure, but can also be handled gracefully.
|
// 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
|
// (note: if the mutex is locked recursively more than twice then this assert won't
|
||||||
|
@ -112,7 +114,8 @@ void Threading::Mutex::Detach()
|
||||||
|
|
||||||
Threading::Mutex::~Mutex()
|
Threading::Mutex::~Mutex()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Mutex::Detach();
|
Mutex::Detach();
|
||||||
}
|
}
|
||||||
DESTRUCTOR_CATCHALL;
|
DESTRUCTOR_CATCHALL;
|
||||||
|
@ -121,7 +124,8 @@ Threading::Mutex::~Mutex()
|
||||||
Threading::MutexRecursive::MutexRecursive()
|
Threading::MutexRecursive::MutexRecursive()
|
||||||
: Mutex(false)
|
: Mutex(false)
|
||||||
{
|
{
|
||||||
if (++_attr_refcount == 1) {
|
if (++_attr_refcount == 1)
|
||||||
|
{
|
||||||
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
||||||
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
||||||
|
|
||||||
|
@ -153,7 +157,8 @@ void Threading::Mutex::Recreate()
|
||||||
// unlocked.
|
// unlocked.
|
||||||
bool Threading::Mutex::RecreateIfLocked()
|
bool Threading::Mutex::RecreateIfLocked()
|
||||||
{
|
{
|
||||||
if (!Wait(def_detach_timeout)) {
|
if (!Wait(def_detach_timeout))
|
||||||
|
{
|
||||||
Recreate();
|
Recreate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -194,12 +199,17 @@ bool Threading::Mutex::TryAcquire()
|
||||||
void Threading::Mutex::Acquire()
|
void Threading::Mutex::Acquire()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
pthread_mutex_lock(&m_mutex);
|
pthread_mutex_lock(&m_mutex);
|
||||||
} else if (_WaitGui_RecursionGuard(L"Mutex::Acquire")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Mutex::Acquire"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
pthread_mutex_lock(&m_mutex);
|
pthread_mutex_lock(&m_mutex);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
while (!AcquireWithoutYield(def_yieldgui_interval))
|
while (!AcquireWithoutYield(def_yieldgui_interval))
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
@ -212,16 +222,22 @@ void Threading::Mutex::Acquire()
|
||||||
bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
|
bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
return AcquireWithoutYield(timeout);
|
return AcquireWithoutYield(timeout);
|
||||||
} else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
return AcquireWithoutYield(timeout);
|
return AcquireWithoutYield(timeout);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
wxTimeSpan countdown((timeout));
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if (AcquireWithoutYield(def_yieldgui_interval))
|
if (AcquireWithoutYield(def_yieldgui_interval))
|
||||||
break;
|
break;
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
@ -264,7 +280,8 @@ void Threading::Mutex::WaitWithoutYield()
|
||||||
//
|
//
|
||||||
bool Threading::Mutex::Wait(const wxTimeSpan& timeout)
|
bool Threading::Mutex::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
if (Acquire(timeout)) {
|
if (Acquire(timeout))
|
||||||
|
{
|
||||||
Release();
|
Release();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +290,8 @@ bool Threading::Mutex::Wait(const wxTimeSpan &timeout)
|
||||||
|
|
||||||
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
|
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
if (AcquireWithoutYield(timeout)) {
|
if (AcquireWithoutYield(timeout))
|
||||||
|
{
|
||||||
Release();
|
Release();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,8 @@ public:
|
||||||
// offsetLocation must be page-aligned
|
// offsetLocation must be page-aligned
|
||||||
void* Alloc(uptr offsetLocation, size_t size) const;
|
void* Alloc(uptr offsetLocation, size_t size) const;
|
||||||
|
|
||||||
void *AllocAtAddress(void *address, size_t size) const {
|
void* AllocAtAddress(void* address, size_t size) const
|
||||||
|
{
|
||||||
return Alloc(size, (uptr)address - m_baseptr);
|
return Alloc(size, (uptr)address - m_baseptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +177,7 @@ class VirtualMemoryBumpAllocator
|
||||||
const VirtualMemoryManagerPtr m_allocator;
|
const VirtualMemoryManagerPtr m_allocator;
|
||||||
std::atomic<uptr> m_baseptr{0};
|
std::atomic<uptr> m_baseptr{0};
|
||||||
const uptr m_endptr = 0;
|
const uptr m_endptr = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
||||||
void* Alloc(size_t size);
|
void* Alloc(size_t size);
|
||||||
|
|
|
@ -86,7 +86,8 @@ public:
|
||||||
|
|
||||||
wxFileName f(file);
|
wxFileName f(file);
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
if (this->SameAs(wxDirName(f.GetPath())))
|
if (this->SameAs(wxDirName(f.GetPath())))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -124,9 +125,12 @@ public:
|
||||||
wxString sv(subject.GetVolume());
|
wxString sv(subject.GetVolume());
|
||||||
sv.MakeUpper();
|
sv.MakeUpper();
|
||||||
|
|
||||||
if (base.IsContains(subject)) {
|
if (base.IsContains(subject))
|
||||||
|
{
|
||||||
subject.MakeRelativeTo(base.GetFullPath());
|
subject.MakeRelativeTo(base.GetFullPath());
|
||||||
} else if (base.HasVolume() && subject.HasVolume() && bv == sv) {
|
}
|
||||||
|
else if (base.HasVolume() && subject.HasVolume() && bv == sv)
|
||||||
|
{
|
||||||
wxString unusedVolume;
|
wxString unusedVolume;
|
||||||
wxString pathSansVolume;
|
wxString pathSansVolume;
|
||||||
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
||||||
|
@ -227,4 +231,4 @@ extern wxString GetFilename(const wxString &src);
|
||||||
extern wxString GetDirectory(const wxString& src);
|
extern wxString GetDirectory(const wxString& src);
|
||||||
extern wxString GetFilenameWithoutExt(const wxString& src);
|
extern wxString GetFilenameWithoutExt(const wxString& src);
|
||||||
extern wxString GetRootDirectory(const wxString& src);
|
extern wxString GetRootDirectory(const wxString& src);
|
||||||
}
|
} // namespace Path
|
||||||
|
|
|
@ -100,7 +100,8 @@ void InfoVector::map(uptr x86, u32 size, const char *symbol)
|
||||||
u32 max_code_size = _1gb;
|
u32 max_code_size = _1gb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (size < max_code_size) {
|
if (size < max_code_size)
|
||||||
|
{
|
||||||
m_v.emplace_back(x86, size, symbol);
|
m_v.emplace_back(x86, size, symbol);
|
||||||
|
|
||||||
#ifdef ENABLE_VTUNE
|
#ifdef ENABLE_VTUNE
|
||||||
|
@ -203,4 +204,4 @@ void dump() {}
|
||||||
void dump_and_reset() {}
|
void dump_and_reset() {}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace Perf
|
||||||
|
|
|
@ -59,4 +59,4 @@ extern InfoVector ee;
|
||||||
extern InfoVector iop;
|
extern InfoVector iop;
|
||||||
extern InfoVector vu;
|
extern InfoVector vu;
|
||||||
extern InfoVector vif;
|
extern InfoVector vif;
|
||||||
}
|
} // namespace Perf
|
||||||
|
|
|
@ -206,4 +206,4 @@ protected:
|
||||||
static void internal_callback_helper(void* func);
|
static void internal_callback_helper(void* func);
|
||||||
static void _pt_callback_cleanup(void* handle);
|
static void _pt_callback_cleanup(void* handle);
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -87,4 +87,4 @@ public:
|
||||||
protected:
|
protected:
|
||||||
ScopedWriteLock(RwMutex& locker, bool isTryLock);
|
ScopedWriteLock(RwMutex& locker, bool isTryLock);
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -42,7 +42,8 @@ T *SafeArray<T>::_virtual_realloc(int newsize)
|
||||||
malloc(newsize * sizeof(T)) :
|
malloc(newsize * sizeof(T)) :
|
||||||
realloc(m_ptr, newsize * sizeof(T)));
|
realloc(m_ptr, newsize * sizeof(T)));
|
||||||
|
|
||||||
if (IsDebugBuild && (retval != NULL)) {
|
if (IsDebugBuild && (retval != NULL))
|
||||||
|
{
|
||||||
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
||||||
// to a debuggee
|
// to a debuggee
|
||||||
|
|
||||||
|
@ -201,7 +202,8 @@ SafeList<T>::SafeList(int initialSize, const wxChar *name)
|
||||||
throw Exception::OutOfMemory(Name)
|
throw Exception::OutOfMemory(Name)
|
||||||
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
||||||
|
|
||||||
for (int i = 0; i < m_allocsize; ++i) {
|
for (int i = 0; i < m_allocsize; ++i)
|
||||||
|
{
|
||||||
new (&m_ptr[i]) T();
|
new (&m_ptr[i]) T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,14 +220,16 @@ T *SafeList<T>::_getPtr(uint i) const
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SafeList<T>::MakeRoomFor(int blockSize)
|
void SafeList<T>::MakeRoomFor(int blockSize)
|
||||||
{
|
{
|
||||||
if (blockSize > m_allocsize) {
|
if (blockSize > m_allocsize)
|
||||||
|
{
|
||||||
const int newalloc = blockSize + ChunkSize;
|
const int newalloc = blockSize + ChunkSize;
|
||||||
m_ptr = _virtual_realloc(newalloc);
|
m_ptr = _virtual_realloc(newalloc);
|
||||||
if (m_ptr == NULL)
|
if (m_ptr == NULL)
|
||||||
throw Exception::OutOfMemory(Name)
|
throw Exception::OutOfMemory(Name)
|
||||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
||||||
|
|
||||||
for (; m_allocsize < newalloc; ++m_allocsize) {
|
for (; m_allocsize < newalloc; ++m_allocsize)
|
||||||
|
{
|
||||||
new (&m_ptr[m_allocsize]) T();
|
new (&m_ptr[m_allocsize]) T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ void Threading::Semaphore::Post(int multiple)
|
||||||
sem_post_multiple(&m_sema, multiple);
|
sem_post_multiple(&m_sema, multiple);
|
||||||
#else
|
#else
|
||||||
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
||||||
while (multiple > 0) {
|
while (multiple > 0)
|
||||||
|
{
|
||||||
multiple--;
|
multiple--;
|
||||||
sem_post(&m_sema);
|
sem_post(&m_sema);
|
||||||
}
|
}
|
||||||
|
@ -80,12 +81,17 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||||
void Threading::Semaphore::Wait()
|
void Threading::Semaphore::Wait()
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
sem_wait(&m_sema);
|
sem_wait(&m_sema);
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
sem_wait(&m_sema);
|
sem_wait(&m_sema);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
while (!WaitWithoutYield(def_yieldgui_interval))
|
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
@ -107,16 +113,22 @@ void Threading::Semaphore::Wait()
|
||||||
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||||
|
{
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
}
|
||||||
|
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||||
|
{
|
||||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||||
return WaitWithoutYield(timeout);
|
return WaitWithoutYield(timeout);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||||
wxTimeSpan countdown((timeout));
|
wxTimeSpan countdown((timeout));
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
if (WaitWithoutYield(def_yieldgui_interval))
|
if (WaitWithoutYield(def_yieldgui_interval))
|
||||||
break;
|
break;
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
|
|
@ -94,7 +94,8 @@ void SplitString(wxArrayString &dest, const wxString &src, const wxString &delim
|
||||||
wxString JoinString(const wxArrayString& src, const wxString& separator)
|
wxString JoinString(const wxArrayString& src, const wxString& separator)
|
||||||
{
|
{
|
||||||
wxString dest;
|
wxString dest;
|
||||||
for (int i = 0, len = src.GetCount(); i < len; ++i) {
|
for (int i = 0, len = src.GetCount(); i < len; ++i)
|
||||||
|
{
|
||||||
if (src[i].IsEmpty())
|
if (src[i].IsEmpty())
|
||||||
continue;
|
continue;
|
||||||
if (!dest.IsEmpty())
|
if (!dest.IsEmpty())
|
||||||
|
@ -107,7 +108,8 @@ wxString JoinString(const wxArrayString &src, const wxString &separator)
|
||||||
wxString JoinString(const wxChar** src, const wxString& separator)
|
wxString JoinString(const wxChar** src, const wxString& separator)
|
||||||
{
|
{
|
||||||
wxString dest;
|
wxString dest;
|
||||||
while (*src != NULL) {
|
while (*src != NULL)
|
||||||
|
{
|
||||||
if (*src[0] == 0)
|
if (*src[0] == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -260,10 +262,14 @@ void px_fputs(FILE *fp, const char *src)
|
||||||
|
|
||||||
const char* curchar = src;
|
const char* curchar = src;
|
||||||
bool prevcr = false;
|
bool prevcr = false;
|
||||||
while (*curchar != 0) {
|
while (*curchar != 0)
|
||||||
if (*curchar == '\r') {
|
{
|
||||||
|
if (*curchar == '\r')
|
||||||
|
{
|
||||||
prevcr = true;
|
prevcr = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Only write a CR/LF pair if the current LF is not prefixed nor
|
// Only write a CR/LF pair if the current LF is not prefixed nor
|
||||||
// post-fixed by a CR.
|
// post-fixed by a CR.
|
||||||
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
||||||
|
|
|
@ -75,7 +75,8 @@ static void make_curthread_key(const pxThread *thr)
|
||||||
if (total_key_count++ != 0)
|
if (total_key_count++ != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (0 != pthread_key_create(&curthread_key, NULL)) {
|
if (0 != pthread_key_create(&curthread_key, NULL))
|
||||||
|
{
|
||||||
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
||||||
curthread_key = 0;
|
curthread_key = 0;
|
||||||
}
|
}
|
||||||
|
@ -114,9 +115,12 @@ pxThread *Threading::pxGetCurrentThread()
|
||||||
// nor the Main/UI thread.
|
// nor the Main/UI thread.
|
||||||
wxString Threading::pxGetCurrentThreadName()
|
wxString Threading::pxGetCurrentThreadName()
|
||||||
{
|
{
|
||||||
if (pxThread *thr = pxGetCurrentThread()) {
|
if (pxThread* thr = pxGetCurrentThread())
|
||||||
|
{
|
||||||
return thr->GetName();
|
return thr->GetName();
|
||||||
} else if (wxThread::IsMain()) {
|
}
|
||||||
|
else if (wxThread::IsMain())
|
||||||
|
{
|
||||||
return L"Main/UI";
|
return L"Main/UI";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +188,12 @@ Threading::pxThread::pxThread(const wxString &name)
|
||||||
// like marrying your sister, and then cheating on her with your daughter.
|
// like marrying your sister, and then cheating on her with your daughter.
|
||||||
Threading::pxThread::~pxThread()
|
Threading::pxThread::~pxThread()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
||||||
|
|
||||||
if (m_running) {
|
if (m_running)
|
||||||
|
{
|
||||||
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
||||||
m_mtx_InThread.Wait();
|
m_mtx_InThread.Wait();
|
||||||
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
||||||
|
@ -222,7 +228,8 @@ bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin
|
||||||
|
|
||||||
void Threading::pxThread::FrankenMutex(Mutex& mutex)
|
void Threading::pxThread::FrankenMutex(Mutex& mutex)
|
||||||
{
|
{
|
||||||
if (mutex.RecreateIfLocked()) {
|
if (mutex.RecreateIfLocked())
|
||||||
|
{
|
||||||
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
||||||
// Let's create a new mutex lock to replace it.
|
// Let's create a new mutex lock to replace it.
|
||||||
|
|
||||||
|
@ -240,7 +247,8 @@ void Threading::pxThread::Start()
|
||||||
{
|
{
|
||||||
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
||||||
ScopedLock startlock(m_mtx_start);
|
ScopedLock startlock(m_mtx_start);
|
||||||
if (m_running) {
|
if (m_running)
|
||||||
|
{
|
||||||
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -259,12 +267,14 @@ void Threading::pxThread::Start()
|
||||||
//
|
//
|
||||||
// In our case, the semaphore was posted (counter is 1) but thread is still
|
// In our case, the semaphore was posted (counter is 1) but thread is still
|
||||||
// waiting... So waits 100ms and checks the counter value manually
|
// waiting... So waits 100ms and checks the counter value manually
|
||||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100))) {
|
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100)))
|
||||||
|
{
|
||||||
if (m_sem_startup.Count() == 0)
|
if (m_sem_startup.Count() == 0)
|
||||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0))) {
|
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0)))
|
||||||
|
{
|
||||||
RethrowException();
|
RethrowException();
|
||||||
|
|
||||||
// And if the thread threw nothing of its own:
|
// And if the thread threw nothing of its own:
|
||||||
|
@ -305,7 +315,8 @@ bool Threading::pxThread::_basecancel()
|
||||||
if (!m_running)
|
if (!m_running)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_detached) {
|
if (m_detached)
|
||||||
|
{
|
||||||
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +349,8 @@ void Threading::pxThread::Cancel(bool isBlocking)
|
||||||
if (!_basecancel())
|
if (!_basecancel())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isBlocking) {
|
if (isBlocking)
|
||||||
|
{
|
||||||
WaitOnSelf(m_mtx_InThread);
|
WaitOnSelf(m_mtx_InThread);
|
||||||
Detach();
|
Detach();
|
||||||
}
|
}
|
||||||
|
@ -432,12 +444,14 @@ void Threading::YieldToMain()
|
||||||
|
|
||||||
void Threading::pxThread::_selfRunningTest(const wxChar* name) const
|
void Threading::pxThread::_selfRunningTest(const wxChar* name) const
|
||||||
{
|
{
|
||||||
if (HasPendingException()) {
|
if (HasPendingException())
|
||||||
|
{
|
||||||
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
||||||
RethrowException();
|
RethrowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_running) {
|
if (!m_running)
|
||||||
|
{
|
||||||
throw Exception::CancelEvent(pxsFmt(
|
throw Exception::CancelEvent(pxsFmt(
|
||||||
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
||||||
WX_STR(GetName()), name));
|
WX_STR(GetName()), name));
|
||||||
|
@ -467,7 +481,8 @@ void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||||
return;
|
return;
|
||||||
_selfRunningTest(L"semaphore");
|
_selfRunningTest(L"semaphore");
|
||||||
|
@ -492,7 +507,8 @@ void Threading::pxThread::WaitOnSelf(Mutex &mutex) const
|
||||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||||
return;
|
return;
|
||||||
_selfRunningTest(L"mutex");
|
_selfRunningTest(L"mutex");
|
||||||
|
@ -508,7 +524,8 @@ bool Threading::pxThread::WaitOnSelf(Semaphore &sem, const wxTimeSpan &timeout)
|
||||||
|
|
||||||
wxTimeSpan runningout(timeout);
|
wxTimeSpan runningout(timeout);
|
||||||
|
|
||||||
while (runningout.GetMilliseconds() > 0) {
|
while (runningout.GetMilliseconds() > 0)
|
||||||
|
{
|
||||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||||
if (sem.WaitWithoutYield(interval))
|
if (sem.WaitWithoutYield(interval))
|
||||||
return true;
|
return true;
|
||||||
|
@ -525,7 +542,8 @@ bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) co
|
||||||
|
|
||||||
wxTimeSpan runningout(timeout);
|
wxTimeSpan runningout(timeout);
|
||||||
|
|
||||||
while (runningout.GetMilliseconds() > 0) {
|
while (runningout.GetMilliseconds() > 0)
|
||||||
|
{
|
||||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||||
if (mutex.WaitWithoutYield(interval))
|
if (mutex.WaitWithoutYield(interval))
|
||||||
return true;
|
return true;
|
||||||
|
@ -548,19 +566,22 @@ void Threading::pxThread::TestCancel() const
|
||||||
// Executes the virtual member method
|
// Executes the virtual member method
|
||||||
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
(this->*method)();
|
(this->*method)();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Neat repackaging for STL Runtime errors...
|
// Neat repackaging for STL Runtime errors...
|
||||||
//
|
//
|
||||||
catch (std::runtime_error &ex) {
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch (Exception::RuntimeError &ex) {
|
catch (Exception::RuntimeError& ex)
|
||||||
|
{
|
||||||
BaseException* woot = ex.Clone();
|
BaseException* woot = ex.Clone();
|
||||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||||
m_except = woot;
|
m_except = woot;
|
||||||
|
@ -585,7 +606,8 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// BaseException -- same deal as LogicErrors.
|
// BaseException -- same deal as LogicErrors.
|
||||||
//
|
//
|
||||||
catch (BaseException &ex) {
|
catch (BaseException& ex)
|
||||||
|
{
|
||||||
BaseException* woot = ex.Clone();
|
BaseException* woot = ex.Clone();
|
||||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||||
m_except = woot;
|
m_except = woot;
|
||||||
|
|
|
@ -100,7 +100,7 @@ extern u64 GetThreadTicksPerSecond();
|
||||||
// Yields the current thread and provides cancellation points if the thread is managed by
|
// Yields the current thread and provides cancellation points if the thread is managed by
|
||||||
// pxThread. Unmanaged threads use standard Sleep.
|
// pxThread. Unmanaged threads use standard Sleep.
|
||||||
extern void pxYield(int ms);
|
extern void pxYield(int ms);
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
@ -155,7 +155,7 @@ public:
|
||||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Exception
|
||||||
|
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
|
@ -422,4 +422,4 @@ struct ScopedLockBool
|
||||||
m_lock.Release();
|
m_lock.Release();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -49,4 +49,4 @@ protected:
|
||||||
void OnTaskComplete(wxCommandEvent& evt);
|
void OnTaskComplete(wxCommandEvent& evt);
|
||||||
//void OnTimer( wxTimerEvent& evt );
|
//void OnTimer( wxTimerEvent& evt );
|
||||||
};
|
};
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -27,4 +27,4 @@ extern bool _WaitGui_RecursionGuard(const wxChar *name);
|
||||||
|
|
||||||
extern void YieldToMain();
|
extern void YieldToMain();
|
||||||
extern bool AllowDeletions();
|
extern bool AllowDeletions();
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
|
@ -27,7 +27,8 @@ Threading::Mutex PageFault_Mutex;
|
||||||
|
|
||||||
void pxInstallSignalHandler()
|
void pxInstallSignalHandler()
|
||||||
{
|
{
|
||||||
if (!Source_PageFault) {
|
if (!Source_PageFault)
|
||||||
|
{
|
||||||
Source_PageFault = new SrcType_PageFault();
|
Source_PageFault = new SrcType_PageFault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +60,8 @@ void SrcType_PageFault::Dispatch(const PageFaultInfo ¶ms)
|
||||||
|
|
||||||
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt)
|
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt)
|
||||||
{
|
{
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
(*iter)->DispatchEvent(evt, m_handled);
|
(*iter)->DispatchEvent(evt, m_handled);
|
||||||
} while ((++iter != iend) && !m_handled);
|
} while ((++iter != iend) && !m_handled);
|
||||||
}
|
}
|
||||||
|
@ -74,22 +76,28 @@ static size_t pageAlign(size_t size)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
VirtualMemoryManager::VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
VirtualMemoryManager::VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
||||||
: m_name(name), m_baseptr(0), m_pageuse(nullptr), m_pages_reserved(0)
|
: m_name(name)
|
||||||
|
, m_baseptr(0)
|
||||||
|
, m_pageuse(nullptr)
|
||||||
|
, m_pages_reserved(0)
|
||||||
{
|
{
|
||||||
if (!size) return;
|
if (!size)
|
||||||
|
return;
|
||||||
|
|
||||||
uptr reserved_bytes = pageAlign(size);
|
uptr reserved_bytes = pageAlign(size);
|
||||||
m_pages_reserved = reserved_bytes / __pagesize;
|
m_pages_reserved = reserved_bytes / __pagesize;
|
||||||
|
|
||||||
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
||||||
|
|
||||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) {
|
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||||
|
{
|
||||||
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
||||||
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
||||||
|
|
||||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||||
|
|
||||||
if (base) {
|
if (base)
|
||||||
|
{
|
||||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||||
// boundschecking criteria below.
|
// boundschecking criteria below.
|
||||||
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
||||||
|
@ -101,11 +109,13 @@ VirtualMemoryManager::VirtualMemoryManager(const wxString &name, uptr base, size
|
||||||
fulfillsRequirements = false;
|
fulfillsRequirements = false;
|
||||||
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
||||||
fulfillsRequirements = false;
|
fulfillsRequirements = false;
|
||||||
if (!fulfillsRequirements) {
|
if (!fulfillsRequirements)
|
||||||
|
{
|
||||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_baseptr) return;
|
if (!m_baseptr)
|
||||||
|
return;
|
||||||
|
|
||||||
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
||||||
|
|
||||||
|
@ -122,17 +132,24 @@ VirtualMemoryManager::VirtualMemoryManager(const wxString &name, uptr base, size
|
||||||
|
|
||||||
VirtualMemoryManager::~VirtualMemoryManager()
|
VirtualMemoryManager::~VirtualMemoryManager()
|
||||||
{
|
{
|
||||||
if (m_pageuse) delete[] m_pageuse;
|
if (m_pageuse)
|
||||||
if (m_baseptr) HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
delete[] m_pageuse;
|
||||||
|
if (m_baseptr)
|
||||||
|
HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VMMMarkPagesAsInUse(std::atomic<bool> *begin, std::atomic<bool> *end) {
|
static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
|
||||||
for (auto current = begin; current < end; current++) {
|
{
|
||||||
|
for (auto current = begin; current < end; current++)
|
||||||
|
{
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed) {
|
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed)
|
||||||
|
{
|
||||||
// This was already allocated! Undo the things we've set until this point
|
// This was already allocated! Undo the things we've set until this point
|
||||||
while (--current >= begin) {
|
while (--current >= begin)
|
||||||
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
{
|
||||||
|
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
|
// 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
|
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
||||||
pxAssert(0);
|
pxAssert(0);
|
||||||
|
@ -164,7 +181,8 @@ void *VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
||||||
void VirtualMemoryManager::Free(void* address, size_t size) const
|
void VirtualMemoryManager::Free(void* address, size_t size) const
|
||||||
{
|
{
|
||||||
uptr offsetLocation = (uptr)address - m_baseptr;
|
uptr offsetLocation = (uptr)address - m_baseptr;
|
||||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address")) {
|
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address"))
|
||||||
|
{
|
||||||
uptr newLoc = pageAlign(offsetLocation);
|
uptr newLoc = pageAlign(offsetLocation);
|
||||||
size -= (offsetLocation - newLoc);
|
size -= (offsetLocation - newLoc);
|
||||||
offsetLocation = newLoc;
|
offsetLocation = newLoc;
|
||||||
|
@ -175,9 +193,11 @@ void VirtualMemoryManager::Free(void *address, size_t size) const
|
||||||
return;
|
return;
|
||||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||||
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||||
for (; puStart < puEnd; puStart++) {
|
for (; puStart < puEnd; puStart++)
|
||||||
|
{
|
||||||
bool expected = true;
|
bool expected = true;
|
||||||
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||||
|
{
|
||||||
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +207,9 @@ void VirtualMemoryManager::Free(void *address, size_t size) const
|
||||||
// VirtualMemoryBumpAllocator (implementations)
|
// VirtualMemoryBumpAllocator (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
||||||
: m_allocator(std::move(allocator)), m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size)), m_endptr(m_baseptr + size)
|
: m_allocator(std::move(allocator))
|
||||||
|
, m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size))
|
||||||
|
, m_endptr(m_baseptr + size)
|
||||||
{
|
{
|
||||||
if (m_baseptr.load() == 0)
|
if (m_baseptr.load() == 0)
|
||||||
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
||||||
|
@ -296,7 +318,8 @@ void VirtualMemoryReserve::Reset()
|
||||||
|
|
||||||
void VirtualMemoryReserve::Release()
|
void VirtualMemoryReserve::Release()
|
||||||
{
|
{
|
||||||
if (!m_baseptr) return;
|
if (!m_baseptr)
|
||||||
|
return;
|
||||||
Reset();
|
Reset();
|
||||||
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
||||||
m_baseptr = nullptr;
|
m_baseptr = nullptr;
|
||||||
|
@ -339,13 +362,15 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
|
||||||
{
|
{
|
||||||
uint newPages = pageAlign(newsize) / __pagesize;
|
uint newPages = pageAlign(newsize) / __pagesize;
|
||||||
|
|
||||||
if (newPages > m_pages_reserved) {
|
if (newPages > m_pages_reserved)
|
||||||
|
{
|
||||||
uint toReservePages = newPages - m_pages_reserved;
|
uint toReservePages = newPages - m_pages_reserved;
|
||||||
uint toReserveBytes = toReservePages * __pagesize;
|
uint toReserveBytes = toReservePages * __pagesize;
|
||||||
|
|
||||||
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
||||||
|
|
||||||
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes)) {
|
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes))
|
||||||
|
{
|
||||||
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
||||||
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
||||||
return false;
|
return false;
|
||||||
|
@ -353,7 +378,9 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
|
||||||
|
|
||||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||||
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
||||||
} else if (newPages < m_pages_reserved) {
|
}
|
||||||
|
else if (newPages < m_pages_reserved)
|
||||||
|
{
|
||||||
if (m_pages_commited > newsize)
|
if (m_pages_commited > newsize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,12 @@ long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
|
||||||
// exception.
|
// exception.
|
||||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||||
// work but I don't fully understand why some do and some don't.
|
// work but I don't fully understand why some do and some don't.
|
||||||
__try {
|
__try
|
||||||
|
{
|
||||||
return DoSysPageFaultExceptionFilter(eps);
|
return DoSysPageFaultExceptionFilter(eps);
|
||||||
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
}
|
||||||
|
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
||||||
|
{
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,9 +65,12 @@ static DWORD ConvertToWinApi(const PageProtectionMode &mode)
|
||||||
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
||||||
// microsoft days wasn't a very good coder, me thinks. --air
|
// microsoft days wasn't a very good coder, me thinks. --air
|
||||||
|
|
||||||
if (mode.CanExecute()) {
|
if (mode.CanExecute())
|
||||||
|
{
|
||||||
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||||
} else if (mode.CanRead()) {
|
}
|
||||||
|
else if (mode.CanRead())
|
||||||
|
{
|
||||||
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +89,13 @@ bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &m
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const DWORD errcode = GetLastError();
|
const DWORD errcode = GetLastError();
|
||||||
if (errcode == ERROR_COMMITMENT_MINIMUM) {
|
if (errcode == ERROR_COMMITMENT_MINIMUM)
|
||||||
|
{
|
||||||
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
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...
|
Sleep(1000); // Cut windows some time to rework its memory...
|
||||||
} else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) {
|
}
|
||||||
|
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
|
||||||
|
{
|
||||||
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +149,8 @@ void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &
|
||||||
__pagesize, __pagesize, size, size));
|
__pagesize, __pagesize, size, size));
|
||||||
|
|
||||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||||
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect)) {
|
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect))
|
||||||
|
{
|
||||||
Exception::WinApiError apiError;
|
Exception::WinApiError apiError;
|
||||||
|
|
||||||
apiError.SetDiagMsg(
|
apiError.SetDiagMsg(
|
||||||
|
|
|
@ -126,9 +126,12 @@ void Threading::SetNameOfCurrentThread(const char *name)
|
||||||
info.dwThreadID = GetCurrentThreadId();
|
info.dwThreadID = GetCurrentThreadId();
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
__try {
|
__try
|
||||||
|
{
|
||||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ SingleCoreAffinity::SingleCoreAffinity()
|
||||||
s_threadId = GetCurrentThread();
|
s_threadId = GetCurrentThread();
|
||||||
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
||||||
|
|
||||||
if (s_oldmask == ERROR_INVALID_PARAMETER) {
|
if (s_oldmask == ERROR_INVALID_PARAMETER)
|
||||||
|
{
|
||||||
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
||||||
Console.Warning(
|
Console.Warning(
|
||||||
"CpuDetect: SetThreadAffinityMask failed...\n"
|
"CpuDetect: SetThreadAffinityMask failed...\n"
|
||||||
|
|
|
@ -32,4 +32,4 @@ void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1,
|
||||||
{
|
{
|
||||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -77,7 +77,8 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
|
||||||
|
|
||||||
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
||||||
|
|
||||||
if (hasStreamingSIMD2Extensions) {
|
if (hasStreamingSIMD2Extensions)
|
||||||
|
{
|
||||||
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
// 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
|
// detect MXCSR masking features of the cpu, so we use it's result below
|
||||||
// and override this.
|
// and override this.
|
||||||
|
@ -113,12 +114,14 @@ s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
||||||
|
|
||||||
// Align the cpu execution to a cpuTick boundary.
|
// Align the cpu execution to a cpuTick boundary.
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
timeStart = GetCPUTicks();
|
timeStart = GetCPUTicks();
|
||||||
startCycle = __rdtsc();
|
startCycle = __rdtsc();
|
||||||
} while (GetCPUTicks() == timeStart);
|
} while (GetCPUTicks() == timeStart);
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
timeStop = GetCPUTicks();
|
timeStop = GetCPUTicks();
|
||||||
endCycle = __rdtsc();
|
endCycle = __rdtsc();
|
||||||
} while ((timeStop - timeStart) < time);
|
} while ((timeStop - timeStart) < time);
|
||||||
|
@ -139,7 +142,8 @@ s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
||||||
|
|
||||||
wxString x86capabilities::GetTypeName() const
|
wxString x86capabilities::GetTypeName() const
|
||||||
{
|
{
|
||||||
switch (TypeID) {
|
switch (TypeID)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return L"Standard OEM";
|
return L"Standard OEM";
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -165,7 +169,8 @@ void x86capabilities::CountCores()
|
||||||
|
|
||||||
// detect multicore for AMD cpu
|
// detect multicore for AMD cpu
|
||||||
|
|
||||||
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD)) {
|
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
|
||||||
|
{
|
||||||
// AMD note: they don't support hyperthreading, but they like to flag this true
|
// 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.
|
// 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
|
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
||||||
|
@ -209,13 +214,15 @@ void x86capabilities::Identify()
|
||||||
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
||||||
|
|
||||||
int vid;
|
int vid;
|
||||||
for (vid = 0; vid < x86Vendor_Unknown; ++vid) {
|
for (vid = 0; vid < x86Vendor_Unknown; ++vid)
|
||||||
|
{
|
||||||
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VendorID = static_cast<x86VendorType>(vid);
|
VendorID = static_cast<x86VendorType>(vid);
|
||||||
|
|
||||||
if (cmds >= 0x00000001) {
|
if (cmds >= 0x00000001)
|
||||||
|
{
|
||||||
cpuid(regs, 0x00000001);
|
cpuid(regs, 0x00000001);
|
||||||
|
|
||||||
StepID = regs[0] & 0xf;
|
StepID = regs[0] & 0xf;
|
||||||
|
@ -229,7 +236,8 @@ void x86capabilities::Identify()
|
||||||
Flags2 = regs[2];
|
Flags2 = regs[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmds >= 0x00000007) {
|
if (cmds >= 0x00000007)
|
||||||
|
{
|
||||||
// Note: ECX must be 0 for AVX2 detection.
|
// Note: ECX must be 0 for AVX2 detection.
|
||||||
cpuidex(regs, 0x00000007, 0);
|
cpuidex(regs, 0x00000007, 0);
|
||||||
|
|
||||||
|
@ -238,7 +246,8 @@ void x86capabilities::Identify()
|
||||||
|
|
||||||
cpuid(regs, 0x80000000);
|
cpuid(regs, 0x80000000);
|
||||||
cmds = regs[0];
|
cmds = regs[0];
|
||||||
if (cmds >= 0x80000001) {
|
if (cmds >= 0x80000001)
|
||||||
|
{
|
||||||
cpuid(regs, 0x80000001);
|
cpuid(regs, 0x80000001);
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
|
|
|
@ -43,11 +43,14 @@ namespace x86Emitter
|
||||||
// with one of the other overloads).
|
// with one of the other overloads).
|
||||||
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
|
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
|
||||||
{
|
{
|
||||||
if (sibdest.Is8BitOp()) {
|
if (sibdest.Is8BitOp())
|
||||||
|
{
|
||||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
||||||
|
|
||||||
xWrite<s8>(imm);
|
xWrite<s8>(imm);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
||||||
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
||||||
|
|
||||||
|
@ -80,14 +83,20 @@ static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xIndirectV
|
||||||
|
|
||||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
|
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
|
||||||
{
|
{
|
||||||
if (!to.Is8BitOp() && is_s8(imm)) {
|
if (!to.Is8BitOp() && is_s8(imm))
|
||||||
|
{
|
||||||
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
||||||
xWrite<s8>(imm);
|
xWrite<s8>(imm);
|
||||||
} else {
|
}
|
||||||
if (to.IsAccumulator()) {
|
else
|
||||||
|
{
|
||||||
|
if (to.IsAccumulator())
|
||||||
|
{
|
||||||
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
||||||
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
||||||
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||||
}
|
}
|
||||||
|
@ -132,10 +141,13 @@ void xImpl_Group2::operator()(const xRegisterInt &to, u8 imm) const
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (imm == 1) {
|
if (imm == 1)
|
||||||
|
{
|
||||||
// special encoding of 1's
|
// special encoding of 1's
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
||||||
xWrite8(imm);
|
xWrite8(imm);
|
||||||
}
|
}
|
||||||
|
@ -151,10 +163,13 @@ void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, u8 imm) const
|
||||||
if (imm == 0)
|
if (imm == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (imm == 1) {
|
if (imm == 1)
|
||||||
|
{
|
||||||
// special encoding of 1's
|
// special encoding of 1's
|
||||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
||||||
xWrite8(imm);
|
xWrite8(imm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,4 +58,4 @@ struct xImplBMI_RVM
|
||||||
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G1Type {
|
enum G1Type
|
||||||
|
{
|
||||||
G1Type_ADD = 0,
|
G1Type_ADD = 0,
|
||||||
G1Type_OR,
|
G1Type_OR,
|
||||||
G1Type_ADC,
|
G1Type_ADC,
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G2Type {
|
enum G2Type
|
||||||
|
{
|
||||||
G2Type_ROL = 0,
|
G2Type_ROL = 0,
|
||||||
G2Type_ROR,
|
G2Type_ROR,
|
||||||
G2Type_RCL,
|
G2Type_RCL,
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
enum G3Type {
|
enum G3Type
|
||||||
|
{
|
||||||
G3Type_NOT = 2,
|
G3Type_NOT = 2,
|
||||||
G3Type_NEG = 3,
|
G3Type_NEG = 3,
|
||||||
G3Type_MUL = 4,
|
G3Type_MUL = 4,
|
||||||
|
@ -105,4 +106,4 @@ struct xImpl_iMul
|
||||||
const xImplSimd_DestRegSSE SS;
|
const xImplSimd_DestRegSSE SS;
|
||||||
const xImplSimd_DestRegSSE SD;
|
const xImplSimd_DestRegSSE SD;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -36,7 +36,8 @@ struct xImpl_JmpCall
|
||||||
{
|
{
|
||||||
if (isJmp)
|
if (isJmp)
|
||||||
xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// calls are relative to the instruction after this one, and length is
|
// 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).
|
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
||||||
|
|
||||||
|
|
|
@ -170,4 +170,4 @@ struct xImplSimd_PMove
|
||||||
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||||
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
|
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -238,4 +238,4 @@ struct SimdImpl_PExtract
|
||||||
// used to extract any single packed dword value from src into an x86 32 bit register.
|
// used to extract any single packed dword value from src into an x86 32 bit register.
|
||||||
const xImplSimd_InsertExtractHelper D;
|
const xImplSimd_InsertExtractHelper D;
|
||||||
};
|
};
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -31,7 +31,8 @@ struct xImpl_Test
|
||||||
void operator()(const xRegisterInt& to, int imm) const;
|
void operator()(const xRegisterInt& to, int imm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum G8Type {
|
enum G8Type
|
||||||
|
{
|
||||||
G8Type_BT = 4,
|
G8Type_BT = 4,
|
||||||
G8Type_BTS,
|
G8Type_BTS,
|
||||||
G8Type_BTR,
|
G8Type_BTR,
|
||||||
|
|
|
@ -199,6 +199,7 @@ public:
|
||||||
class xScopedSavedRegisters
|
class xScopedSavedRegisters
|
||||||
{
|
{
|
||||||
std::vector<std::reference_wrapper<const xAddressReg>> regs;
|
std::vector<std::reference_wrapper<const xAddressReg>> regs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
xScopedSavedRegisters(std::initializer_list<std::reference_wrapper<const xAddressReg>> regs);
|
xScopedSavedRegisters(std::initializer_list<std::reference_wrapper<const xAddressReg>> regs);
|
||||||
~xScopedSavedRegisters();
|
~xScopedSavedRegisters();
|
||||||
|
@ -599,4 +600,4 @@ extern const xImplSimd_Unpack xUNPCK;
|
||||||
extern const SimdImpl_Pack xPACK;
|
extern const SimdImpl_Pack xPACK;
|
||||||
extern const xImplSimd_PInsert xPINSR;
|
extern const xImplSimd_PInsert xPINSR;
|
||||||
extern const SimdImpl_PExtract xPEXTR;
|
extern const SimdImpl_PExtract xPEXTR;
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -137,7 +137,8 @@ __emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1 ¶m1, const T2 &p
|
||||||
u8 p =
|
u8 p =
|
||||||
prefix == 0xF2 ? 3 :
|
prefix == 0xF2 ? 3 :
|
||||||
prefix == 0xF3 ? 2 :
|
prefix == 0xF3 ? 2 :
|
||||||
prefix == 0x66 ? 1 : 0;
|
prefix == 0x66 ? 1 :
|
||||||
|
0;
|
||||||
|
|
||||||
xWrite8(0xC5);
|
xWrite8(0xC5);
|
||||||
xWrite8(nR | nv | L | p);
|
xWrite8(nR | nv | L | p);
|
||||||
|
@ -172,11 +173,13 @@ __emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1 ¶m
|
||||||
u8 p =
|
u8 p =
|
||||||
prefix == 0xF2 ? 3 :
|
prefix == 0xF2 ? 3 :
|
||||||
prefix == 0xF3 ? 2 :
|
prefix == 0xF3 ? 2 :
|
||||||
prefix == 0x66 ? 1 : 0;
|
prefix == 0x66 ? 1 :
|
||||||
|
0;
|
||||||
|
|
||||||
u8 m =
|
u8 m =
|
||||||
mb_prefix == 0x3A ? 3 :
|
mb_prefix == 0x3A ? 3 :
|
||||||
mb_prefix == 0x38 ? 2 : 1;
|
mb_prefix == 0x38 ? 2 :
|
||||||
|
1;
|
||||||
|
|
||||||
xWrite8(0xC4);
|
xWrite8(0xC4);
|
||||||
xWrite8(nR | nX | nB | m);
|
xWrite8(nR | nX | nB | m);
|
||||||
|
@ -184,4 +187,4 @@ __emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1 ¶m
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
EmitSibMagic(param1, param3);
|
EmitSibMagic(param1, param3);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -33,11 +33,13 @@
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
|
|
||||||
void xImpl_JmpCall::operator()(const xAddressReg &absreg) const {
|
void xImpl_JmpCall::operator()(const xAddressReg& absreg) const
|
||||||
|
{
|
||||||
// Jumps are always wide and don't need the rex.W
|
// Jumps are always wide and don't need the rex.W
|
||||||
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
||||||
}
|
}
|
||||||
void xImpl_JmpCall::operator()(const xIndirectNative &src) const {
|
void xImpl_JmpCall::operator()(const xIndirectNative& src) const
|
||||||
|
{
|
||||||
// Jumps are always wide and don't need the rex.W
|
// Jumps are always wide and don't need the rex.W
|
||||||
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
||||||
xWrite8(0xff);
|
xWrite8(0xff);
|
||||||
|
@ -49,78 +51,106 @@ const xImpl_JmpCall xCALL = {false};
|
||||||
|
|
||||||
|
|
||||||
template <typename Reg1, typename Reg2>
|
template <typename Reg1, typename Reg2>
|
||||||
void prepareRegsForFastcall(const Reg1 &a1, const Reg2 &a2) {
|
void prepareRegsForFastcall(const Reg1& a1, const Reg2& a2)
|
||||||
if (a1.IsEmpty()) return;
|
{
|
||||||
|
if (a1.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
||||||
if (a2.Id != arg1reg.Id) {
|
if (a2.Id != arg1reg.Id)
|
||||||
|
{
|
||||||
xMOV(Reg1(arg1reg), a1);
|
xMOV(Reg1(arg1reg), a1);
|
||||||
if (!a2.IsEmpty()) {
|
if (!a2.IsEmpty())
|
||||||
|
{
|
||||||
xMOV(Reg2(arg2reg), a2);
|
xMOV(Reg2(arg2reg), a2);
|
||||||
}
|
}
|
||||||
} else if (a1.Id != arg2reg.Id) {
|
}
|
||||||
|
else if (a1.Id != arg2reg.Id)
|
||||||
|
{
|
||||||
xMOV(Reg2(arg2reg), a2);
|
xMOV(Reg2(arg2reg), a2);
|
||||||
xMOV(Reg1(arg1reg), a1);
|
xMOV(Reg1(arg1reg), a1);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xPUSH(a1);
|
xPUSH(a1);
|
||||||
xMOV(Reg2(arg2reg), a2);
|
xMOV(Reg2(arg2reg), a2);
|
||||||
xPOP(Reg1(arg1reg));
|
xPOP(Reg1(arg1reg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, const xRegister32 &a1, const xRegister32 &a2) const {
|
void xImpl_FastCall::operator()(void* f, const xRegister32& a1, const xRegister32& a2) const
|
||||||
|
{
|
||||||
prepareRegsForFastcall(a1, a2);
|
prepareRegsForFastcall(a1, a2);
|
||||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||||
if ((sptr)disp == (s32)disp) {
|
if ((sptr)disp == (s32)disp)
|
||||||
|
{
|
||||||
xCALL(f);
|
xCALL(f);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xMOV(rax, ptrNative[f]);
|
xMOV(rax, ptrNative[f]);
|
||||||
xCALL(rax);
|
xCALL(rax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
void xImpl_FastCall::operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||||
|
{
|
||||||
prepareRegsForFastcall(a1, a2);
|
prepareRegsForFastcall(a1, a2);
|
||||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||||
if ((sptr)disp == (s32)disp) {
|
if ((sptr)disp == (s32)disp)
|
||||||
|
{
|
||||||
xCALL(f);
|
xCALL(f);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xMOV(rax, ptrNative[f]);
|
xMOV(rax, ptrNative[f]);
|
||||||
xCALL(rax);
|
xCALL(rax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegisterLong& a2) const
|
||||||
if (!a2.IsEmpty()) { xMOV(arg2reg, a2); }
|
{
|
||||||
|
if (!a2.IsEmpty())
|
||||||
|
{
|
||||||
|
xMOV(arg2reg, a2);
|
||||||
|
}
|
||||||
xMOV(arg1reg, a1);
|
xMOV(arg1reg, a1);
|
||||||
(*this)(f, arg1reg, arg2reg);
|
(*this)(f, arg1reg, arg2reg);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, void *a1) const {
|
void xImpl_FastCall::operator()(void* f, void* a1) const
|
||||||
|
{
|
||||||
xLEA(arg1reg, ptr[a1]);
|
xLEA(arg1reg, ptr[a1]);
|
||||||
(*this)(f, arg1reg, arg2reg);
|
(*this)(f, arg1reg, arg2reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegister32 &a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegister32& a2) const
|
||||||
if (!a2.IsEmpty()) { xMOV(arg2regd, a2); }
|
{
|
||||||
|
if (!a2.IsEmpty())
|
||||||
|
{
|
||||||
|
xMOV(arg2regd, a2);
|
||||||
|
}
|
||||||
xMOV(arg1regd, a1);
|
xMOV(arg1regd, a1);
|
||||||
(*this)(f, arg1regd, arg2regd);
|
(*this)(f, arg1regd, arg2regd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, const xIndirect32 &a1) const {
|
void xImpl_FastCall::operator()(void* f, const xIndirect32& a1) const
|
||||||
|
{
|
||||||
xMOV(arg1regd, a1);
|
xMOV(arg1regd, a1);
|
||||||
(*this)(f, arg1regd);
|
(*this)(f, arg1regd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(void *f, u32 a1, u32 a2) const {
|
void xImpl_FastCall::operator()(void* f, u32 a1, u32 a2) const
|
||||||
|
{
|
||||||
xMOV(arg1regd, a1);
|
xMOV(arg1regd, a1);
|
||||||
xMOV(arg2regd, a2);
|
xMOV(arg2regd, a2);
|
||||||
(*this)(f, arg1regd, arg2regd);
|
(*this)(f, arg1regd, arg2regd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xImpl_FastCall::operator()(const xIndirectNative &f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
void xImpl_FastCall::operator()(const xIndirectNative& f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||||
|
{
|
||||||
prepareRegsForFastcall(a1, a2);
|
prepareRegsForFastcall(a1, a2);
|
||||||
xCALL(f);
|
xCALL(f);
|
||||||
}
|
}
|
||||||
|
@ -135,7 +165,8 @@ __emitinline s32 *xJcc32(JccComparisonType comparison, s32 displacement)
|
||||||
{
|
{
|
||||||
if (comparison == Jcc_Unconditional)
|
if (comparison == Jcc_Unconditional)
|
||||||
xWrite8(0xe9);
|
xWrite8(0xe9);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
xWrite8(0x0f);
|
xWrite8(0x0f);
|
||||||
xWrite8(0x80 | comparison);
|
xWrite8(0x80 | comparison);
|
||||||
}
|
}
|
||||||
|
@ -170,13 +201,15 @@ __emitinline void xJccKnownTarget(JccComparisonType comparison, const void *targ
|
||||||
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
||||||
displacement8 -= slideVal;
|
displacement8 -= slideVal;
|
||||||
|
|
||||||
if (slideForward) {
|
if (slideForward)
|
||||||
|
{
|
||||||
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_s8(displacement8))
|
if (is_s8(displacement8))
|
||||||
xJcc8(comparison, displacement8);
|
xJcc8(comparison, displacement8);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// Perform a 32 bit jump instead. :(
|
// Perform a 32 bit jump instead. :(
|
||||||
s32* bah = xJcc32(comparison);
|
s32* bah = xJcc32(comparison);
|
||||||
sptr distance = (sptr)target - (sptr)xGetPtr();
|
sptr distance = (sptr)target - (sptr)xGetPtr();
|
||||||
|
@ -208,10 +241,12 @@ xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
|
||||||
|
|
||||||
if (opsize == 1)
|
if (opsize == 1)
|
||||||
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (cctype == Jcc_Unconditional)
|
if (cctype == Jcc_Unconditional)
|
||||||
xWrite8(0xe9);
|
xWrite8(0xe9);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
xWrite8(0x0f);
|
xWrite8(0x0f);
|
||||||
xWrite8(0x80 | cctype);
|
xWrite8(0x80 | cctype);
|
||||||
}
|
}
|
||||||
|
@ -225,10 +260,13 @@ void xForwardJumpBase::_setTarget(uint opsize) const
|
||||||
pxAssertDev(BasePtr != NULL, "");
|
pxAssertDev(BasePtr != NULL, "");
|
||||||
|
|
||||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||||
if (opsize == 1) {
|
if (opsize == 1)
|
||||||
|
{
|
||||||
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
||||||
BasePtr[-1] = (s8)displacement;
|
BasePtr[-1] = (s8)displacement;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// full displacement, no sanity checks needed :D
|
// full displacement, no sanity checks needed :D
|
||||||
((s32*)BasePtr)[-1] = displacement;
|
((s32*)BasePtr)[-1] = displacement;
|
||||||
}
|
}
|
||||||
|
@ -244,4 +282,4 @@ __fi JccComparisonType xInvertCond(JccComparisonType src)
|
||||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||||
return (JccComparisonType)((int)src ^ 1);
|
return (JccComparisonType)((int)src ^ 1);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -96,7 +96,8 @@ void x86SetJ8(u8 *j8)
|
||||||
{
|
{
|
||||||
u32 jump = (x86Ptr - j8) - 1;
|
u32 jump = (x86Ptr - j8) - 1;
|
||||||
|
|
||||||
if (jump > 0x7f) {
|
if (jump > 0x7f)
|
||||||
|
{
|
||||||
Console.Error("j8 greater than 0x7f!!");
|
Console.Error("j8 greater than 0x7f!!");
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
@ -107,16 +108,19 @@ void x86SetJ8A(u8 *j8)
|
||||||
{
|
{
|
||||||
u32 jump = (x86Ptr - j8) - 1;
|
u32 jump = (x86Ptr - j8) - 1;
|
||||||
|
|
||||||
if (jump > 0x7f) {
|
if (jump > 0x7f)
|
||||||
|
{
|
||||||
Console.Error("j8 greater than 0x7f!!");
|
Console.Error("j8 greater than 0x7f!!");
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((uptr)x86Ptr & 0xf) > 4) {
|
if (((uptr)x86Ptr & 0xf) > 4)
|
||||||
|
{
|
||||||
|
|
||||||
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
||||||
|
|
||||||
if (newjump <= 0x7f) {
|
if (newjump <= 0x7f)
|
||||||
|
{
|
||||||
jump = newjump;
|
jump = newjump;
|
||||||
while ((uptr)x86Ptr & 0xf)
|
while ((uptr)x86Ptr & 0xf)
|
||||||
*x86Ptr++ = 0x90;
|
*x86Ptr++ = 0x90;
|
||||||
|
|
|
@ -57,10 +57,12 @@ void xImpl_Mov::operator()(const xIndirectVoid &dest, const xRegisterInt &from)
|
||||||
|
|
||||||
#ifndef __M_X86_64
|
#ifndef __M_X86_64
|
||||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||||
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty()) {
|
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty())
|
||||||
|
{
|
||||||
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
||||||
xWrite32(dest.Displacement);
|
xWrite32(dest.Displacement);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
||||||
|
@ -74,10 +76,12 @@ void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) con
|
||||||
|
|
||||||
#ifndef __M_X86_64
|
#ifndef __M_X86_64
|
||||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||||
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty()) {
|
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty())
|
||||||
|
{
|
||||||
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
||||||
xWrite32(src.Displacement);
|
xWrite32(src.Displacement);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
||||||
|
@ -86,7 +90,8 @@ void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) con
|
||||||
|
|
||||||
void xImpl_Mov::operator()(const xIndirect64orLess& dest, sptr imm) const
|
void xImpl_Mov::operator()(const xIndirect64orLess& dest, sptr imm) const
|
||||||
{
|
{
|
||||||
switch (dest.GetOperandSize()) {
|
switch (dest.GetOperandSize())
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||||
break;
|
break;
|
||||||
|
@ -110,7 +115,8 @@ void xImpl_Mov::operator()(const xIndirect64orLess &dest, sptr imm) const
|
||||||
// the flags (namely replacing mov reg,0 with xor).
|
// the flags (namely replacing mov reg,0 with xor).
|
||||||
void xImpl_Mov::operator()(const xRegisterInt& to, sptr imm, bool preserve_flags) const
|
void xImpl_Mov::operator()(const xRegisterInt& to, sptr imm, bool preserve_flags) const
|
||||||
{
|
{
|
||||||
switch (to.GetOperandSize()) {
|
switch (to.GetOperandSize())
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||||
break;
|
break;
|
||||||
|
@ -127,14 +133,19 @@ void xImpl_Mov::operator()(const xRegisterInt &to, sptr imm, bool preserve_flags
|
||||||
pxAssertMsg(0, "Bad indirect size!");
|
pxAssertMsg(0, "Bad indirect size!");
|
||||||
}
|
}
|
||||||
const xRegisterInt& to_ = to.GetNonWide();
|
const xRegisterInt& to_ = to.GetNonWide();
|
||||||
if (!preserve_flags && (imm == 0)) {
|
if (!preserve_flags && (imm == 0))
|
||||||
|
{
|
||||||
_g1_EmitOp(G1Type_XOR, to_, to_);
|
_g1_EmitOp(G1Type_XOR, to_, to_);
|
||||||
} else if (imm == (u32)imm || !to.IsWide()) {
|
}
|
||||||
|
else if (imm == (u32)imm || !to.IsWide())
|
||||||
|
{
|
||||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||||
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
||||||
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
||||||
to_.xWriteImm(imm);
|
to_.xWriteImm(imm);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
||||||
to.xWriteImm(imm);
|
to.xWriteImm(imm);
|
||||||
}
|
}
|
||||||
|
@ -145,9 +156,12 @@ const xImpl_Mov xMOV;
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
||||||
{
|
{
|
||||||
if (imm == (u32)imm || imm == (s32)imm) {
|
if (imm == (u32)imm || imm == (s32)imm)
|
||||||
|
{
|
||||||
xMOV(to, imm, preserve_flags);
|
xMOV(to, imm, preserve_flags);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
u8 opcode = 0xb8 | to.Id;
|
u8 opcode = 0xb8 | to.Id;
|
||||||
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
||||||
xWrite64(imm);
|
xWrite64(imm);
|
||||||
|
|
|
@ -23,7 +23,8 @@ SSE_MXCSR MXCSR_Mask;
|
||||||
|
|
||||||
const wxChar* EnumToString(SSE_RoundMode sse)
|
const wxChar* EnumToString(SSE_RoundMode sse)
|
||||||
{
|
{
|
||||||
switch (sse) {
|
switch (sse)
|
||||||
|
{
|
||||||
case SSEround_Nearest:
|
case SSEround_Nearest:
|
||||||
return L"Nearest";
|
return L"Nearest";
|
||||||
case SSEround_NegInf:
|
case SSEround_NegInf:
|
||||||
|
@ -104,18 +105,24 @@ __emitinline void SimdPrefix(u8 prefix, u16 opcode)
|
||||||
if (!is16BitOpcode)
|
if (!is16BitOpcode)
|
||||||
pxAssert((opcode >> 8) == 0);
|
pxAssert((opcode >> 8) == 0);
|
||||||
|
|
||||||
if (prefix != 0) {
|
if (prefix != 0)
|
||||||
|
{
|
||||||
if (is16BitOpcode)
|
if (is16BitOpcode)
|
||||||
xWrite32((opcode << 16) | 0x0f00 | prefix);
|
xWrite32((opcode << 16) | 0x0f00 | prefix);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
xWrite16(0x0f00 | prefix);
|
xWrite16(0x0f00 | prefix);
|
||||||
xWrite8(opcode);
|
xWrite8(opcode);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (is16BitOpcode) {
|
else
|
||||||
|
{
|
||||||
|
if (is16BitOpcode)
|
||||||
|
{
|
||||||
xWrite8(0x0f);
|
xWrite8(0x0f);
|
||||||
xWrite16(opcode);
|
xWrite16(opcode);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
xWrite16((opcode << 8) | 0x0f);
|
xWrite16((opcode << 8) | 0x0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -797,4 +804,4 @@ __emitinline void xFXRSTOR(const xIndirectVoid &src)
|
||||||
{
|
{
|
||||||
xOpWrite0F(0, 0xae, 1, src);
|
xOpWrite0F(0, 0xae, 1, src);
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
|
|
||||||
#include "common/Dependencies.h"
|
#include "common/Dependencies.h"
|
||||||
|
|
||||||
enum x86VendorType {
|
enum x86VendorType
|
||||||
|
{
|
||||||
x86Vendor_Intel = 0,
|
x86Vendor_Intel = 0,
|
||||||
x86Vendor_AMD = 1,
|
x86Vendor_AMD = 1,
|
||||||
x86Vendor_Unknown = 2
|
x86Vendor_Unknown = 2
|
||||||
|
@ -124,7 +125,8 @@ protected:
|
||||||
void CountLogicalCores();
|
void CountLogicalCores();
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SSE_RoundMode {
|
enum SSE_RoundMode
|
||||||
|
{
|
||||||
SSE_RoundMode_FIRST = 0,
|
SSE_RoundMode_FIRST = 0,
|
||||||
SSEround_Nearest = 0,
|
SSEround_Nearest = 0,
|
||||||
SSEround_NegInf,
|
SSEround_NegInf,
|
||||||
|
@ -136,10 +138,12 @@ enum SSE_RoundMode {
|
||||||
ImplementEnumOperators(SSE_RoundMode);
|
ImplementEnumOperators(SSE_RoundMode);
|
||||||
|
|
||||||
// Predeclaration for xIndirect32
|
// Predeclaration for xIndirect32
|
||||||
namespace x86Emitter {
|
namespace x86Emitter
|
||||||
template <typename T> class xIndirect;
|
{
|
||||||
|
template <typename T>
|
||||||
|
class xIndirect;
|
||||||
typedef xIndirect<u32> xIndirect32;
|
typedef xIndirect<u32> xIndirect32;
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SSE_MXCSR - Control/Status Register (bitfield)
|
// SSE_MXCSR - Control/Status Register (bitfield)
|
||||||
|
|
|
@ -195,21 +195,24 @@ const char *const x86_regnames_gpr8[] =
|
||||||
"al", "cl", "dl", "bl",
|
"al", "cl", "dl", "bl",
|
||||||
"ah", "ch", "dh", "bh",
|
"ah", "ch", "dh", "bh",
|
||||||
"b8", "b9", "b10", "b11",
|
"b8", "b9", "b10", "b11",
|
||||||
"b12", "b13", "b14", "b15"};
|
"b12", "b13", "b14", "b15"
|
||||||
|
};
|
||||||
|
|
||||||
const char* const x86_regnames_gpr16[] =
|
const char* const x86_regnames_gpr16[] =
|
||||||
{
|
{
|
||||||
"ax", "cx", "dx", "bx",
|
"ax", "cx", "dx", "bx",
|
||||||
"sp", "bp", "si", "di",
|
"sp", "bp", "si", "di",
|
||||||
"h8", "h9", "h10", "h11",
|
"h8", "h9", "h10", "h11",
|
||||||
"h12", "h13", "h14", "h15"};
|
"h12", "h13", "h14", "h15"
|
||||||
|
};
|
||||||
|
|
||||||
const char* const x86_regnames_gpr32[] =
|
const char* const x86_regnames_gpr32[] =
|
||||||
{
|
{
|
||||||
"eax", "ecx", "edx", "ebx",
|
"eax", "ecx", "edx", "ebx",
|
||||||
"esp", "ebp", "esi", "edi",
|
"esp", "ebp", "esi", "edi",
|
||||||
"e8", "e9", "e10", "e11",
|
"e8", "e9", "e10", "e11",
|
||||||
"e12", "e13", "e14", "e15"};
|
"e12", "e13", "e14", "e15"
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
const char* const x86_regnames_gpr64[] =
|
const char* const x86_regnames_gpr64[] =
|
||||||
|
@ -217,7 +220,8 @@ const char *const x86_regnames_gpr64[] =
|
||||||
"rax", "rcx", "rdx", "rbx",
|
"rax", "rcx", "rdx", "rbx",
|
||||||
"rsp", "rbp", "rsi", "rdi",
|
"rsp", "rbp", "rsi", "rdi",
|
||||||
"r8", "r9", "r10", "r11",
|
"r8", "r9", "r10", "r11",
|
||||||
"r12", "r13", "r14", "r15"};
|
"r12", "r13", "r14", "r15"
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* const x86_regnames_sse[] =
|
const char* const x86_regnames_sse[] =
|
||||||
|
@ -225,7 +229,8 @@ const char *const x86_regnames_sse[] =
|
||||||
"xmm0", "xmm1", "xmm2", "xmm3",
|
"xmm0", "xmm1", "xmm2", "xmm3",
|
||||||
"xmm4", "xmm5", "xmm6", "xmm7",
|
"xmm4", "xmm5", "xmm6", "xmm7",
|
||||||
"xmm8", "xmm9", "xmm10", "xmm11",
|
"xmm8", "xmm9", "xmm10", "xmm11",
|
||||||
"xmm12", "xmm13", "xmm14", "xmm15"};
|
"xmm12", "xmm13", "xmm14", "xmm15"
|
||||||
|
};
|
||||||
|
|
||||||
const char* xRegisterBase::GetName()
|
const char* xRegisterBase::GetName()
|
||||||
{
|
{
|
||||||
|
@ -239,7 +244,8 @@ const char *xRegisterBase::GetName()
|
||||||
if (Id >= (int)iREGCNT_GPR || Id < 0)
|
if (Id >= (int)iREGCNT_GPR || Id < 0)
|
||||||
return "!Register index out of range!";
|
return "!Register index out of range!";
|
||||||
|
|
||||||
switch (GetOperandSize()) {
|
switch (GetOperandSize())
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return x86_regnames_gpr8[Id];
|
return x86_regnames_gpr8[Id];
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -299,10 +305,13 @@ void EmitSibMagic(uint regfield, const void *address, int extraRIPOffset)
|
||||||
#else
|
#else
|
||||||
sptr ripRelative = (sptr)address - ((sptr)x86Ptr + sizeof(s8) + sizeof(s32) + extraRIPOffset);
|
sptr ripRelative = (sptr)address - ((sptr)x86Ptr + sizeof(s8) + sizeof(s32) + extraRIPOffset);
|
||||||
// Can we use a rip-relative address? (Prefer this over eiz because it's a byte shorter)
|
// Can we use a rip-relative address? (Prefer this over eiz because it's a byte shorter)
|
||||||
if (ripRelative == (s32)ripRelative) {
|
if (ripRelative == (s32)ripRelative)
|
||||||
|
{
|
||||||
ModRM(0, regfield, ModRm_UseDisp32);
|
ModRM(0, regfield, ModRm_UseDisp32);
|
||||||
displacement = ripRelative;
|
displacement = ripRelative;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pxAssertDev(displacement == (s32)displacement, "SIB target is too far away, needs an indirect register");
|
pxAssertDev(displacement == (s32)displacement, "SIB target is too far away, needs an indirect register");
|
||||||
ModRM(0, regfield, ModRm_UseSib);
|
ModRM(0, regfield, ModRm_UseSib);
|
||||||
SibSB(0, Sib_EIZ, Sib_UseDisp32);
|
SibSB(0, Sib_EIZ, Sib_UseDisp32);
|
||||||
|
@ -352,34 +361,43 @@ void EmitSibMagic(uint regfield, const xIndirectVoid &info, int extraRIPOffset)
|
||||||
// Displacement is only 64 bits for rip-relative addressing
|
// Displacement is only 64 bits for rip-relative addressing
|
||||||
pxAssert(info.Displacement == (s32)info.Displacement || (info.Base.IsEmpty() && info.Index.IsEmpty()));
|
pxAssert(info.Displacement == (s32)info.Displacement || (info.Base.IsEmpty() && info.Index.IsEmpty()));
|
||||||
|
|
||||||
if (!NeedsSibMagic(info)) {
|
if (!NeedsSibMagic(info))
|
||||||
|
{
|
||||||
// Use ModRm-only encoding, with the rm field holding an index/base register, if
|
// Use ModRm-only encoding, with the rm field holding an index/base register, if
|
||||||
// one has been specified. If neither register is specified then use Disp32 form,
|
// one has been specified. If neither register is specified then use Disp32 form,
|
||||||
// which is encoded as "EBP w/o displacement" (which is why EBP must always be
|
// which is encoded as "EBP w/o displacement" (which is why EBP must always be
|
||||||
// encoded *with* a displacement of 0, if it would otherwise not have one).
|
// encoded *with* a displacement of 0, if it would otherwise not have one).
|
||||||
|
|
||||||
if (info.Index.IsEmpty()) {
|
if (info.Index.IsEmpty())
|
||||||
|
{
|
||||||
EmitSibMagic(regfield, (void*)info.Displacement, extraRIPOffset);
|
EmitSibMagic(regfield, (void*)info.Displacement, extraRIPOffset);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (info.Index == rbp && displacement_size == 0)
|
if (info.Index == rbp && displacement_size == 0)
|
||||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||||
|
|
||||||
ModRM(displacement_size, regfield, info.Index.Id & 7);
|
ModRM(displacement_size, regfield, info.Index.Id & 7);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// In order to encode "just" index*scale (and no base), we have to encode
|
// In order to encode "just" index*scale (and no base), we have to encode
|
||||||
// it as a special [index*scale + displacement] form, which is done by
|
// it as a special [index*scale + displacement] form, which is done by
|
||||||
// specifying EBP as the base register and setting the displacement field
|
// specifying EBP as the base register and setting the displacement field
|
||||||
// to zero. (same as ModRm w/o SIB form above, basically, except the
|
// to zero. (same as ModRm w/o SIB form above, basically, except the
|
||||||
// ModRm_UseDisp flag is specified in the SIB instead of the ModRM field).
|
// ModRm_UseDisp flag is specified in the SIB instead of the ModRM field).
|
||||||
|
|
||||||
if (info.Base.IsEmpty()) {
|
if (info.Base.IsEmpty())
|
||||||
|
{
|
||||||
ModRM(0, regfield, ModRm_UseSib);
|
ModRM(0, regfield, ModRm_UseSib);
|
||||||
SibSB(info.Scale, info.Index.Id, Sib_UseDisp32);
|
SibSB(info.Scale, info.Index.Id, Sib_UseDisp32);
|
||||||
xWrite<s32>(info.Displacement);
|
xWrite<s32>(info.Displacement);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (info.Base == rbp && displacement_size == 0)
|
if (info.Base == rbp && displacement_size == 0)
|
||||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||||
|
|
||||||
|
@ -388,7 +406,8 @@ void EmitSibMagic(uint regfield, const xIndirectVoid &info, int extraRIPOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displacement_size != 0) {
|
if (displacement_size != 0)
|
||||||
|
{
|
||||||
if (displacement_size == 1)
|
if (displacement_size == 1)
|
||||||
xWrite<s8>(info.Displacement);
|
xWrite<s8>(info.Displacement);
|
||||||
else
|
else
|
||||||
|
@ -444,7 +463,8 @@ void EmitRex(uint regfield, const xIndirectVoid &info)
|
||||||
bool r = false;
|
bool r = false;
|
||||||
bool x = info.Index.IsExtended();
|
bool x = info.Index.IsExtended();
|
||||||
bool b = info.Base.IsExtended();
|
bool b = info.Base.IsExtended();
|
||||||
if (!NeedsSibMagic(info)) {
|
if (!NeedsSibMagic(info))
|
||||||
|
{
|
||||||
b = x;
|
b = x;
|
||||||
x = false;
|
x = false;
|
||||||
}
|
}
|
||||||
|
@ -485,7 +505,8 @@ void EmitRex(const xRegisterBase ®1, const xIndirectVoid &sib)
|
||||||
bool r = reg1.IsExtended();
|
bool r = reg1.IsExtended();
|
||||||
bool x = sib.Index.IsExtended();
|
bool x = sib.Index.IsExtended();
|
||||||
bool b = sib.Base.IsExtended();
|
bool b = sib.Base.IsExtended();
|
||||||
if (!NeedsSibMagic(sib)) {
|
if (!NeedsSibMagic(sib))
|
||||||
|
{
|
||||||
b = x;
|
b = x;
|
||||||
x = false;
|
x = false;
|
||||||
}
|
}
|
||||||
|
@ -508,7 +529,8 @@ void EmitRexImplicitlyWide(const xIndirectVoid &sib)
|
||||||
bool r = false;
|
bool r = false;
|
||||||
bool x = sib.Index.IsExtended();
|
bool x = sib.Index.IsExtended();
|
||||||
bool b = sib.Base.IsExtended();
|
bool b = sib.Base.IsExtended();
|
||||||
if (!NeedsSibMagic(sib)) {
|
if (!NeedsSibMagic(sib))
|
||||||
|
{
|
||||||
b = x;
|
b = x;
|
||||||
x = false;
|
x = false;
|
||||||
}
|
}
|
||||||
|
@ -551,7 +573,8 @@ __emitinline void xAlignCallTarget()
|
||||||
// Core2/i7 CPUs prefer unaligned addresses. Checking for SSSE3 is a decent filter.
|
// Core2/i7 CPUs prefer unaligned addresses. Checking for SSSE3 is a decent filter.
|
||||||
// (also align in debug modes for disasm convenience)
|
// (also align in debug modes for disasm convenience)
|
||||||
|
|
||||||
if (IsDebugBuild || !x86caps.hasSupplementalStreamingSIMD3Extensions) {
|
if (IsDebugBuild || !x86caps.hasSupplementalStreamingSIMD3Extensions)
|
||||||
|
{
|
||||||
// - P4's and earlier prefer 16 byte alignment.
|
// - P4's and earlier prefer 16 byte alignment.
|
||||||
// - AMD Athlons and Phenoms prefer 8 byte alignment, but I don't have an easy
|
// - AMD Athlons and Phenoms prefer 8 byte alignment, but I don't have an easy
|
||||||
// heuristic for it yet.
|
// heuristic for it yet.
|
||||||
|
@ -569,11 +592,13 @@ __emitinline u8 *xGetAlignedCallTarget()
|
||||||
|
|
||||||
__emitinline void xAdvancePtr(uint bytes)
|
__emitinline void xAdvancePtr(uint bytes)
|
||||||
{
|
{
|
||||||
if (IsDevBuild) {
|
if (IsDevBuild)
|
||||||
|
{
|
||||||
// common debugger courtesy: advance with INT3 as filler.
|
// common debugger courtesy: advance with INT3 as filler.
|
||||||
for (uint i = 0; i < bytes; i++)
|
for (uint i = 0; i < bytes; i++)
|
||||||
xWrite8(0xcc);
|
xWrite8(0xcc);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
x86Ptr += bytes;
|
x86Ptr += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,9 +607,7 @@ __emitinline void xAdvancePtr(uint bytes)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
xRegisterInt xRegisterInt::MatchSizeTo(xRegisterInt other) const
|
xRegisterInt xRegisterInt::MatchSizeTo(xRegisterInt other) const
|
||||||
{
|
{
|
||||||
return other.GetOperandSize() == 1
|
return other.GetOperandSize() == 1 ? xRegisterInt(xRegister8(*this)) : xRegisterInt(other.GetOperandSize(), Id);
|
||||||
? xRegisterInt(xRegister8(*this))
|
|
||||||
: xRegisterInt(other.GetOperandSize(), Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -676,20 +699,25 @@ xAddressVoid::xAddressVoid(const void *displacement)
|
||||||
|
|
||||||
xAddressVoid& xAddressVoid::Add(const xAddressReg& src)
|
xAddressVoid& xAddressVoid::Add(const xAddressReg& src)
|
||||||
{
|
{
|
||||||
if (src == Index) {
|
if (src == Index)
|
||||||
|
{
|
||||||
Factor++;
|
Factor++;
|
||||||
} else if (src == Base) {
|
}
|
||||||
|
else if (src == Base)
|
||||||
|
{
|
||||||
// Compound the existing register reference into the Index/Scale pair.
|
// Compound the existing register reference into the Index/Scale pair.
|
||||||
Base = xEmptyReg;
|
Base = xEmptyReg;
|
||||||
|
|
||||||
if (src == Index)
|
if (src == Index)
|
||||||
Factor++;
|
Factor++;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
pxAssertDev(Index.IsEmpty(), "x86Emitter: Only one scaled index register is allowed in an address modifier.");
|
pxAssertDev(Index.IsEmpty(), "x86Emitter: Only one scaled index register is allowed in an address modifier.");
|
||||||
Index = src;
|
Index = src;
|
||||||
Factor = 2;
|
Factor = 2;
|
||||||
}
|
}
|
||||||
} else if (Base.IsEmpty())
|
}
|
||||||
|
else if (Base.IsEmpty())
|
||||||
Base = src;
|
Base = src;
|
||||||
else if (Index.IsEmpty())
|
else if (Index.IsEmpty())
|
||||||
Index = src;
|
Index = src;
|
||||||
|
@ -705,14 +733,20 @@ xAddressVoid &xAddressVoid::Add(const xAddressVoid &src)
|
||||||
Add(src.Displacement);
|
Add(src.Displacement);
|
||||||
|
|
||||||
// If the factor is 1, we can just treat index like a base register also.
|
// If the factor is 1, we can just treat index like a base register also.
|
||||||
if (src.Factor == 1) {
|
if (src.Factor == 1)
|
||||||
|
{
|
||||||
Add(src.Index);
|
Add(src.Index);
|
||||||
} else if (Index.IsEmpty()) {
|
}
|
||||||
|
else if (Index.IsEmpty())
|
||||||
|
{
|
||||||
Index = src.Index;
|
Index = src.Index;
|
||||||
Factor = src.Factor;
|
Factor = src.Factor;
|
||||||
} else if (Index == src.Index) {
|
}
|
||||||
|
else if (Index == src.Index)
|
||||||
|
{
|
||||||
Factor += src.Factor;
|
Factor += src.Factor;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
pxAssumeDev(false, L"x86Emitter: address modifiers cannot have more than two index registers."); // oops, only 2 regs allowed per ModRm!
|
pxAssumeDev(false, L"x86Emitter: address modifiers cannot have more than two index registers."); // oops, only 2 regs allowed per ModRm!
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -763,7 +797,8 @@ xIndirectVoid::xIndirectVoid(xAddressReg base, xAddressReg index, int scale, spt
|
||||||
//
|
//
|
||||||
void xIndirectVoid::Reduce()
|
void xIndirectVoid::Reduce()
|
||||||
{
|
{
|
||||||
if (Index.IsStackPointer()) {
|
if (Index.IsStackPointer())
|
||||||
|
{
|
||||||
// esp cannot be encoded as the index, so move it to the Base, if possible.
|
// esp cannot be encoded as the index, so move it to the Base, if possible.
|
||||||
// note: intentionally leave index assigned to esp also (generates correct
|
// note: intentionally leave index assigned to esp also (generates correct
|
||||||
// encoding later, since ESP cannot be encoded 'alone')
|
// encoding later, since ESP cannot be encoded 'alone')
|
||||||
|
@ -776,7 +811,8 @@ void xIndirectVoid::Reduce()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no index reg, then load the base register into the index slot.
|
// If no index reg, then load the base register into the index slot.
|
||||||
if (Index.IsEmpty()) {
|
if (Index.IsEmpty())
|
||||||
|
{
|
||||||
Index = Base;
|
Index = Base;
|
||||||
Scale = 0;
|
Scale = 0;
|
||||||
if (!Base.IsStackPointer()) // prevent ESP from being encoded 'alone'
|
if (!Base.IsStackPointer()) // prevent ESP from being encoded 'alone'
|
||||||
|
@ -786,7 +822,8 @@ void xIndirectVoid::Reduce()
|
||||||
|
|
||||||
// The Scale has a series of valid forms, all shown here:
|
// The Scale has a series of valid forms, all shown here:
|
||||||
|
|
||||||
switch (Scale) {
|
switch (Scale)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -854,19 +891,24 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
||||||
|
|
||||||
// See EmitSibMagic for commenting on SIB encoding.
|
// See EmitSibMagic for commenting on SIB encoding.
|
||||||
|
|
||||||
if (!NeedsSibMagic(src) && src.Displacement == (s32)src.Displacement) {
|
if (!NeedsSibMagic(src) && src.Displacement == (s32)src.Displacement)
|
||||||
|
{
|
||||||
// LEA Land: means we have either 1-register encoding or just an offset.
|
// LEA Land: means we have either 1-register encoding or just an offset.
|
||||||
// offset is encodable as an immediate MOV, and a register is encodable
|
// offset is encodable as an immediate MOV, and a register is encodable
|
||||||
// as a register MOV.
|
// as a register MOV.
|
||||||
|
|
||||||
if (src.Index.IsEmpty()) {
|
if (src.Index.IsEmpty())
|
||||||
|
{
|
||||||
xMOV(to, src.Displacement);
|
xMOV(to, src.Displacement);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (displacement_size == 0) {
|
else if (displacement_size == 0)
|
||||||
|
{
|
||||||
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
||||||
return;
|
return;
|
||||||
} else if (!preserve_flags) {
|
}
|
||||||
|
else if (!preserve_flags)
|
||||||
|
{
|
||||||
// encode as MOV and ADD combo. Make sure to use the immediate on the
|
// encode as MOV and ADD combo. Make sure to use the immediate on the
|
||||||
// ADD since it can encode as an 8-bit sign-extended value.
|
// ADD since it can encode as an 8-bit sign-extended value.
|
||||||
|
|
||||||
|
@ -874,9 +916,13 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
||||||
xADD(to, src.Displacement);
|
xADD(to, src.Displacement);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (src.Base.IsEmpty()) {
|
else
|
||||||
if (!preserve_flags && (displacement_size == 0)) {
|
{
|
||||||
|
if (src.Base.IsEmpty())
|
||||||
|
{
|
||||||
|
if (!preserve_flags && (displacement_size == 0))
|
||||||
|
{
|
||||||
// Encode [Index*Scale] as a combination of Mov and Shl.
|
// Encode [Index*Scale] as a combination of Mov and Shl.
|
||||||
// This is more efficient because of the bloated LEA format which requires
|
// This is more efficient because of the bloated LEA format which requires
|
||||||
// a 32 bit displacement, and the compact nature of the alternative.
|
// a 32 bit displacement, and the compact nature of the alternative.
|
||||||
|
@ -888,21 +934,30 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
||||||
xSHL(to, src.Scale);
|
xSHL(to, src.Scale);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (src.Scale == 0) {
|
else
|
||||||
if (!preserve_flags) {
|
{
|
||||||
if (src.Index == rsp) {
|
if (src.Scale == 0)
|
||||||
|
{
|
||||||
|
if (!preserve_flags)
|
||||||
|
{
|
||||||
|
if (src.Index == rsp)
|
||||||
|
{
|
||||||
// ESP is not encodable as an index (ix86 ignores it), thus:
|
// ESP is not encodable as an index (ix86 ignores it), thus:
|
||||||
_xMovRtoR(to, src.Base.MatchSizeTo(to)); // will do the trick!
|
_xMovRtoR(to, src.Base.MatchSizeTo(to)); // will do the trick!
|
||||||
if (src.Displacement)
|
if (src.Displacement)
|
||||||
xADD(to, src.Displacement);
|
xADD(to, src.Displacement);
|
||||||
return;
|
return;
|
||||||
} else if (src.Displacement == 0) {
|
}
|
||||||
|
else if (src.Displacement == 0)
|
||||||
|
{
|
||||||
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
||||||
_g1_EmitOp(G1Type_ADD, to, src.Index.MatchSizeTo(to));
|
_g1_EmitOp(G1Type_ADD, to, src.Index.MatchSizeTo(to));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if ((src.Index == rsp) && (src.Displacement == 0)) {
|
}
|
||||||
|
else if ((src.Index == rsp) && (src.Displacement == 0))
|
||||||
|
{
|
||||||
// special case handling of ESP as Index, which is replaceable with
|
// special case handling of ESP as Index, which is replaceable with
|
||||||
// a single MOV even when preserve_flags is set! :D
|
// a single MOV even when preserve_flags is set! :D
|
||||||
|
|
||||||
|
@ -960,9 +1015,12 @@ void xImpl_Test::operator()(const xIndirect64orLess &dest, int imm) const
|
||||||
|
|
||||||
void xImpl_Test::operator()(const xRegisterInt& to, int imm) const
|
void xImpl_Test::operator()(const xRegisterInt& to, int imm) const
|
||||||
{
|
{
|
||||||
if (to.IsAccumulator()) {
|
if (to.IsAccumulator())
|
||||||
|
{
|
||||||
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa8 : 0xa9, 0, to);
|
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa8 : 0xa9, 0, to);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xf6 : 0xf7, 0, to);
|
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xf6 : 0xf7, 0, to);
|
||||||
}
|
}
|
||||||
to.xWriteImm(imm);
|
to.xWriteImm(imm);
|
||||||
|
@ -980,10 +1038,13 @@ void xImpl_BitScan::operator()(const xRegister16or32or64 &to, const xIndirectVoi
|
||||||
|
|
||||||
void xImpl_IncDec::operator()(const xRegisterInt& to) const
|
void xImpl_IncDec::operator()(const xRegisterInt& to) const
|
||||||
{
|
{
|
||||||
if (to.Is8BitOp()) {
|
if (to.Is8BitOp())
|
||||||
|
{
|
||||||
u8 regfield = isDec ? 1 : 0;
|
u8 regfield = isDec ? 1 : 0;
|
||||||
xOpWrite(to.GetPrefix16(), 0xfe, regfield, to);
|
xOpWrite(to.GetPrefix16(), 0xfe, regfield, to);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
xOpWrite(to.GetPrefix16(), 0xff, isDec ? 1 : 0, to);
|
xOpWrite(to.GetPrefix16(), 0xff, isDec ? 1 : 0, to);
|
||||||
#else
|
#else
|
||||||
|
@ -1055,22 +1116,27 @@ __emitinline void xPUSH(const xIndirectVoid &from)
|
||||||
EmitSibMagic(6, from);
|
EmitSibMagic(6, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void xPOP(xRegister32or64 from) {
|
__fi void xPOP(xRegister32or64 from)
|
||||||
|
{
|
||||||
EmitRexImplicitlyWide(from);
|
EmitRexImplicitlyWide(from);
|
||||||
xWrite8(0x58 | (from->Id & 7));
|
xWrite8(0x58 | (from->Id & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void xPUSH(u32 imm)
|
__fi void xPUSH(u32 imm)
|
||||||
{
|
{
|
||||||
if (is_s8(imm)) {
|
if (is_s8(imm))
|
||||||
|
{
|
||||||
xWrite8(0x6a);
|
xWrite8(0x6a);
|
||||||
xWrite8(imm);
|
xWrite8(imm);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xWrite8(0x68);
|
xWrite8(0x68);
|
||||||
xWrite32(imm);
|
xWrite32(imm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__fi void xPUSH(xRegister32or64 from) {
|
__fi void xPUSH(xRegister32or64 from)
|
||||||
|
{
|
||||||
EmitRexImplicitlyWide(from);
|
EmitRexImplicitlyWide(from);
|
||||||
xWrite8(0x50 | (from->Id & 7));
|
xWrite8(0x50 | (from->Id & 7));
|
||||||
}
|
}
|
||||||
|
@ -1104,7 +1170,8 @@ __fi void xINT(u8 imm)
|
||||||
{
|
{
|
||||||
if (imm == 3)
|
if (imm == 3)
|
||||||
xWrite8(0xcc);
|
xWrite8(0xcc);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
xWrite8(0xcd);
|
xWrite8(0xcd);
|
||||||
xWrite8(imm);
|
xWrite8(imm);
|
||||||
}
|
}
|
||||||
|
@ -1151,9 +1218,11 @@ __emitinline void xRestoreReg(const xRegisterSSE &dest)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void stackAlign(int offset, bool moveDown) {
|
static void stackAlign(int offset, bool moveDown)
|
||||||
|
{
|
||||||
int needed = (16 - (offset % 16)) % 16;
|
int needed = (16 - (offset % 16)) % 16;
|
||||||
if (moveDown) {
|
if (moveDown)
|
||||||
|
{
|
||||||
needed = -needed;
|
needed = -needed;
|
||||||
}
|
}
|
||||||
ALIGN_STACK(needed);
|
ALIGN_STACK(needed);
|
||||||
|
@ -1168,11 +1237,14 @@ xScopedStackFrame::xScopedStackFrame(bool base_frame, bool save_base_pointer, in
|
||||||
m_offset += sizeof(void*); // Call stores the return address (4 bytes)
|
m_offset += sizeof(void*); // Call stores the return address (4 bytes)
|
||||||
|
|
||||||
// Note rbp can surely be optimized in 64 bits
|
// Note rbp can surely be optimized in 64 bits
|
||||||
if (m_base_frame) {
|
if (m_base_frame)
|
||||||
|
{
|
||||||
xPUSH(rbp);
|
xPUSH(rbp);
|
||||||
xMOV(rbp, rsp);
|
xMOV(rbp, rsp);
|
||||||
m_offset += sizeof(void*);
|
m_offset += sizeof(void*);
|
||||||
} else if (m_save_base_pointer) {
|
}
|
||||||
|
else if (m_save_base_pointer)
|
||||||
|
{
|
||||||
xPUSH(rbp);
|
xPUSH(rbp);
|
||||||
m_offset += sizeof(void*);
|
m_offset += sizeof(void*);
|
||||||
}
|
}
|
||||||
|
@ -1233,9 +1305,12 @@ xScopedStackFrame::~xScopedStackFrame()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Destroy the frame
|
// Destroy the frame
|
||||||
if (m_base_frame) {
|
if (m_base_frame)
|
||||||
|
{
|
||||||
xLEAVE();
|
xLEAVE();
|
||||||
} else if (m_save_base_pointer) {
|
}
|
||||||
|
else if (m_save_base_pointer)
|
||||||
|
{
|
||||||
xPOP(rbp);
|
xPOP(rbp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1251,31 +1326,41 @@ xScopedSavedRegisters::xScopedSavedRegisters(std::initializer_list<std::referenc
|
||||||
stackAlign(regs.size() * wordsize, true);
|
stackAlign(regs.size() * wordsize, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
xScopedSavedRegisters::~xScopedSavedRegisters() {
|
xScopedSavedRegisters::~xScopedSavedRegisters()
|
||||||
|
{
|
||||||
stackAlign(regs.size() * wordsize, false);
|
stackAlign(regs.size() * wordsize, false);
|
||||||
for (auto it = regs.rbegin(); it < regs.rend(); ++it) {
|
for (auto it = regs.rbegin(); it < regs.rend(); ++it)
|
||||||
|
{
|
||||||
const xAddressReg& regRef = *it;
|
const xAddressReg& regRef = *it;
|
||||||
xPOP(regRef);
|
xPOP(regRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xAddressVoid xComplexAddress(const xAddressReg& tmpRegister, void *base, const xAddressVoid& offset) {
|
xAddressVoid xComplexAddress(const xAddressReg& tmpRegister, void* base, const xAddressVoid& offset)
|
||||||
if ((sptr)base == (s32)(sptr)base) {
|
{
|
||||||
|
if ((sptr)base == (s32)(sptr)base)
|
||||||
|
{
|
||||||
return offset + base;
|
return offset + base;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xLEA(tmpRegister, ptr[base]);
|
xLEA(tmpRegister, ptr[base]);
|
||||||
return offset + tmpRegister;
|
return offset + tmpRegister;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xLoadFarAddr(const xAddressReg& dst, void *addr) {
|
void xLoadFarAddr(const xAddressReg& dst, void* addr)
|
||||||
|
{
|
||||||
#ifdef __M_X86_64
|
#ifdef __M_X86_64
|
||||||
sptr iaddr = (sptr)addr;
|
sptr iaddr = (sptr)addr;
|
||||||
sptr rip = (sptr)xGetPtr() + 7; // LEA will be 7 bytes
|
sptr rip = (sptr)xGetPtr() + 7; // LEA will be 7 bytes
|
||||||
sptr disp = iaddr - rip;
|
sptr disp = iaddr - rip;
|
||||||
if (disp == (s32)disp) {
|
if (disp == (s32)disp)
|
||||||
|
{
|
||||||
xLEA(dst, ptr[addr]);
|
xLEA(dst, ptr[addr]);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xMOV64(dst, iaddr);
|
xMOV64(dst, iaddr);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -26,7 +26,8 @@ static const uint iREGCNT_XMM = 8;
|
||||||
static const uint iREGCNT_GPR = 8;
|
static const uint iREGCNT_GPR = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum XMMSSEType {
|
enum XMMSSEType
|
||||||
|
{
|
||||||
XMMT_INT = 0, // integer (sse2 only)
|
XMMT_INT = 0, // integer (sse2 only)
|
||||||
XMMT_FPS = 1, // floating point
|
XMMT_FPS = 1, // floating point
|
||||||
//XMMT_FPD = 3, // double
|
//XMMT_FPD = 3, // double
|
||||||
|
@ -127,7 +128,8 @@ static const bool AlwaysUseMovaps = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ModRM 'mod' field enumeration. Provided mostly for reference:
|
// ModRM 'mod' field enumeration. Provided mostly for reference:
|
||||||
enum ModRm_ModField {
|
enum ModRm_ModField
|
||||||
|
{
|
||||||
Mod_NoDisp = 0, // effective address operation with no displacement, in the form of [reg] (or uses special Disp32-only encoding in the case of [ebp] form)
|
Mod_NoDisp = 0, // effective address operation with no displacement, in the form of [reg] (or uses special Disp32-only encoding in the case of [ebp] form)
|
||||||
Mod_Disp8, // effective address operation with 8 bit displacement, in the form of [reg+disp8]
|
Mod_Disp8, // effective address operation with 8 bit displacement, in the form of [reg+disp8]
|
||||||
Mod_Disp32, // effective address operation with 32 bit displacement, in the form of [reg+disp32],
|
Mod_Disp32, // effective address operation with 32 bit displacement, in the form of [reg+disp32],
|
||||||
|
@ -137,7 +139,8 @@ enum ModRm_ModField {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// JccComparisonType - enumerated possibilities for inspired code branching!
|
// JccComparisonType - enumerated possibilities for inspired code branching!
|
||||||
//
|
//
|
||||||
enum JccComparisonType {
|
enum JccComparisonType
|
||||||
|
{
|
||||||
Jcc_Unknown = -2,
|
Jcc_Unknown = -2,
|
||||||
Jcc_Unconditional = -1,
|
Jcc_Unconditional = -1,
|
||||||
Jcc_Overflow = 0x0,
|
Jcc_Overflow = 0x0,
|
||||||
|
@ -168,7 +171,8 @@ enum JccComparisonType {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// SSE2_ComparisonType - enumerated possibilities for SIMD data comparison!
|
// SSE2_ComparisonType - enumerated possibilities for SIMD data comparison!
|
||||||
//
|
//
|
||||||
enum SSE2_ComparisonType {
|
enum SSE2_ComparisonType
|
||||||
|
{
|
||||||
SSE2_Equal = 0,
|
SSE2_Equal = 0,
|
||||||
SSE2_Less,
|
SSE2_Less,
|
||||||
SSE2_LessOrEqual,
|
SSE2_LessOrEqual,
|
||||||
|
@ -208,8 +212,10 @@ protected:
|
||||||
: _operandSize(operandSize)
|
: _operandSize(operandSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint GetOperandSize() const {
|
uint GetOperandSize() const
|
||||||
|
{
|
||||||
pxAssertDev(_operandSize != 0, "Attempted to use operand size of uninitialized or void object");
|
pxAssertDev(_operandSize != 0, "Attempted to use operand size of uninitialized or void object");
|
||||||
return _operandSize;
|
return _operandSize;
|
||||||
}
|
}
|
||||||
|
@ -222,12 +228,18 @@ public:
|
||||||
xWrite8(0x66);
|
xWrite8(0x66);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetImmSize() const {
|
int GetImmSize() const
|
||||||
switch (GetOperandSize()) {
|
{
|
||||||
case 1: return 1;
|
switch (GetOperandSize())
|
||||||
case 2: return 2;
|
{
|
||||||
case 4: return 4;
|
case 1:
|
||||||
case 8: return 4; // Only mov's take 64-bit immediates
|
return 1;
|
||||||
|
case 2:
|
||||||
|
return 2;
|
||||||
|
case 4:
|
||||||
|
return 4;
|
||||||
|
case 8:
|
||||||
|
return 4; // Only mov's take 64-bit immediates
|
||||||
jNO_DEFAULT
|
jNO_DEFAULT
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -235,7 +247,8 @@ public:
|
||||||
|
|
||||||
void xWriteImm(int imm) const
|
void xWriteImm(int imm) const
|
||||||
{
|
{
|
||||||
switch (GetImmSize()) {
|
switch (GetImmSize())
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
xWrite8(imm);
|
xWrite8(imm);
|
||||||
break;
|
break;
|
||||||
|
@ -270,17 +283,20 @@ class xRegisterBase : public OperandSizedObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
xRegisterBase(uint operandSize, int regId)
|
xRegisterBase(uint operandSize, int regId)
|
||||||
: OperandSizedObject(operandSize), Id(regId)
|
: OperandSizedObject(operandSize)
|
||||||
|
, Id(regId)
|
||||||
{
|
{
|
||||||
// Note: to avoid tons of ifdef, the 32 bits build will instantiate
|
// Note: to avoid tons of ifdef, the 32 bits build will instantiate
|
||||||
// all 16x64 bits registers.
|
// all 16x64 bits registers.
|
||||||
pxAssert((Id >= xRegId_Empty) && (Id < 16));
|
pxAssert((Id >= xRegId_Empty) && (Id < 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int Id;
|
int Id;
|
||||||
|
|
||||||
xRegisterBase()
|
xRegisterBase()
|
||||||
: OperandSizedObject(0), Id(xRegId_Invalid)
|
: OperandSizedObject(0)
|
||||||
|
, Id(xRegId_Invalid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +342,7 @@ protected:
|
||||||
: _parent(operandSize, regId)
|
: _parent(operandSize, regId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
xRegisterInt() = default;
|
xRegisterInt() = default;
|
||||||
|
|
||||||
|
@ -961,7 +978,7 @@ static __fi xAddressVoid operator+(sptr addr, const xAddressReg ®)
|
||||||
{
|
{
|
||||||
return reg + (sptr)addr;
|
return reg + (sptr)addr;
|
||||||
}
|
}
|
||||||
}
|
} // namespace x86Emitter
|
||||||
|
|
||||||
#include "implement/helpers.h"
|
#include "implement/helpers.h"
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ void pxCheckBox::Init(const wxString &label, const wxString &subtext, int flags)
|
||||||
*this += m_checkbox | pxSizerFlags::StdExpand();
|
*this += m_checkbox | pxSizerFlags::StdExpand();
|
||||||
|
|
||||||
static const int Indentation = 23;
|
static const int Indentation = 23;
|
||||||
if (!subtext.IsEmpty()) {
|
if (!subtext.IsEmpty())
|
||||||
|
{
|
||||||
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
||||||
|
|
||||||
wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
|
wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
|
||||||
|
@ -61,7 +62,8 @@ void pxCheckBox::Init(const wxString &label, const wxString &subtext, int flags)
|
||||||
pxCheckBox& pxCheckBox::SetSubPadding(int pad)
|
pxCheckBox& pxCheckBox::SetSubPadding(int pad)
|
||||||
{
|
{
|
||||||
m_subPadding = pad;
|
m_subPadding = pad;
|
||||||
if (m_sizerItem_subtext) {
|
if (m_sizerItem_subtext)
|
||||||
|
{
|
||||||
m_sizerItem_subtext->SetBorder(m_subPadding);
|
m_sizerItem_subtext->SetBorder(m_subPadding);
|
||||||
Fit();
|
Fit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Threading
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Semaphore;
|
class Semaphore;
|
||||||
class pxThread;
|
class pxThread;
|
||||||
}
|
} // namespace Threading
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,7 +51,8 @@ void pxRadioPanel::Reset()
|
||||||
if (numbuttons == 0)
|
if (numbuttons == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
|
{
|
||||||
safe_delete(m_objects[i].LabelObj);
|
safe_delete(m_objects[i].LabelObj);
|
||||||
safe_delete(m_objects[i].SubTextObj);
|
safe_delete(m_objects[i].SubTextObj);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +81,8 @@ void pxRadioPanel::Realize()
|
||||||
for (int i = 1; i < numbuttons; ++i)
|
for (int i = 1; i < numbuttons; ++i)
|
||||||
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
|
{
|
||||||
m_objects[i].SubTextObj = NULL;
|
m_objects[i].SubTextObj = NULL;
|
||||||
if (m_buttonStrings[i].SubText.IsEmpty())
|
if (m_buttonStrings[i].SubText.IsEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
@ -89,10 +91,12 @@ void pxRadioPanel::Realize()
|
||||||
|
|
||||||
pxAssert(GetSizer() != NULL);
|
pxAssert(GetSizer() != NULL);
|
||||||
|
|
||||||
for (int i = 0; i < numbuttons; ++i) {
|
for (int i = 0; i < numbuttons; ++i)
|
||||||
|
{
|
||||||
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
||||||
|
|
||||||
if (pxStaticText *subobj = m_objects[i].SubTextObj) {
|
if (pxStaticText* subobj = m_objects[i].SubTextObj)
|
||||||
|
{
|
||||||
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
||||||
*this += 9 + m_padding.GetHeight();
|
*this += 9 + m_padding.GetHeight();
|
||||||
}
|
}
|
||||||
|
@ -137,7 +141,8 @@ pxRadioPanel &pxRadioPanel::SetSelection(int idx)
|
||||||
|
|
||||||
void pxRadioPanel::_RealizeDefaultOption()
|
void pxRadioPanel::_RealizeDefaultOption()
|
||||||
{
|
{
|
||||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
if (m_IsRealized && m_DefaultIdx != -1)
|
||||||
|
{
|
||||||
wxFont def(GetFont());
|
wxFont def(GetFont());
|
||||||
def.SetWeight(wxFONTWEIGHT_BOLD);
|
def.SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
||||||
|
@ -153,7 +158,8 @@ pxRadioPanel &pxRadioPanel::SetDefaultItem(int idx)
|
||||||
if (idx == m_DefaultIdx)
|
if (idx == m_DefaultIdx)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
if (m_IsRealized && m_DefaultIdx != -1)
|
||||||
|
{
|
||||||
wxFont def(GetFont());
|
wxFont def(GetFont());
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
||||||
|
@ -193,7 +199,8 @@ int pxRadioPanel::GetSelection() const
|
||||||
if (!VerifyRealizedState())
|
if (!VerifyRealizedState())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (uint i = 0; i < m_buttonStrings.size(); ++i) {
|
for (uint i = 0; i < m_buttonStrings.size(); ++i)
|
||||||
|
{
|
||||||
if (wxRadioButton* woot = m_objects[i].LabelObj)
|
if (wxRadioButton* woot = m_objects[i].LabelObj)
|
||||||
if (woot->GetValue())
|
if (woot->GetValue())
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -168,7 +168,8 @@ wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const
|
||||||
double parentalFactor = 1.0;
|
double parentalFactor = 1.0;
|
||||||
const wxWindow* millrun = this;
|
const wxWindow* millrun = this;
|
||||||
|
|
||||||
while (millrun) {
|
while (millrun)
|
||||||
|
{
|
||||||
// IMPORTANT : wxWizard changes its min size and then expects everything else
|
// 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)
|
// to play nice and NOT resize according to the new min size. (wtf stupid)
|
||||||
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
||||||
|
@ -177,7 +178,8 @@ wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const
|
||||||
|
|
||||||
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
||||||
|
|
||||||
if (min > 0 && ((idealWidth < 0) || (min < idealWidth))) {
|
if (min > 0 && ((idealWidth < 0) || (min < idealWidth)))
|
||||||
|
{
|
||||||
idealWidth = min;
|
idealWidth = min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +187,8 @@ wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const
|
||||||
millrun = millrun->GetParent();
|
millrun = millrun->GetParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idealWidth <= 0) {
|
if (idealWidth <= 0)
|
||||||
|
{
|
||||||
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
|
// 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.
|
// the size of the user's display area.
|
||||||
|
|
||||||
|
@ -208,7 +211,8 @@ pxStaticText &pxStaticText::WrapAt(int width)
|
||||||
if (width > 1)
|
if (width > 1)
|
||||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
||||||
|
|
||||||
if (m_wrappedLabel != wrappedLabel) {
|
if (m_wrappedLabel != wrappedLabel)
|
||||||
|
{
|
||||||
m_wrappedLabel = wrappedLabel;
|
m_wrappedLabel = wrappedLabel;
|
||||||
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
||||||
SetMinSize(wxSize(
|
SetMinSize(wxSize(
|
||||||
|
@ -220,7 +224,8 @@ pxStaticText &pxStaticText::WrapAt(int width)
|
||||||
|
|
||||||
bool pxStaticText::_updateWrapping(bool textChanged)
|
bool pxStaticText::_updateWrapping(bool textChanged)
|
||||||
{
|
{
|
||||||
if (!m_autowrap) {
|
if (!m_autowrap)
|
||||||
|
{
|
||||||
//m_wrappedLabel = wxEmptyString;
|
//m_wrappedLabel = wxEmptyString;
|
||||||
//m_wrappedWidth = -1;
|
//m_wrappedWidth = -1;
|
||||||
return false;
|
return false;
|
||||||
|
@ -257,7 +262,8 @@ void pxStaticText::UpdateWrapping(bool textChanged)
|
||||||
void pxStaticText::SetLabel(const wxString& label)
|
void pxStaticText::SetLabel(const wxString& label)
|
||||||
{
|
{
|
||||||
const bool labelChanged(label != m_label);
|
const bool labelChanged(label != m_label);
|
||||||
if (labelChanged) {
|
if (labelChanged)
|
||||||
|
{
|
||||||
m_label = label;
|
m_label = label;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
@ -277,7 +283,8 @@ wxFont pxStaticText::GetFontOk() const
|
||||||
|
|
||||||
bool pxStaticText::Enable(bool enabled)
|
bool pxStaticText::Enable(bool enabled)
|
||||||
{
|
{
|
||||||
if (_parent::Enable(enabled)) {
|
if (_parent::Enable(enabled))
|
||||||
|
{
|
||||||
Refresh();
|
Refresh();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -328,10 +335,13 @@ wxSize pxStaticText::DoGetBestSize() const
|
||||||
|
|
||||||
wxSize best;
|
wxSize best;
|
||||||
|
|
||||||
if (m_autowrap) {
|
if (m_autowrap)
|
||||||
|
{
|
||||||
best = GetBestWrappedSize(dc);
|
best = GetBestWrappedSize(dc);
|
||||||
//best.x = wxDefaultCoord;
|
//best.x = wxDefaultCoord;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// No autowrapping, so we can force a specific size here!
|
// No autowrapping, so we can force a specific size here!
|
||||||
best = dc.GetMultiLineTextExtent(GetLabel());
|
best = dc.GetMultiLineTextExtent(GetLabel());
|
||||||
best.x += calcPaddingWidth(best.x);
|
best.x += calcPaddingWidth(best.x);
|
||||||
|
|
|
@ -86,7 +86,8 @@ void pxInputStream::SetStream(const wxString &filename, wxInputStream *stream)
|
||||||
void pxInputStream::Read(void* dest, size_t size)
|
void pxInputStream::Read(void* dest, size_t size)
|
||||||
{
|
{
|
||||||
m_stream_in->Read(dest, size);
|
m_stream_in->Read(dest, size);
|
||||||
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR) {
|
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
|
||||||
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
if (!err)
|
if (!err)
|
||||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
||||||
|
@ -147,7 +148,8 @@ void pxOutputStream::SetStream(const wxString &filename, wxOutputStream *stream)
|
||||||
void pxOutputStream::Write(const void* src, size_t size)
|
void pxOutputStream::Write(const void* src, size_t size)
|
||||||
{
|
{
|
||||||
m_stream_out->Write(src, size);
|
m_stream_out->Write(src, size);
|
||||||
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR) {
|
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
|
||||||
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
if (!err)
|
if (!err)
|
||||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
||||||
|
@ -167,7 +169,8 @@ bool pxReadLine(wxInputStream &input, std::string &dest)
|
||||||
{
|
{
|
||||||
dest.clear();
|
dest.clear();
|
||||||
bool isUTF8 = false;
|
bool isUTF8 = false;
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
char c;
|
char c;
|
||||||
input.Read(&c, sizeof(c));
|
input.Read(&c, sizeof(c));
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
|
@ -176,7 +179,8 @@ bool pxReadLine(wxInputStream &input, std::string &dest)
|
||||||
break;
|
break;
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
break; // eat on UNIX
|
break; // eat on UNIX
|
||||||
if (c == '\r') {
|
if (c == '\r')
|
||||||
|
{
|
||||||
input.Read(&c, sizeof(c));
|
input.Read(&c, sizeof(c));
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -201,7 +205,8 @@ void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed)
|
||||||
dest.clear();
|
dest.clear();
|
||||||
if (pxReadLine(input, intermed))
|
if (pxReadLine(input, intermed))
|
||||||
dest = fromUTF8(intermed.c_str());
|
dest = fromUTF8(intermed.c_str());
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// Optimized ToAscii conversion.
|
// Optimized ToAscii conversion.
|
||||||
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
||||||
const char* ascii = intermed.c_str();
|
const char* ascii = intermed.c_str();
|
||||||
|
@ -230,7 +235,8 @@ void pxWriteLine(wxOutputStream &output)
|
||||||
|
|
||||||
void pxWriteLine(wxOutputStream& output, const wxString& text)
|
void pxWriteLine(wxOutputStream& output, const wxString& text)
|
||||||
{
|
{
|
||||||
if (!text.IsEmpty()) {
|
if (!text.IsEmpty())
|
||||||
|
{
|
||||||
pxToUTF8 utf8(text);
|
pxToUTF8 utf8(text);
|
||||||
output.Write(utf8, utf8.Length());
|
output.Write(utf8, utf8.Length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,12 @@ void pxWindowTextWriter::_DoWriteLn(const wxString &msg)
|
||||||
|
|
||||||
wxPoint dispos(m_curpos);
|
wxPoint dispos(m_curpos);
|
||||||
|
|
||||||
if (m_align & wxALIGN_CENTER_HORIZONTAL) {
|
if (m_align & wxALIGN_CENTER_HORIZONTAL)
|
||||||
|
{
|
||||||
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
||||||
} else if (m_align & wxALIGN_RIGHT) {
|
}
|
||||||
|
else if (m_align & wxALIGN_RIGHT)
|
||||||
|
{
|
||||||
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,12 @@ void SynchronousActionState::SetException(const BaseException &ex)
|
||||||
|
|
||||||
void SynchronousActionState::SetException(BaseException* ex)
|
void SynchronousActionState::SetException(BaseException* ex)
|
||||||
{
|
{
|
||||||
if (!m_posted) {
|
if (!m_posted)
|
||||||
|
{
|
||||||
m_exception = ScopedExcept(ex);
|
m_exception = ScopedExcept(ex);
|
||||||
} else if (wxTheApp) {
|
}
|
||||||
|
else if (wxTheApp)
|
||||||
|
{
|
||||||
// transport the exception to the main thread, since the message is fully
|
// transport the exception to the main thread, since the message is fully
|
||||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
// 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
|
// as a non-blocking action since proper handling of user errors on async messages
|
||||||
|
@ -143,7 +146,8 @@ void pxActionEvent::SetException(BaseException *ex)
|
||||||
const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
||||||
ex->DiagMsg() = prefix + ex->DiagMsg();
|
ex->DiagMsg() = prefix + ex->DiagMsg();
|
||||||
|
|
||||||
if (!m_state) {
|
if (!m_state)
|
||||||
|
{
|
||||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||||
ex->Rethrow();
|
ex->Rethrow();
|
||||||
}
|
}
|
||||||
|
@ -202,7 +206,8 @@ void pxSynchronousCommandEvent::SetException(const BaseException &ex)
|
||||||
|
|
||||||
void pxSynchronousCommandEvent::SetException(BaseException* ex)
|
void pxSynchronousCommandEvent::SetException(BaseException* ex)
|
||||||
{
|
{
|
||||||
if (!m_sync) {
|
if (!m_sync)
|
||||||
|
{
|
||||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||||
ex->Rethrow();
|
ex->Rethrow();
|
||||||
}
|
}
|
||||||
|
@ -349,7 +354,8 @@ bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void *method)
|
||||||
|
|
||||||
void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
|
void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain()) {
|
if (wxThread::IsMain())
|
||||||
|
{
|
||||||
method();
|
method();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -392,7 +398,8 @@ bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain())
|
if (wxThread::IsMain())
|
||||||
return _parent::ProcessEvent(evt);
|
return _parent::ProcessEvent(evt);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
evt.SetSyncState(sync);
|
evt.SetSyncState(sync);
|
||||||
AddPendingEvent(evt);
|
AddPendingEvent(evt);
|
||||||
|
@ -403,10 +410,13 @@ bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt)
|
||||||
|
|
||||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
|
bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
|
||||||
{
|
{
|
||||||
if (wxThread::IsMain()) {
|
if (wxThread::IsMain())
|
||||||
|
{
|
||||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||||
return _parent::ProcessEvent(*deleteMe);
|
return _parent::ProcessEvent(*deleteMe);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
evt->SetSyncState(sync);
|
evt->SetSyncState(sync);
|
||||||
AddPendingEvent(*evt);
|
AddPendingEvent(*evt);
|
||||||
|
@ -436,11 +446,16 @@ void pxActionEvent::_DoInvokeEvent()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFrom_MainUI();
|
AffinityAssert_AllowFrom_MainUI();
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
InvokeEvent();
|
InvokeEvent();
|
||||||
} catch (BaseException &ex) {
|
}
|
||||||
|
catch (BaseException& ex)
|
||||||
|
{
|
||||||
SetException(ex);
|
SetException(ex);
|
||||||
} catch (std::runtime_error &ex) {
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
SetException(new Exception::RuntimeError(ex));
|
SetException(new Exception::RuntimeError(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,11 +470,16 @@ void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent &evt)
|
||||||
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
||||||
evt.SetEventType(evt.GetRealEventType());
|
evt.SetEventType(evt.GetRealEventType());
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
ProcessEvent(evt);
|
ProcessEvent(evt);
|
||||||
} catch (BaseException &ex) {
|
}
|
||||||
|
catch (BaseException& ex)
|
||||||
|
{
|
||||||
evt.SetException(ex);
|
evt.SetException(ex);
|
||||||
} catch (std::runtime_error &ex) {
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,12 +518,14 @@ void wxAppWithHelpers::IdleEventDispatcher(const wxChar *action)
|
||||||
|
|
||||||
ScopedLock lock(m_IdleEventMutex);
|
ScopedLock lock(m_IdleEventMutex);
|
||||||
|
|
||||||
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end()) {
|
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end())
|
||||||
|
{
|
||||||
std::unique_ptr<wxEvent> deleteMe(*node);
|
std::unique_ptr<wxEvent> deleteMe(*node);
|
||||||
m_IdleEventQueue.erase(node);
|
m_IdleEventQueue.erase(node);
|
||||||
|
|
||||||
lock.Release();
|
lock.Release();
|
||||||
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread)) {
|
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread))
|
||||||
|
{
|
||||||
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
|
// 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
|
// 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
|
// thread to crash. So we disallow deletions when those waits are in action, and continue
|
||||||
|
@ -511,7 +533,9 @@ void wxAppWithHelpers::IdleEventDispatcher(const wxChar *action)
|
||||||
|
|
||||||
pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
||||||
postponed.push_back(deleteMe.release());
|
postponed.push_back(deleteMe.release());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
||||||
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
||||||
}
|
}
|
||||||
|
@ -586,12 +610,14 @@ void wxAppWithHelpers::PostAction(const pxActionEvent &evt)
|
||||||
|
|
||||||
void wxAppWithHelpers::ProcessAction(pxActionEvent& evt)
|
void wxAppWithHelpers::ProcessAction(pxActionEvent& evt)
|
||||||
{
|
{
|
||||||
if (!wxThread::IsMain()) {
|
if (!wxThread::IsMain())
|
||||||
|
{
|
||||||
SynchronousActionState sync;
|
SynchronousActionState sync;
|
||||||
evt.SetSyncState(sync);
|
evt.SetSyncState(sync);
|
||||||
AddPendingEvent(evt);
|
AddPendingEvent(evt);
|
||||||
sync.WaitForResult();
|
sync.WaitForResult();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
evt._DoInvokeEvent();
|
evt._DoInvokeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,7 +684,8 @@ wxAppTraits *wxAppWithHelpers::CreateTraits()
|
||||||
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent& evt)
|
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
|
std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
|
||||||
if (!thr) {
|
if (!thr)
|
||||||
|
{
|
||||||
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,4 +142,4 @@ namespace Msgbox
|
||||||
{
|
{
|
||||||
extern int ShowModal(BaseMessageBoxEvent& evt);
|
extern int ShowModal(BaseMessageBoxEvent& evt);
|
||||||
extern int ShowModal(const wxString& title, const wxString& content, const MsgButtons& buttons);
|
extern int ShowModal(const wxString& title, const wxString& content, const MsgButtons& buttons);
|
||||||
}
|
} // namespace Msgbox
|
||||||
|
|
|
@ -40,7 +40,8 @@ const pxStretchType
|
||||||
|
|
||||||
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
||||||
{
|
{
|
||||||
switch (intval) {
|
switch (intval)
|
||||||
|
{
|
||||||
case Centre:
|
case Centre:
|
||||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
||||||
break;
|
break;
|
||||||
|
@ -70,7 +71,8 @@ wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
||||||
|
|
||||||
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
|
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
|
||||||
{
|
{
|
||||||
switch (intval) {
|
switch (intval)
|
||||||
|
{
|
||||||
case Shrink:
|
case Shrink:
|
||||||
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
||||||
break;
|
break;
|
||||||
|
@ -420,8 +422,10 @@ pxTextWrapperBase &pxTextWrapperBase::Wrap(const wxWindow &win, const wxString &
|
||||||
|
|
||||||
wxString::const_iterator lastSpace = text.end();
|
wxString::const_iterator lastSpace = text.end();
|
||||||
wxString::const_iterator lineStart = text.begin();
|
wxString::const_iterator lineStart = text.begin();
|
||||||
for (wxString::const_iterator p = lineStart;; ++p) {
|
for (wxString::const_iterator p = lineStart;; ++p)
|
||||||
if (IsStartOfNewLine()) {
|
{
|
||||||
|
if (IsStartOfNewLine())
|
||||||
|
{
|
||||||
OnNewLine();
|
OnNewLine();
|
||||||
|
|
||||||
lastSpace = text.end();
|
lastSpace = text.end();
|
||||||
|
@ -433,28 +437,36 @@ pxTextWrapperBase &pxTextWrapperBase::Wrap(const wxWindow &win, const wxString &
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p == text.end() || *p == L'\n') {
|
if (p == text.end() || *p == L'\n')
|
||||||
|
{
|
||||||
wasWrapped = false;
|
wasWrapped = false;
|
||||||
DoOutputLine(line);
|
DoOutputLine(line);
|
||||||
|
|
||||||
if (p == text.end())
|
if (p == text.end())
|
||||||
break;
|
break;
|
||||||
} else { // not EOL
|
}
|
||||||
if (is_cjk_char(*p)) {
|
else
|
||||||
if (!no_break_before(*p)) {
|
{ // not EOL
|
||||||
|
if (is_cjk_char(*p))
|
||||||
|
{
|
||||||
|
if (!no_break_before(*p))
|
||||||
|
{
|
||||||
if (p == lineStart || !no_break_after(*(p - 1)))
|
if (p == lineStart || !no_break_after(*(p - 1)))
|
||||||
lastSpace = p;
|
lastSpace = p;
|
||||||
}
|
}
|
||||||
} else if (*p == L' ' || *p == L',' || *p == L'/')
|
}
|
||||||
|
else if (*p == L' ' || *p == L',' || *p == L'/')
|
||||||
lastSpace = p;
|
lastSpace = p;
|
||||||
|
|
||||||
line += *p;
|
line += *p;
|
||||||
|
|
||||||
if (widthMax >= 0 && lastSpace != text.end()) {
|
if (widthMax >= 0 && lastSpace != text.end())
|
||||||
|
{
|
||||||
int width;
|
int width;
|
||||||
win.GetTextExtent(line, &width, NULL);
|
win.GetTextExtent(line, &width, NULL);
|
||||||
|
|
||||||
if (width > widthMax) {
|
if (width > widthMax)
|
||||||
|
{
|
||||||
wasWrapped = true;
|
wasWrapped = true;
|
||||||
|
|
||||||
// remove the last word from this line
|
// remove the last word from this line
|
||||||
|
@ -544,7 +556,8 @@ ScopedBusyCursor::~ScopedBusyCursor()
|
||||||
if (!pxAssert(wxTheApp != NULL))
|
if (!pxAssert(wxTheApp != NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!pxAssert(!m_cursorStack.empty())) {
|
if (!pxAssert(!m_cursorStack.empty()))
|
||||||
|
{
|
||||||
SetManualBusyCursor(m_defBusyType);
|
SetManualBusyCursor(m_defBusyType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +583,8 @@ void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
|
||||||
|
|
||||||
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
|
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
|
||||||
{
|
{
|
||||||
switch (busytype) {
|
switch (busytype)
|
||||||
|
{
|
||||||
case Cursor_NotBusy:
|
case Cursor_NotBusy:
|
||||||
wxSetCursor(wxNullCursor);
|
wxSetCursor(wxNullCursor);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,7 +46,7 @@ extern wxSizerFlags SubGroup();
|
||||||
extern wxSizerFlags StdButton();
|
extern wxSizerFlags StdButton();
|
||||||
extern wxSizerFlags Checkbox();
|
extern wxSizerFlags Checkbox();
|
||||||
extern void SetBestPadding();
|
extern void SetBestPadding();
|
||||||
};
|
}; // namespace pxSizerFlags
|
||||||
|
|
||||||
#define wxSF wxSizerFlags()
|
#define wxSF wxSizerFlags()
|
||||||
|
|
||||||
|
@ -58,7 +58,8 @@ extern void SetBestPadding();
|
||||||
//
|
//
|
||||||
struct pxAlignmentType
|
struct pxAlignmentType
|
||||||
{
|
{
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
Centre,
|
Centre,
|
||||||
Center = Centre,
|
Center = Centre,
|
||||||
Middle,
|
Middle,
|
||||||
|
@ -100,7 +101,8 @@ struct pxAlignmentType
|
||||||
|
|
||||||
struct pxStretchType
|
struct pxStretchType
|
||||||
{
|
{
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
Shrink,
|
Shrink,
|
||||||
Expand,
|
Expand,
|
||||||
Shaped,
|
Shaped,
|
||||||
|
@ -745,7 +747,8 @@ public:
|
||||||
const wxCursor& GetArrowWait();
|
const wxCursor& GetArrowWait();
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BusyCursorType {
|
enum BusyCursorType
|
||||||
|
{
|
||||||
Cursor_NotBusy,
|
Cursor_NotBusy,
|
||||||
Cursor_KindaBusy,
|
Cursor_KindaBusy,
|
||||||
Cursor_ReallyBusy,
|
Cursor_ReallyBusy,
|
||||||
|
|
|
@ -122,7 +122,8 @@ wxDialogWithHelpers::wxDialogWithHelpers(wxWindow *parent, const wxString &title
|
||||||
: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, cflags.GetWxWindowFlags())
|
: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, cflags.GetWxWindowFlags())
|
||||||
{
|
{
|
||||||
m_hasContextHelp = cflags.hasContextHelp;
|
m_hasContextHelp = cflags.hasContextHelp;
|
||||||
if ((int)cflags.BoxSizerOrient != 0) {
|
if ((int)cflags.BoxSizerOrient != 0)
|
||||||
|
{
|
||||||
SetSizer(new wxBoxSizer(cflags.BoxSizerOrient));
|
SetSizer(new wxBoxSizer(cflags.BoxSizerOrient));
|
||||||
*this += StdPadding;
|
*this += StdPadding;
|
||||||
}
|
}
|
||||||
|
@ -179,10 +180,12 @@ void wxDialogWithHelpers::DoAutoCenter()
|
||||||
// a lot since the main window is small).
|
// a lot since the main window is small).
|
||||||
|
|
||||||
bool centerfail = true;
|
bool centerfail = true;
|
||||||
if (wxWindow *parent = GetParent()) {
|
if (wxWindow* parent = GetParent())
|
||||||
|
{
|
||||||
const wxSize parentSize(parent->GetSize());
|
const wxSize parentSize(parent->GetSize());
|
||||||
|
|
||||||
if ((parentSize.x > ((int)GetSize().x * 1.5)) || (parentSize.y > ((int)GetSize().y * 1.5))) {
|
if ((parentSize.x > ((int)GetSize().x * 1.5)) || (parentSize.y > ((int)GetSize().y * 1.5)))
|
||||||
|
{
|
||||||
CenterOnParent();
|
CenterOnParent();
|
||||||
centerfail = false;
|
centerfail = false;
|
||||||
}
|
}
|
||||||
|
@ -197,19 +200,22 @@ void wxDialogWithHelpers::SmartCenterFit()
|
||||||
Fit();
|
Fit();
|
||||||
|
|
||||||
const wxString dlgName(GetDialogName());
|
const wxString dlgName(GetDialogName());
|
||||||
if (dlgName.IsEmpty()) {
|
if (dlgName.IsEmpty())
|
||||||
|
{
|
||||||
DoAutoCenter();
|
DoAutoCenter();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxConfigBase *cfg = wxConfigBase::Get(false)) {
|
if (wxConfigBase* cfg = wxConfigBase::Get(false))
|
||||||
|
{
|
||||||
wxRect screenRect(GetScreenRect());
|
wxRect screenRect(GetScreenRect());
|
||||||
|
|
||||||
IniLoader loader(cfg);
|
IniLoader loader(cfg);
|
||||||
ScopedIniGroup group(loader, L"DialogPositions");
|
ScopedIniGroup group(loader, L"DialogPositions");
|
||||||
cfg->SetRecordDefaults(false);
|
cfg->SetRecordDefaults(false);
|
||||||
|
|
||||||
if (GetWindowStyle() & wxRESIZE_BORDER) {
|
if (GetWindowStyle() & wxRESIZE_BORDER)
|
||||||
|
{
|
||||||
wxSize size;
|
wxSize size;
|
||||||
loader.Entry(dlgName + L"_Size", size, screenRect.GetSize());
|
loader.Entry(dlgName + L"_Size", size, screenRect.GetSize());
|
||||||
SetSize(size);
|
SetSize(size);
|
||||||
|
@ -217,7 +223,8 @@ void wxDialogWithHelpers::SmartCenterFit()
|
||||||
|
|
||||||
if (!cfg->Exists(dlgName + L"_Pos"))
|
if (!cfg->Exists(dlgName + L"_Pos"))
|
||||||
DoAutoCenter();
|
DoAutoCenter();
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
wxPoint pos;
|
wxPoint pos;
|
||||||
loader.Entry(dlgName + L"_Pos", pos, screenRect.GetPosition());
|
loader.Entry(dlgName + L"_Pos", pos, screenRect.GetPosition());
|
||||||
SetPosition(pos);
|
SetPosition(pos);
|
||||||
|
@ -241,7 +248,8 @@ int wxDialogWithHelpers::ShowModal()
|
||||||
// 75% larger than the fitted dialog.
|
// 75% larger than the fitted dialog.
|
||||||
bool wxDialogWithHelpers::Show(bool show)
|
bool wxDialogWithHelpers::Show(bool show)
|
||||||
{
|
{
|
||||||
if (show) {
|
if (show)
|
||||||
|
{
|
||||||
SmartCenterFit();
|
SmartCenterFit();
|
||||||
m_CreatedRect = GetScreenRect();
|
m_CreatedRect = GetScreenRect();
|
||||||
}
|
}
|
||||||
|
@ -270,15 +278,18 @@ void wxDialogWithHelpers::RememberPosition()
|
||||||
// ... not sure how to fix that yet. I could register a list of open windows into wxAppWithHelpers
|
// ... not sure how to fix that yet. I could register a list of open windows into wxAppWithHelpers
|
||||||
// that systematically get closed. Seems like work, maybe later. --air
|
// that systematically get closed. Seems like work, maybe later. --air
|
||||||
|
|
||||||
if (wxConfigBase *cfg = IsIconized() ? NULL : wxConfigBase::Get(false)) {
|
if (wxConfigBase* cfg = IsIconized() ? NULL : wxConfigBase::Get(false))
|
||||||
|
{
|
||||||
const wxString dlgName(GetDialogName());
|
const wxString dlgName(GetDialogName());
|
||||||
const wxRect screenRect(GetScreenRect());
|
const wxRect screenRect(GetScreenRect());
|
||||||
if (!dlgName.IsEmpty() && (m_CreatedRect != screenRect)) {
|
if (!dlgName.IsEmpty() && (m_CreatedRect != screenRect))
|
||||||
|
{
|
||||||
wxPoint pos(screenRect.GetPosition());
|
wxPoint pos(screenRect.GetPosition());
|
||||||
IniSaver saver(cfg);
|
IniSaver saver(cfg);
|
||||||
ScopedIniGroup group(saver, L"DialogPositions");
|
ScopedIniGroup group(saver, L"DialogPositions");
|
||||||
|
|
||||||
if (GetWindowStyle() & wxRESIZE_BORDER) {
|
if (GetWindowStyle() & wxRESIZE_BORDER)
|
||||||
|
{
|
||||||
wxSize size(screenRect.GetSize());
|
wxSize size(screenRect.GetSize());
|
||||||
saver.Entry(dlgName + L"_Size", size, screenRect.GetSize());
|
saver.Entry(dlgName + L"_Size", size, screenRect.GetSize());
|
||||||
}
|
}
|
||||||
|
@ -313,7 +324,8 @@ void wxDialogWithHelpers::AddOkCancel(wxSizer &sizer, bool hasApply)
|
||||||
|
|
||||||
// Add the context-sensitive help button on the caption for the platforms
|
// Add the context-sensitive help button on the caption for the platforms
|
||||||
// which support it (currently MSW only)
|
// which support it (currently MSW only)
|
||||||
if (m_hasContextHelp) {
|
if (m_hasContextHelp)
|
||||||
|
{
|
||||||
SetExtraStyle(wxDIALOG_EX_CONTEXTHELP);
|
SetExtraStyle(wxDIALOG_EX_CONTEXTHELP);
|
||||||
#ifndef __WXMSW__
|
#ifndef __WXMSW__
|
||||||
*m_extraButtonSizer += new wxContextHelpButton(this) | StdButton();
|
*m_extraButtonSizer += new wxContextHelpButton(this) | StdButton();
|
||||||
|
|
Loading…
Reference in New Issue