Mostly-new host exception system (host meaning the C++ / SEH exceptions, not the VM's PS2/MIPS exceptions). Main purpose is to make specifying diagnostic and end-user messages more sane. Secondary goal was to remove the need for C++ multiple and virtual inheritance, which are buggy in MSVC still, and problematic even when they aren't buggy.

I also re-implemented R5900 runtime exception handling for TLB Miss and such (devbuilds only, for now).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3335 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-06-28 18:03:54 +00:00
parent f058e38f5b
commit 1c7fc3e176
60 changed files with 827 additions and 774 deletions

View File

@ -122,7 +122,7 @@ extern pxDoAssertFnType* pxDoAssert;
# define pxAssertDev(cond, msg) pxAssertRel(cond, msg)
# define pxAssumeMsg(cond, msg) (__assume(cond))
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg)
# define pxAssumeDev(cond, msg) pxAssumeRel(cond, msg)
# define pxFail(msg) (__assume(false))
# define pxFailDev(msg) pxAssumeDev(false, msg)

View File

@ -108,6 +108,30 @@ static const pxEnumEnd_t pxEnumEnd = {};
classname& operator=(const classname&)
#endif
// --------------------------------------------------------------------------------------
// ScopedBool - Makes sure a boolean is set back to FALSE when current scope is left
// --------------------------------------------------------------------------------------
// Exception-safe way of tracking entry and exit of various functions of execution zones.
//
class ScopedBool
{
protected:
bool* m_boolme;
public:
ScopedBool(bool& boolme)
{
boolme = true;
m_boolme = &boolme;
}
~ScopedBool() throw()
{
m_boolme = false;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// macro provided for tagging translation strings, without actually running them through the
// translator (which the _() does automatically, and sometimes we don't want that). This is

View File

@ -66,7 +66,6 @@ namespace Exception
protected:
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
wxString m_stacktrace; // contains the stack trace string dump (unimplemented)
public:
virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode.
@ -77,23 +76,20 @@ namespace Exception
wxString& DiagMsg() { return m_message_diag; }
wxString& UserMsg() { return m_message_user; }
BaseException& SetBothMsgs( const char* msg_diag );
BaseException& SetDiagMsg( const wxString& msg_diag );
BaseException& SetUserMsg( const wxString& msg_user );
// Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace.
virtual wxString FormatDiagnosticMessage() const;
// Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such.
virtual wxString FormatDisplayMessage() const { return m_message_user; }
virtual wxString FormatDisplayMessage() const;
virtual void Rethrow() const=0;
virtual BaseException* Clone() const=0;
protected:
// Construction using two pre-formatted pre-translated messages
void InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt );
// Construction using one translation key.
void InitBaseEx( const char* msg_eng );
};
// --------------------------------------------------------------------------------------
@ -118,6 +114,9 @@ namespace Exception
virtual u32 GetPc() const=0;
virtual bool IsDelaySlot() const=0;
virtual wxString Message() const { return m_message; }
virtual void Rethrow() const=0;
virtual Ps2Generic* Clone() const=0;
};
// Some helper macros for defining the standard constructors of internationalized constructors
@ -129,46 +128,44 @@ namespace Exception
// it will be optionally translated.
//
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
// ambiguity errors on virtual inheritence (it really shouldn't!). So I have to force it to the
// ambiguity errors on virtual inheritance (it really shouldn't!). So I have to force it to the
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
//
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
//
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
virtual ~classname() throw() {} \
virtual void Rethrow() const { throw *this; } \
virtual BaseException* Clone() const { return new classname( *this ); }
// This is here because MSVC's support for covariant return types on Clone() is broken, and will
// not work with virtual class inheritance (see DEFINE_EXCEPTION_COPYTORS for details)
#define DEFINE_EXCEPTION_COPYTORS_COVARIANT( classname ) \
#define DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
private: \
typedef parent _parent; \
public: \
virtual ~classname() throw() {} \
virtual void Rethrow() const { throw *this; } \
virtual classname* Clone() const { return new classname( *this ); }
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \
\
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
explicit classname( const wxString& msg_eng, const wxString& msg_xlt ) { BaseException::InitBaseEx( msg_eng, msg_xlt); }
#define DEFINE_LOGIC_EXCEPTION( classname, defmsg ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \
\
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
#define DEFINE_EXCEPTION_MESSAGES( classname ) \
public: \
classname& SetBothMsgs( const char* msg_diag ) { BaseException::SetBothMsgs(msg_diag); return *this; } \
classname& SetDiagMsg( const wxString& msg_diag ) { m_message_diag = msg_diag; return *this; } \
classname& SetUserMsg( const wxString& msg_user ) { m_message_user = msg_user; return *this; }
#define DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
classname() { SetDiagMsg(wxT(message)); } \
DEFINE_EXCEPTION_MESSAGES( classname )
// ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits!
// ---------------------------------------------------------------------------------------
class RuntimeError : public virtual BaseException
class RuntimeError : public BaseException
{
DEFINE_EXCEPTION_COPYTORS( RuntimeError, BaseException )
DEFINE_EXCEPTION_MESSAGES( RuntimeError )
public:
bool IsSilent;
public:
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
RuntimeError() { IsSilent = false; }
RuntimeError( const std::runtime_error& ex, const wxString& prefix=wxEmptyString );
RuntimeError( const std::exception& ex, const wxString& prefix=wxEmptyString );
};
@ -182,18 +179,12 @@ namespace Exception
//
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
class CancelEvent : public virtual RuntimeError
class CancelEvent : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION( CancelEvent, RuntimeError, "No reason given." )
public:
DEFINE_EXCEPTION_COPYTORS( CancelEvent )
explicit CancelEvent( const char* logmsg )
{
m_message_diag = fromUTF8( logmsg );
// overridden message formatters only use the diagnostic version...
}
explicit CancelEvent( const wxString& logmsg=L"No reason given." )
explicit CancelEvent( const wxString& logmsg )
{
m_message_diag = logmsg;
// overridden message formatters only use the diagnostic version...
@ -203,38 +194,33 @@ namespace Exception
virtual wxString FormatDiagnosticMessage() const;
};
// --------------------------------------------------------------------------------------
class ObjectIsNull : public virtual CancelEvent
// ---------------------------------------------------------------------------------------
// OutOfMemory
// ---------------------------------------------------------------------------------------
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
// where %s is filled in with the block name.
//
// The user string is not custom-formatted, and should contain *NO* %s tags.
//
class OutOfMemory : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") )
public:
wxString ObjectName;
wxString AllocDescription;
DEFINE_EXCEPTION_COPYTORS( ObjectIsNull )
explicit ObjectIsNull( const char* objname="unspecified" )
{
m_message_diag = fromUTF8( objname );
// overridden message formatters only use the diagnostic version...
}
public:
OutOfMemory( const wxString& allocdesc );
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
// ---------------------------------------------------------------------------------------
// OutOfMemory / InvalidOperation / InvalidArgument / ParseError
// ---------------------------------------------------------------------------------------
class OutOfMemory : public virtual RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
};
class ParseError : public RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION( ParseError, "Parse error" );
DEFINE_RUNTIME_EXCEPTION( ParseError, RuntimeError, "Parse error" );
};
// ---------------------------------------------------------------------------------------
@ -245,16 +231,15 @@ namespace Exception
// This exception is a specific type of OutOfMemory error that isn't "really" an out of
// memory error. More likely it's caused by a plugin or driver reserving a range of memory
// we'd really like to have access to.
class VirtualMemoryMapConflict : public virtual OutOfMemory
class VirtualMemoryMapConflict : public OutOfMemory
{
public:
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
};
class HardwareDeficiency : public virtual RuntimeError
class HardwareDeficiency : public RuntimeError
{
public:
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, RuntimeError, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
};
// ---------------------------------------------------------------------------------------
@ -262,51 +247,28 @@ namespace Exception
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// ---------------------------------------------------------------------------------------
#define DEFINE_STREAM_EXCEPTION( classname, defmsg ) \
DEFINE_EXCEPTION_COPYTORS( classname ) \
\
explicit classname( const wxString& objname=wxString(), const char* msg=defmsg ) \
{ \
BaseException::InitBaseEx( msg ); \
StreamName = objname; \
} \
explicit classname( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
StreamName = objname; \
} \
explicit classname( const char* objname, const char* msg=defmsg ) \
{ \
BaseException::InitBaseEx( msg ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng, const wxString& msg_xlt ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const char* objname, const wxString& msg_eng ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_eng ); \
StreamName = fromUTF8( objname ); \
} \
explicit classname( const wxString& objname, const wxString& msg_eng ) \
{ \
BaseException::InitBaseEx( msg_eng, msg_eng ); \
StreamName = objname; \
}
#define DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) \
virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
#define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \
DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
classname( const wxString& filename ) { \
StreamName = filename; \
SetBothMsgs(message); \
} \
DEFINE_STREAM_EXCEPTION_ACCESSORS( classname )
// Generic stream error. Contains the name of the stream and a message.
// This exception is usually thrown via derived classes, except in the (rare) case of a
// generic / unknown error.
//
class Stream : public virtual RuntimeError
class Stream : public RuntimeError
{
public:
wxString StreamName; // name of the stream (if applicable)
DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") )
public:
DEFINE_STREAM_EXCEPTION( Stream, "General file operation error." )
wxString StreamName; // name of the stream (if applicable)
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
@ -316,42 +278,40 @@ namespace Exception
// connection, or anything else that would indicate a failure to read the data after the
// stream was successfully opened.
//
class BadStream : public virtual Stream
class BadStream : public Stream
{
public:
DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
};
// A generic exception for odd-ball stream creation errors.
//
class CannotCreateStream : public virtual Stream
class CannotCreateStream : public Stream
{
public:
DEFINE_STREAM_EXCEPTION( CannotCreateStream, wxLt("File could not be created or opened.") )
DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") )
};
// Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid)
//
class FileNotFound : public virtual CannotCreateStream
class FileNotFound : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found.") )
DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") )
};
class AccessDenied : public virtual CannotCreateStream
class AccessDenied : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file.") )
DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") )
};
// EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks.
//
class EndOfStream : public virtual Stream
class EndOfStream : public Stream
{
public:
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") );
};
#ifdef __WXMSW__
@ -360,13 +320,14 @@ namespace Exception
// --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS( WinApiError, RuntimeError )
DEFINE_EXCEPTION_MESSAGES( WinApiError )
public:
int ErrorId;
public:
DEFINE_EXCEPTION_COPYTORS( WinApiError )
WinApiError( const char* msg="" );
WinApiError();
wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const;

View File

@ -233,8 +233,8 @@ template< int Precision >
FixedInt<Precision> FixedInt<Precision>::FromString( const wxString parseFrom )
{
FixedInt<Precision> dest;
if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError(
wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision), wxEmptyString
);
if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError()
.SetDiagMsg(wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision));
return dest;
}

View File

@ -22,30 +22,6 @@
namespace Threading
{
// --------------------------------------------------------------------------------------
// IThread - Interface for the public access to pxThread.
// --------------------------------------------------------------------------------------
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
// as a do-nothing placebo or an assertion generator.
//
class IThread
{
DeclareNoncopyableObject(IThread);
public:
IThread() {}
virtual ~IThread() throw() {}
virtual bool IsSelf() const { return false; }
virtual bool IsRunning() { return false; }
virtual void Start() {}
virtual void Cancel( bool isBlocking = true ) {}
virtual void Block() {}
virtual bool Detach() { return false; }
};
// --------------------------------------------------------------------------------------
// ThreadDeleteEvent
// --------------------------------------------------------------------------------------
@ -109,7 +85,7 @@ namespace Threading
// no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead.
//
class pxThread : public virtual IThread
class pxThread
{
DeclareNoncopyableObject(pxThread);

View File

@ -93,7 +93,7 @@ protected:
m_size = initSize;
if( m_ptr == NULL )
throw Exception::OutOfMemory();
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize));
}
virtual T* _virtual_realloc( int newsize )
@ -138,7 +138,7 @@ public:
m_size = initialSize;
if( (initialSize != 0) && (m_ptr == NULL) )
throw Exception::OutOfMemory();
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize));
}
// Clears the contents of the array to zero, and frees all memory allocations.
@ -163,17 +163,10 @@ public:
m_ptr = _virtual_realloc( newsize );
if( m_ptr == NULL )
{
throw Exception::OutOfMemory(
wxsFormat( // english (for diagnostic)
L"Out-of-memory on SafeArray block re-allocation.\n"
L"Old size: %d bytes, New size: %d bytes.",
m_size, newsize
),
// internationalized!
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newsize )
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize)
);
}
m_size = newsize;
}
@ -262,24 +255,27 @@ public:
safe_free( m_ptr );
}
explicit SafeList( const wxChar* name=L"Unnamed" ) :
Name( name )
, ChunkSize( DefaultChunkSize )
, m_ptr( NULL )
, m_allocsize( 0 )
, m_length( 0 )
explicit SafeList( const wxChar* name=L"Unnamed" )
: Name( name )
{
ChunkSize = DefaultChunkSize;
m_ptr = NULL;
m_allocsize = 0;
m_length = 0;
}
explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" ) :
Name( name )
, ChunkSize( DefaultChunkSize )
, m_ptr( (T*)malloc( initialSize * sizeof(T) ) )
, m_allocsize( initialSize )
, m_length( 0 )
explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" )
: Name( name )
{
ChunkSize = DefaultChunkSize;
m_allocsize = initialSize;
m_length = 0;
m_ptr = (T*)malloc( initialSize * sizeof(T) );
if( m_ptr == NULL )
throw Exception::OutOfMemory();
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length)
);
for( int i=0; i<m_allocsize; ++i )
{
@ -310,18 +306,9 @@ public:
const int newalloc = blockSize + ChunkSize;
m_ptr = _virtual_realloc( newalloc );
if( m_ptr == NULL )
{
throw Exception::OutOfMemory(
// English Diagnostic message:
wxsFormat(
L"Out-of-memory on SafeList block re-allocation.\n"
L"Name: %s, Old size: %d bytes, New size: %d bytes",
Name.c_str(), m_allocsize, newalloc
),
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newalloc )
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize)
);
}
for( ; m_allocsize<newalloc; ++m_allocsize )
{

View File

@ -63,23 +63,30 @@ namespace Threading
namespace Exception
{
class BaseThreadError : public virtual RuntimeError
class BaseThreadError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS( BaseThreadError, RuntimeError )
DEFINE_EXCEPTION_MESSAGES( BaseThreadError )
public:
Threading::pxThread* m_thread;
DEFINE_EXCEPTION_COPYTORS( BaseThreadError )
explicit BaseThreadError( Threading::pxThread* _thread=NULL )
{
m_thread = _thread;
BaseException::InitBaseEx( "Unspecified thread error" );
protected:
BaseThreadError() {
m_thread = NULL;
}
BaseThreadError( Threading::pxThread& _thread )
public:
explicit BaseThreadError( Threading::pxThread* _thread )
{
m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
explicit BaseThreadError( Threading::pxThread& _thread )
{
m_thread = &_thread;
BaseException::InitBaseEx( "Unspecified thread error" );
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
virtual wxString FormatDiagnosticMessage() const;
@ -89,27 +96,21 @@ namespace Exception
const Threading::pxThread& Thread() const;
};
class ThreadCreationError : public virtual BaseThreadError
class ThreadCreationError : public BaseThreadError
{
public:
DEFINE_EXCEPTION_COPYTORS( ThreadCreationError )
DEFINE_EXCEPTION_COPYTORS( ThreadCreationError, BaseThreadError )
explicit ThreadCreationError( Threading::pxThread* _thread=NULL, const char* msg="Creation of thread '%s' failed." )
public:
explicit ThreadCreationError( Threading::pxThread* _thread )
{
m_thread = _thread;
BaseException::InitBaseEx( msg );
SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
}
ThreadCreationError( Threading::pxThread& _thread, const char* msg="Creation of thread '%s' failed." )
explicit ThreadCreationError( Threading::pxThread& _thread )
{
m_thread = &_thread;
BaseException::InitBaseEx( msg );
}
ThreadCreationError( Threading::pxThread& _thread, const wxString& msg_diag, const wxString& msg_user )
{
m_thread = &_thread;
BaseException::InitBaseEx( msg_diag, msg_user );
SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
}
};
}

View File

@ -109,7 +109,7 @@ T* Threading::TlsVariable<T>::GetPtr() const
{
pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) );
if( result == NULL )
throw Exception::OutOfMemory( "Out of memory allocating thread local storage variable." );
throw Exception::OutOfMemory( L"Out of memory allocating thread local storage variable." );
*result = m_initval;
}
return result;

View File

@ -23,14 +23,9 @@
#include <signal.h>
#endif
wxString GetEnglish( const char* msg )
static wxString GetTranslation( const char* msg )
{
return fromUTF8(msg);
}
wxString GetTranslation( const char* msg )
{
return wxGetTranslation( fromUTF8(msg) );
return msg ? wxGetTranslation( fromUTF8(msg) ) : wxString();
}
// ------------------------------------------------------------------------
@ -132,71 +127,91 @@ __forceinline void pxOnAssert( const DiagnosticOrigin& origin, const char* msg)
// --------------------------------------------------------------------------------------
// Exception Namespace Implementations (Format message handlers for general exceptions)
// BaseException (implementations)
// --------------------------------------------------------------------------------------
BaseException::~BaseException() throw() {}
void BaseException::InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt )
BaseException& BaseException::SetBothMsgs( const char* msg_diag )
{
m_message_diag = msg_eng;
m_message_user = msg_xlt.IsEmpty() ? msg_eng : msg_xlt;
// Linux/GCC exception handling is still suspect (this is likely to do with GCC more
// than linux), and fails to propagate exceptions up the stack from EErec code. This
// could likely be because of the EErec using EBP. So to ensure the user at least
// gets a log of the error, we output to console here in the constructor.
#ifdef __LINUX__
//wxLogError( msg_eng.c_str() );
Console.Error( msg_eng );
#endif
m_message_user = GetTranslation( msg_diag );
return SetDiagMsg( fromUTF8(msg_diag) );
}
// given message is assumed to be a translation key, and will be stored in translated
// and untranslated forms.
void BaseException::InitBaseEx( const char* msg_eng )
BaseException& BaseException::SetDiagMsg( const wxString& msg_diag )
{
m_message_diag = GetEnglish( msg_eng );
m_message_user = GetTranslation( msg_eng );
m_message_diag = msg_diag;
return *this;
}
#ifdef __LINUX__
//wxLogError( m_message_diag.c_str() );
Console.Error( msg_eng );
#endif
BaseException& BaseException::SetUserMsg( const wxString& msg_user )
{
m_message_user = msg_user;
return *this;
}
wxString BaseException::FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\n" + m_stacktrace;
return m_message_diag;
}
// ------------------------------------------------------------------------
wxString BaseException::FormatDisplayMessage() const
{
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
}
// --------------------------------------------------------------------------------------
// Exception::RuntimeError (implementations)
// --------------------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix )
{
IsSilent = false;
const wxString msg( wxsFormat( L"STL Runtime Error%s: %s",
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
fromUTF8( ex.what() ).c_str()
) );
BaseException::InitBaseEx( msg, msg );
SetDiagMsg( msg );
}
// ------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& prefix )
{
IsSilent = false;
const wxString msg( wxsFormat( L"STL Exception%s: %s",
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
fromUTF8( ex.what() ).c_str()
) );
BaseException::InitBaseEx( msg, msg );
SetDiagMsg( msg );
}
// --------------------------------------------------------------------------------------
// Exception::OutOfMemory (implementations)
// --------------------------------------------------------------------------------------
Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc )
{
AllocDescription = allocdesc;
m_message_diag = L"Out of memory exception, while allocating the %s.";
m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs.");
}
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
{
return wxsFormat(m_message_diag, AllocDescription.c_str());
}
wxString Exception::OutOfMemory::FormatDisplayMessage() const
{
if (m_message_user.IsEmpty()) return FormatDisplayMessage();
return m_message_user + wxsFormat( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str());
}
// ------------------------------------------------------------------------
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
{
// FIXME: This should probably just log a single line from the stacktrace.. ?
return L"Action canceled: " + m_message_diag;
}
@ -205,35 +220,20 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
return L"Action canceled: " + m_message_diag;
}
// ------------------------------------------------------------------------
wxString Exception::ObjectIsNull::FormatDiagnosticMessage() const
{
return wxsFormat(
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
) + m_stacktrace;
}
wxString Exception::ObjectIsNull::FormatDisplayMessage() const
{
return wxsFormat(
L"reference to '%s' failed : handle is null.",
m_message_diag.c_str()
);
}
// ------------------------------------------------------------------------
wxString Exception::Stream::FormatDiagnosticMessage() const
{
return wxsFormat(
L"Stream exception: %s\n\tFile/Object: %s",
L"%s\n\tFile/Object: %s",
m_message_diag.c_str(), StreamName.c_str()
) + m_stacktrace;
);
}
wxString Exception::Stream::FormatDisplayMessage() const
{
return m_message_user + L"\n\n" +
wxsFormat( _("Name: %s"), StreamName.c_str() );
wxString retval( m_message_user );
if (!StreamName.IsEmpty())
retval += L"\n\n" + wxsFormat( _("Path: %s"), StreamName.c_str() );
return retval;
}

View File

@ -72,7 +72,7 @@ Threading::MutexRecursive::MutexRecursive() : Mutex( false )
if( _InterlockedIncrement( &_attr_refcount ) == 1 )
{
if( 0 != pthread_mutexattr_init( &_attr_recursive ) )
throw Exception::OutOfMemory( "Out of memory error initializing the Mutex attributes for recursive mutexing." );
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
pthread_mutexattr_settype( &_attr_recursive, PTHREAD_MUTEX_RECURSIVE );
}

View File

@ -246,7 +246,7 @@ void Threading::pxThread::Start()
RethrowException();
// And if the thread threw nothing of its own:
throw Exception::ThreadCreationError( this, "(%s thread) Start error: created thread never posted startup semaphore." );
throw Exception::ThreadCreationError( this ).SetDiagMsg( L"Thread creation error: %s thread never posted startup semaphore." );
}
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the

View File

@ -201,3 +201,35 @@ wxString GetOSVersionString()
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::WinApiError (implementations)
// --------------------------------------------------------------------------------------
Exception::WinApiError::WinApiError()
{
ErrorId = GetLastError();
m_message_diag = L"Unspecified Windows API error.";
}
wxString Exception::WinApiError::GetMsgFromWindows() const
{
if (!ErrorId) return L"No valid error number was assigned to this exception!";
const DWORD BUF_LEN = 2048;
TCHAR t_Msg[BUF_LEN];
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
}
wxString Exception::WinApiError::FormatDisplayMessage() const
{
return m_message_user + L"\n\n" + GetMsgFromWindows();
}
wxString Exception::WinApiError::FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\t" + GetMsgFromWindows();
}

View File

@ -96,12 +96,7 @@ FILE *_cdvdOpenMechaVer()
Console.Warning("MEC File Not Found , Creating Blank File");
fd = fopen(file, "wb");
if (fd == NULL)
{
Console.Error( "MEC File Creation failed!" );
throw Exception::CannotCreateStream( file );
//Msgbox::Alert( "_cdvdOpenMechaVer: Error creating %s", file);
//exit(1);
}
throw Exception::CannotCreateStream(mecfile.GetFullPath());
fputc(0x03, fd);
fputc(0x06, fd);
@ -136,10 +131,8 @@ FILE *_cdvdOpenNVM()
Console.Warning("NVM File Not Found , Creating Blank File");
fd = fopen(file, "wb");
if (fd == NULL)
{
Console.Error( "NVM File Creation failed!" );
throw Exception::CannotCreateStream( file );
}
throw Exception::CannotCreateStream(nvmfile.GetFullPath());
for (int i=0; i<1024; i++) fputc(0, fd);
}
return fd;
@ -809,7 +802,7 @@ __forceinline void cdvdReadInterrupt()
// Any other value besides 0 should be considered invalid here (wtf is that wacky
// plugin trying to do?)
jASSUME( cdvd.RErr == 0 );
pxAssume( cdvd.RErr == 0 );
}
if (cdvdReadSector() == -1)

View File

@ -94,7 +94,8 @@ IsoDirectory::IsoDirectory(SectorSource& r)
}
if( !isValid )
throw Exception::FileNotFound( "IsoFS", "Root directory not found on ISO image." );
throw Exception::FileNotFound(L"IsoFS") // FIXME: Should report the name of the ISO here...
.SetDiagMsg(L"IsoFS could not find the root directory on the ISO image.");
DevCon.WriteLn( L"(IsoFS) Filesystem is " + FStype_ToString() );
Init( rootDirEntry );
@ -153,7 +154,7 @@ int IsoDirectory::GetIndexOf(const wxString& fileName) const
if(files[i].name == fileName) return i;
}
throw Exception::FileNotFound( fileName );
throw Exception::FileNotFound(fileName);
}
const IsoFileDescriptor& IsoDirectory::GetEntry(const wxString& fileName) const

View File

@ -242,7 +242,7 @@ bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders(
void ElfObject::readIso(IsoFile file)
{
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename );
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
}
void ElfObject::readFile()
@ -257,19 +257,19 @@ void ElfObject::readFile()
rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
fclose( f );
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename );
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
}
void ElfObject::checkElfSize(s64 elfsize)
{
if (elfsize > 0xfffffff)
throw Exception::BadStream( filename, wxLt("Illegal ELF file size, over 2GB!") );
throw Exception::BadStream(filename).SetBothMsgs(wxLt("Illegal ELF file size over 2GB!"));
if (elfsize == -1)
throw Exception::BadStream( filename, wxLt("Elf file does not exist! ") );
throw Exception::BadStream(filename).SetBothMsgs(wxLt("ELF file does not exist!"));
if (elfsize == 0)
throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") );
throw Exception::BadStream(filename).SetBothMsgs(wxLt("Unexpected end of ELF file."));
}
u32 ElfObject::getCRC()
@ -473,12 +473,14 @@ int GetPS2ElfName( wxString& name )
return 0;
}
}
catch (Exception::BadStream&)
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return 0; // ISO error
}
catch( Exception::FileNotFound& )
catch( Exception::FileNotFound& ex )
{
Console.Warning(ex.FormatDiagnosticMessage());
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
}

View File

@ -18,6 +18,7 @@
#include "Common.h"
#include "R5900OpcodeTables.h"
#include "R5900Exceptions.h"
#include "System/SysThreads.h"
#include "Elfheader.h"
@ -419,6 +420,12 @@ static void intClear(u32 Addr, u32 Size)
static void intShutdown() {
}
static void intThrowException( const BaseR5900Exception& ex )
{
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
ex.Rethrow();
}
R5900cpu intCpu =
{
intAlloc,
@ -429,5 +436,6 @@ R5900cpu intCpu =
intExecute,
intCheckExecutionState,
intThrowException,
intClear,
};

View File

@ -38,7 +38,7 @@ void psxMemAlloc()
m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096 );
if( m_psxAllMem == NULL)
throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." );
throw Exception::OutOfMemory( L"IOP system ram (and roms)" );
u8* curpos = m_psxAllMem;
psxM = curpos; curpos += Ps2MemSize::IopRam;
@ -54,8 +54,8 @@ void psxMemAlloc()
// which is performed by MemInit and PsxMemInit()
void psxMemReset()
{
jASSUME( psxMemWLUT != NULL );
jASSUME( m_psxAllMem != NULL );
pxAssume( psxMemWLUT != NULL );
pxAssume( m_psxAllMem != NULL );
DbgCon.WriteLn( "IOP Resetting physical ram..." );

View File

@ -936,10 +936,11 @@ void SysMtgsThread::WaitForOpen()
RethrowException();
// Not opened yet, and no exceptions. Weird? You decide!
// TODO : implement a user confirmation to cancel the action and exit the
// [TODO] : implement a user confirmation to cancel the action and exit the
// emulator forcefully, or to continue waiting on the GS.
throw Exception::PluginOpenError( PluginId_GS, "The MTGS thread has become unresponsive while waiting for the GS plugin to open." );
throw Exception::PluginOpenError( PluginId_GS )
.SetBothMsgs(wxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open."));
}
}

View File

@ -639,7 +639,7 @@ void memAlloc()
m_psAllMem = vtlb_malloc( m_allMemSize, 4096 );
if( m_psAllMem == NULL)
throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
u8* curpos = m_psAllMem;
psM = curpos; curpos += Ps2MemSize::Base;

View File

@ -617,18 +617,22 @@ PluginManager *g_plugins = NULL;
// Plugin-related Exception Implementations
// ---------------------------------------------------------------------------------
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng )
Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
{
BaseException::InitBaseEx( eng );
StreamName = objname;
PluginId = pid;
m_message_diag = L"%s plugin failed to open!";
m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.";
}
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname,
const wxString& eng_msg, const wxString& xlt_msg )
Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
{
PluginId = pid;
m_message_diag = L"%s plugin initialization failed!";
m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed.";
}
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
{
BaseException::InitBaseEx( eng_msg, xlt_msg );
StreamName = objname;
PluginId = pid;
}
@ -659,7 +663,7 @@ wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
return wxsFormat(
L"%s plugin returned an error while saving the state.\n\n",
tbl_PluginInfo[PluginId].shortname
) + m_stacktrace;
);
}
wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
@ -673,7 +677,7 @@ wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
return wxsFormat(
L"%s plugin returned an error while loading the state.\n\n",
tbl_PluginInfo[PluginId].shortname
) + m_stacktrace;
);
}
wxString Exception::ThawPluginFailure::FormatDisplayMessage() const
@ -726,17 +730,15 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
IsOpened = false;
if( Filename.IsEmpty() )
throw Exception::PluginInitError( pid, "Empty plugin filename." );
throw Exception::PluginInitError( pid ).SetDiagMsg( L"Empty plugin filename" );
if( !wxFile::Exists( Filename ) )
throw Exception::PluginLoadError( pid, srcfile,
wxLt("The configured %s plugin file was not found")
);
throw Exception::PluginLoadError( pid ).SetStreamName(srcfile)
.SetBothMsgs(wxLt("The configured %s plugin file was not found"));
if( !Lib.Load( Filename ) )
throw Exception::PluginLoadError( pid, Filename,
wxLt("The configured %s plugin file is not a valid dynamic library")
);
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
.SetBothMsgs(wxLt("The configured %s plugin file is not a valid dynamic library"));
// Try to enumerate the new v2.0 plugin interface first.
@ -752,10 +754,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
_PS2EsetEmuVersion SetEmuVersion = (_PS2EsetEmuVersion) Lib.GetSymbol( L"PS2EsetEmuVersion" );
if( GetLibName == NULL || GetLibVersion2 == NULL )
throw Exception::PluginLoadError( pid, Filename,
L"\nMethod binding failure on GetLibName or GetLibVersion2.\n",
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." )
);
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
.SetDiagMsg(L"%s plugin init failed: Method binding failure on GetLibName or GetLibVersion2.")
.SetUserMsg(_( "The configured %s plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
if( SetEmuVersion != NULL )
SetEmuVersion( "PCSX2", (0ul << 24) | (9ul<<16) | (7ul<<8) | 0 );
@ -778,10 +779,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
int testres = CommonBindings.Test();
if( testres != 0 )
throw Exception::PluginLoadError( pid, Filename,
wxsFormat( L"Plugin Test failure, return code: %d", testres ),
_( "The plugin reports that your hardware or software/drivers are not supported." )
);
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
.SetDiagMsg(wxsFormat( L"Plugin Test failure, return code: %d", testres ))
.SetUserMsg(_("The plugin reports that your hardware or software/drivers are not supported."));
}
void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
@ -800,10 +800,9 @@ void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
if( *target == NULL )
{
throw Exception::PluginLoadError( pid, Filename,
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ),
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." )
);
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
.SetDiagMsg(wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ))
.SetUserMsg(_("Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
}
target++;
@ -827,10 +826,9 @@ void PluginManager::PluginStatus_t::BindRequired( PluginsEnum_t pid )
if( *(current->Dest) == NULL )
{
throw Exception::PluginLoadError( pid, Filename,
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName().c_str() ),
_( "Configured plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2." )
);
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
.SetDiagMsg(wxsFormat( L"\n%s plugin init error; Method binding failed: %s\n", current->GetMethodName().c_str() ))
.SetUserMsg(_( "Configured %s plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2."));
}
current++;
@ -929,7 +927,7 @@ void PluginManager::Load( const wxString (&folders)[PluginId_Count] )
if( m_mcdPlugin == NULL )
{
// fixme: use plugin's GetLastError (not implemented yet!)
throw Exception::PluginLoadError( PluginId_Mcd, wxEmptyString, "Internal Memorycard Plugin failed to load." );
throw Exception::PluginLoadError( PluginId_Mcd ).SetDiagMsg(L"Internal Memorycard Plugin failed to load.");
}
SendLogFolder();
@ -1246,7 +1244,8 @@ void PluginManager::Init()
if( SysPlugins.Mcd == NULL )
{
// fixme: use plugin's GetLastError (not implemented yet!)
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." );
throw Exception::PluginInitError( PluginId_Mcd )
.SetBothMsgs(wxLt("Internal Memorycard Plugin failed to initialize."));
}
}

View File

@ -55,24 +55,21 @@ struct PluginInfo
namespace Exception
{
// Exception thrown when a corrupted or truncated savestate is encountered.
class SaveStateLoadError : public virtual BadStream
class SaveStateLoadError : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Load failed: The savestate appears to be corrupt or incomplete.") )
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") )
};
class PluginError : public virtual RuntimeError
class PluginError : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, "Generic plugin error")
public:
PluginsEnum_t PluginId;
public:
DEFINE_EXCEPTION_COPYTORS( PluginError )
PluginError() {}
PluginError( PluginsEnum_t pid, const char* msg="Generic plugin error" )
explicit PluginError( PluginsEnum_t pid )
{
BaseException::InitBaseEx( msg );
PluginId = pid;
}
@ -83,15 +80,22 @@ namespace Exception
// Plugin load errors occur when initially trying to load plugins during the
// creation of a PluginManager object. The error may either be due to non-existence,
// corruption, or incompatible versioning.
class PluginLoadError : public virtual PluginError, public virtual BadStream
class PluginLoadError : public PluginError
{
DEFINE_EXCEPTION_COPYTORS( PluginLoadError, PluginError )
DEFINE_EXCEPTION_MESSAGES( PluginLoadError )
public:
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginLoadError )
wxString StreamName;
PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng );
protected:
PluginLoadError() {}
PluginLoadError( PluginsEnum_t pid, const wxString& objname,
const wxString& eng_msg, const wxString& xlt_msg );
public:
PluginLoadError( PluginsEnum_t pid );
virtual PluginLoadError& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
virtual PluginLoadError& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
@ -100,44 +104,46 @@ namespace Exception
// Thrown when a plugin fails it's init() callback. The meaning of this error is entirely
// dependent on the plugin and, in most cases probably never happens (most plugins do little
// more than a couple basic memory reservations during init)
class PluginInitError : public virtual PluginError
class PluginInitError : public PluginError
{
public:
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginInitError )
DEFINE_EXCEPTION_COPYTORS( PluginInitError, PluginError )
DEFINE_EXCEPTION_MESSAGES( PluginInitError )
explicit PluginInitError( PluginsEnum_t pid,
const char* msg=wxLt("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.") )
{
BaseException::InitBaseEx( msg );
PluginId = pid;
}
protected:
PluginInitError() {}
public:
PluginInitError( PluginsEnum_t pid );
};
// Plugin failed to open. Typically this is a non-critical error that means the plugin has
// not been configured properly by the user, but may also be indicative of a system
class PluginOpenError : public virtual PluginError
class PluginOpenError : public PluginError
{
public:
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginOpenError )
DEFINE_EXCEPTION_COPYTORS( PluginOpenError, PluginError )
DEFINE_EXCEPTION_MESSAGES( PluginOpenError )
explicit PluginOpenError( PluginsEnum_t pid,
const char* msg=wxLt("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.") )
{
BaseException::InitBaseEx( msg );
PluginId = pid;
}
protected:
PluginOpenError() {}
public:
explicit PluginOpenError( PluginsEnum_t pid );
};
// This exception is thrown when a plugin returns an error while trying to save itself.
// Typically this should be a very rare occurance since a plugin typically shoudn't
// be doing memory allocations or file access during state saving.
//
class FreezePluginFailure : public virtual PluginError
class FreezePluginFailure : public PluginError
{
public:
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure )
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure, PluginError )
DEFINE_EXCEPTION_MESSAGES( FreezePluginFailure )
explicit FreezePluginFailure( PluginsEnum_t pid)
protected:
FreezePluginFailure() {}
public:
explicit FreezePluginFailure( PluginsEnum_t pid )
{
PluginId = pid;
}
@ -146,11 +152,18 @@ namespace Exception
virtual wxString FormatDisplayMessage() const;
};
class ThawPluginFailure : public virtual PluginError, public virtual SaveStateLoadError
class ThawPluginFailure : public SaveStateLoadError
{
public:
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure )
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure, SaveStateLoadError )
DEFINE_EXCEPTION_MESSAGES( ThawPluginFailure )
public:
PluginsEnum_t PluginId;
protected:
ThawPluginFailure() {}
public:
explicit ThawPluginFailure( PluginsEnum_t pid )
{
PluginId = pid;

View File

@ -50,9 +50,6 @@ static const uint eeWaitCycles = 3072;
bool eeEventTestIsActive = false;
R5900Exception::BaseExcept::~BaseExcept() throw (){}
void cpuReset()
{
if( GetMTGS().IsOpen() )
@ -367,7 +364,7 @@ u32 g_nextBranchCycle = 0;
// and the recompiler. (moved here to help alleviate redundant code)
__forceinline void _cpuBranchTest_Shared()
{
eeEventTestIsActive = true;
ScopedBool etest(eeEventTestIsActive);
g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
// ---- Counters -------------
@ -475,8 +472,6 @@ __forceinline void _cpuBranchTest_Shared()
// Apply vsync and other counter nextCycles
cpuSetNextBranch( nextsCounter, nextCounter );
eeEventTestIsActive = false;
// ---- INTC / DMAC Exceptions -----------------
// Raise the INTC and DMAC interrupts here, which usually throw exceptions.
// This should be done last since the IOP and the VU0 can raise several EE

View File

@ -15,11 +15,11 @@
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef __LINUX__
#pragma region Recompiler Stuffs
#endif
class BaseR5900Exception;
// --------------------------------------------------------------------------------------
// Recompiler Stuffs
// --------------------------------------------------------------------------------------
// This code section contains recompiler vars that are used in "shared" code. Placing
// them in iR5900.h would mean having to include that into more files than I care to
// right now, so we're sticking them here for now until a better solution comes along.
@ -39,12 +39,10 @@ namespace Exception
explicit ExitCpuExecute() { }
};
}
#ifndef __LINUX__
#pragma endregion
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// EE Bios function name tables.
// --------------------------------------------------------------------------------------
// EE Bios function name tables.
// --------------------------------------------------------------------------------------
namespace R5900 {
extern const char* const bios[256];
}
@ -349,6 +347,11 @@ struct R5900cpu
//
void (*CheckExecutionState)();
// Safely throws host exceptions from executing code (either recompiled or interpreted).
// If this function is called outside the context of the CPU's code execution, then the
// given exception will be re-thrown automatically.
void (*ThrowException)( const BaseR5900Exception& ex );
// Manual recompiled code cache clear; typically useful to recompilers only. Size is
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
// better off replaced with some generic API callbacks from VTLB block protection.

View File

@ -13,60 +13,65 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _R5900_EXCEPTIONS_H_
#define _R5900_EXCEPTIONS_H_
#pragma once
// --------------------------------------------------------------------------------------
// BaseR5900Exception
// --------------------------------------------------------------------------------------
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
// time the exception is raised.
//
// Translation note: EE Emulation exceptions are untranslated only. There's really no
// point in providing translations for this hardcore mess. :)
//
class BaseR5900Exception : public Exception::Ps2Generic
{
DEFINE_EXCEPTION_COPYTORS(BaseR5900Exception, Exception::Ps2Generic)
public:
cpuRegisters cpuState;
public:
u32 GetPc() const { return cpuState.pc; }
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
wxString& Message() { return m_message; }
wxString FormatMessage() const
{
return wxsFormat(L"(EE pc:%8.8X) ", cpuRegs.pc) + m_message;
}
protected:
void Init( const wxString& msg )
{
m_message = msg;;
cpuState = cpuRegs;
}
void Init( const char* msg )
{
m_message = fromUTF8( msg );
cpuState = cpuRegs;
}
};
namespace R5900Exception
{
using Exception::Ps2Generic;
//////////////////////////////////////////////////////////////////////////////////////////
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
// time the exception is raised.
//
// Translation note: EE Emulation exceptions are untranslated only. There's really no
// point in providing translations for this hardcore mess. :)
//
class BaseExcept : public virtual Ps2Generic
// --------------------------------------------------------------------------------------
// BaseAddressError
// --------------------------------------------------------------------------------------
class BaseAddressError : public BaseR5900Exception
{
public:
cpuRegisters cpuState;
DEFINE_EXCEPTION_COPYTORS(BaseAddressError, BaseR5900Exception)
public:
virtual ~BaseExcept() throw()=0;
u32 GetPc() const { return cpuState.pc; }
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
protected:
void Init( const wxString& msg )
{
m_message = L"(EE) " + msg;
cpuState = cpuRegs;
}
void Init( const char*msg )
{
m_message = fromUTF8( msg );
cpuState = cpuRegs;
}
};
//////////////////////////////////////////////////////////////////////////////////
//
class BaseAddressError : public BaseExcept
{
public:
bool OnWrite;
u32 Address;
public:
virtual ~BaseAddressError() throw() {}
protected:
void Init( u32 ps2addr, bool onWrite, const wxString& msg )
{
BaseExcept::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) );
_parent::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) );
OnWrite = onWrite;
Address = ps2addr;
}
@ -76,54 +81,46 @@ namespace R5900Exception
class AddressError : public BaseAddressError
{
public:
virtual ~AddressError() throw() {}
AddressError( u32 ps2addr, bool onWrite )
{
BaseAddressError::Init( ps2addr, onWrite, L"Address error" );
}
};
//////////////////////////////////////////////////////////////////////////////////
//
class TLBMiss : public BaseAddressError
{
public:
virtual ~TLBMiss() throw() {}
DEFINE_EXCEPTION_COPYTORS(TLBMiss, BaseAddressError)
public:
TLBMiss( u32 ps2addr, bool onWrite )
{
BaseAddressError::Init( ps2addr, onWrite, L"TLB Miss" );
}
};
//////////////////////////////////////////////////////////////////////////////////
//
class BusError : public BaseAddressError
{
public:
virtual ~BusError() throw() {}
DEFINE_EXCEPTION_COPYTORS(BusError, BaseAddressError)
public:
BusError( u32 ps2addr, bool onWrite )
{
BaseAddressError::Init( ps2addr, onWrite, L"Bus Error" );
}
};
//////////////////////////////////////////////////////////////////////////////////
//
class Trap : public BaseExcept
class Trap : public BaseR5900Exception
{
DEFINE_EXCEPTION_COPYTORS(Trap, BaseR5900Exception)
public:
u16 TrapCode;
public:
virtual ~Trap() throw() {}
// Generates a trap for immediate-style Trap opcodes
Trap()
{
BaseExcept::Init( "Trap" );
_parent::Init( "Trap" );
TrapCode = 0;
}
@ -131,24 +128,19 @@ namespace R5900Exception
// error code in the opcode
explicit Trap( u16 trapcode )
{
BaseExcept::Init( "Trap" ),
_parent::Init( "Trap" ),
TrapCode = trapcode;
}
};
//////////////////////////////////////////////////////////////////////////////////
//
class DebugBreakpoint : public BaseExcept
class DebugBreakpoint : public BaseR5900Exception
{
DEFINE_EXCEPTION_COPYTORS(DebugBreakpoint, BaseR5900Exception)
public:
virtual ~DebugBreakpoint() throw() {}
explicit DebugBreakpoint()
{
BaseExcept::Init( "Debug Breakpoint" );
_parent::Init( "Debug Breakpoint" );
}
};
}
#endif

View File

@ -94,11 +94,9 @@ void SaveStateBase::FreezeTag( const char* src )
if( strcmp( m_tagspace, src ) != 0 )
{
pxFail( "Savestate data corruption detected while reading tag" );
throw Exception::SaveStateLoadError(
// Untranslated diagnostic msg (use default msg for translation)
L"Savestate data corruption detected while reading tag: " + fromUTF8(src)
);
wxString msg( L"Savestate data corruption detected while reading tag: " + fromUTF8(src) );
pxFail( msg );
throw Exception::SaveStateLoadError().SetDiagMsg(msg);
}
}
@ -229,10 +227,9 @@ void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxCh
{
if( sectlen != realsectsize ) // if they don't match then we have a problem, jim.
{
throw Exception::SaveStateLoadError( wxEmptyString,
wxsFormat( L"Invalid size encountered on section '%s'.", sectname ),
_("The savestate data is invalid or corrupted.")
);
throw Exception::SaveStateLoadError()
.SetDiagMsg(wxsFormat(L"Invalid size encountered on section '%s'.", sectname ))
.SetUserMsg(_("The savestate data is invalid or corrupted."));
}
}
}
@ -258,10 +255,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
if( sectlen != 128 )
{
throw Exception::SaveStateLoadError( wxEmptyString,
L"Invalid size encountered on BiosVersion section.",
_("The savestate data is invalid or corrupted.")
);
throw Exception::SaveStateLoadError()
.SetDiagMsg(L"Invalid size encountered on BiosVersion section.")
.SetUserMsg(_("The savestate data is invalid or corrupted."));
}
if( isSeeking )
@ -281,10 +277,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
Freeze( sectlen );
if( sectlen != MainMemorySizeInBytes )
{
throw Exception::SaveStateLoadError( wxEmptyString,
L"Invalid size encountered on MainMemory section.",
_("The savestate data is invalid or corrupted.")
);
throw Exception::SaveStateLoadError()
.SetDiagMsg(L"Invalid size encountered on MainMemory section.")
.SetUserMsg(_("The savestate data is invalid or corrupted."));
}
if( isSeeking )

View File

@ -58,17 +58,20 @@ namespace Exception
// thrown when the savestate being loaded isn't supported.
//
class UnsupportedStateVersion : public virtual SaveStateLoadError
class UnsupportedStateVersion : public SaveStateLoadError
{
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion, SaveStateLoadError )
DEFINE_EXCEPTION_MESSAGES( UnsupportedStateVersion )
public:
u32 Version; // version number of the unsupported state.
public:
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion )
protected:
UnsupportedStateVersion() {}
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString )
public:
explicit UnsupportedStateVersion( int version )
{
StreamName = objname;
Version = version;
}
@ -80,18 +83,21 @@ namespace Exception
// CRC returned by the Cdvd driver.
// [feature not implemented yet]
//
class StateCrcMismatch : public virtual SaveStateLoadError
class StateCrcMismatch : public SaveStateLoadError
{
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch, SaveStateLoadError )
DEFINE_EXCEPTION_MESSAGES( StateCrcMismatch )
public:
u32 Crc_Savestate;
u32 Crc_Cdvd;
public:
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch )
protected:
StateCrcMismatch() {}
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString )
public:
StateCrcMismatch( u32 crc_save, u32 crc_cdvd )
{
StreamName = objname;
Crc_Savestate = crc_save;
Crc_Cdvd = crc_cdvd;
}

View File

@ -167,8 +167,9 @@ template< typename CpuType >
class CpuInitializer
{
public:
ScopedPtr<CpuType> MyCpu;
ScopedPtr<CpuType> MyCpu;
ScopedPtr<BaseException> ExThrown;
CpuInitializer();
virtual ~CpuInitializer() throw();
@ -199,14 +200,14 @@ CpuInitializer< CpuType >::CpuInitializer()
catch( Exception::RuntimeError& ex )
{
Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
if( MyCpu )
MyCpu = NULL;
MyCpu = NULL;
ExThrown = ex.Clone();
}
catch( std::runtime_error& ex )
{
Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
if( MyCpu )
MyCpu = NULL;
MyCpu = NULL;
ExThrown = new Exception::RuntimeError(ex);
}
}
@ -253,9 +254,6 @@ SysCoreAllocations::SysCoreAllocations()
Console.WriteLn( "Initializing PS2 virtual machine..." );
m_RecSuccessEE = false;
m_RecSuccessIOP = false;
try
{
vtlb_Core_Alloc();
@ -266,8 +264,7 @@ SysCoreAllocations::SysCoreAllocations()
// ----------------------------------------------------------------------------
catch( Exception::OutOfMemory& ex )
{
wxString newmsg( ex.UserMsg() + L"\n\n" + GetMemoryErrorVM() );
ex.UserMsg() = newmsg;
ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
CleanupMess();
throw;
}
@ -278,12 +275,12 @@ SysCoreAllocations::SysCoreAllocations()
// re-throw std::bad_alloc as something more friendly. This is needed since
// much of the code uses new/delete internally, which throw std::bad_alloc on fail.
throw Exception::OutOfMemory(
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
L"Error Details: " + fromUTF8( ex.what() ),
GetMemoryErrorVM() // translated
);
throw Exception::OutOfMemory()
.SetDiagMsg(
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
L"Error Details: " + fromUTF8( ex.what() )
)
.SetUserMsg(GetMemoryErrorVM()); // translated
}
Console.WriteLn( "Allocating memory for recompilers..." );
@ -292,20 +289,20 @@ SysCoreAllocations::SysCoreAllocations()
try {
recCpu.Allocate();
m_RecSuccessEE = true;
}
catch( Exception::RuntimeError& ex )
{
m_RecExceptionEE = ex.Clone();
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
recCpu.Shutdown();
}
try {
psxRec.Allocate();
m_RecSuccessIOP = true;
}
catch( Exception::RuntimeError& ex )
{
m_RecExceptionIOP = ex.Clone();
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
psxRec.Shutdown();
}
@ -320,9 +317,13 @@ SysCoreAllocations::SysCoreAllocations()
bool SysCoreAllocations::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
bool SysCoreAllocations::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); }
BaseException* SysCoreAllocations::GetException_MicroVU0() const { return CpuProviders->microVU0.ExThrown; }
BaseException* SysCoreAllocations::GetException_MicroVU1() const { return CpuProviders->microVU1.ExThrown; }
bool SysCoreAllocations::IsRecAvailable_SuperVU0() const { return CpuProviders->superVU0.IsAvailable(); }
bool SysCoreAllocations::IsRecAvailable_SuperVU1() const { return CpuProviders->superVU1.IsAvailable(); }
BaseException* SysCoreAllocations::GetException_SuperVU0() const { return CpuProviders->superVU0.ExThrown; }
BaseException* SysCoreAllocations::GetException_SuperVU1() const { return CpuProviders->superVU1.ExThrown; }
void SysCoreAllocations::CleanupMess() throw()

View File

@ -31,8 +31,8 @@ class SysCoreAllocations
protected:
ScopedPtr<CpuInitializerSet> CpuProviders;
bool m_RecSuccessEE:1;
bool m_RecSuccessIOP:1;
ScopedPtr<BaseException> m_RecExceptionEE;
ScopedPtr<BaseException> m_RecExceptionIOP;
public:
SysCoreAllocations();
@ -42,14 +42,21 @@ public:
bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const;
bool IsRecAvailable_EE() const { return m_RecSuccessEE; }
bool IsRecAvailable_IOP() const { return m_RecSuccessIOP; }
bool IsRecAvailable_EE() const { return !m_RecExceptionEE; }
bool IsRecAvailable_IOP() const { return !m_RecExceptionIOP; }
BaseException* GetException_EE() const { return m_RecExceptionEE; }
BaseException* GetException_IOP() const { return m_RecExceptionIOP; }
bool IsRecAvailable_MicroVU0() const;
bool IsRecAvailable_MicroVU1() const;
BaseException* GetException_MicroVU0() const;
BaseException* GetException_MicroVU1() const;
bool IsRecAvailable_SuperVU0() const;
bool IsRecAvailable_SuperVU1() const;
BaseException* GetException_SuperVU0() const;
BaseException* GetException_SuperVU1() const;
protected:
void CleanupMess() throw();

View File

@ -81,7 +81,8 @@ void SysThreadBase::OnStart()
//
void SysThreadBase::Suspend( bool isBlocking )
{
if( IsSelf() || !IsRunning() ) return;
if (!pxAssertDev(!IsSelf(),"Suspend/Resume are not allowed from this thread.")) return;
if (!IsRunning()) return;
// shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
// from Resume or OnResumeReady code.
@ -98,7 +99,7 @@ void SysThreadBase::Suspend( bool isBlocking )
case ExecMode_Pausing:
case ExecMode_Paused:
if( !isBlocking )
throw Exception::CancelEvent( "Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
throw Exception::CancelEvent( L"Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
m_ExecMode = ExecMode_Closing;
m_sem_Resume.Post();
@ -182,7 +183,7 @@ void SysThreadBase::Resume()
{
Start();
if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
throw Exception::ThreadCreationError();
throw Exception::ThreadCreationError(this);
if( m_ExecMode == ExecMode_Opened ) return;
}
// fall through...

View File

@ -31,9 +31,9 @@ void vuMicroMemAlloc()
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
if( m_vuAllMem == NULL )
throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." );
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
jASSUME( sizeof( VURegs ) <= 0x800 );
pxAssume( sizeof( VURegs ) <= 0x800 );
u8* curpos = m_vuAllMem;
VU0.Micro = curpos; curpos += 0x1000;
@ -55,8 +55,8 @@ void vuMicroMemShutdown()
void vuMicroMemReset()
{
jASSUME( VU0.Mem != NULL );
jASSUME( VU1.Mem != NULL );
pxAssume( VU0.Mem != NULL );
pxAssume( VU1.Mem != NULL );
memMapVUmicro();
@ -107,8 +107,8 @@ void SaveStateBase::vuMicroFreeze()
{
FreezeTag( "vuMicro" );
jASSUME( VU0.Mem != NULL );
jASSUME( VU1.Mem != NULL );
pxAssume( VU0.Mem != NULL );
pxAssume( VU1.Mem != NULL );
Freeze(VU0.ACC);
Freeze(VU0.code);

View File

@ -58,7 +58,7 @@ CompressThread_gzip::~CompressThread_gzip() throw()
void CompressThread_gzip::Write( const void* data, size_t size )
{
if( gzwrite( m_gzfp, data, size ) == 0 )
throw Exception::BadStream( m_filename, "Write to zip file failed." );
throw Exception::BadStream( m_filename ).SetDiagMsg(L"Write to zip file failed.");
}
void CompressThread_gzip::ExecuteTaskInThread()
@ -104,7 +104,9 @@ void CompressThread_gzip::ExecuteTaskInThread()
m_gzfp = NULL;
if( !wxRenameFile( tempfile, m_filename, true ) )
throw Exception::BadStream( m_filename, "Failed to move or copy the temporary archive to the destination filename." );
throw Exception::BadStream( m_filename )
.SetDiagMsg(L"Failed to move or copy the temporary archive to the destination filename.")
.SetUserMsg(_("The savestate was not properly saved. The temporary file was created successfully but could not be moved to its final resting place."));
Console.WriteLn( "(gzipThread) Data saved to disk without error." );
}

View File

@ -154,15 +154,14 @@ namespace Exception
// Exception used to perform an "errorless" termination of the app during OnInit
// procedures. This happens when a user cancels out of startup prompts/wizards.
//
class StartupAborted : public BaseException
class StartupAborted : public CancelEvent
{
public:
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
DEFINE_RUNTIME_EXCEPTION( StartupAborted, CancelEvent, "Startup initialization was aborted by the user." )
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
public:
StartupAborted( const wxString& reason )
{
// english messages only for this exception.
BaseException::InitBaseEx( msg_eng, msg_eng );
m_message_diag = L"Startup aborted: " + reason;
}
};

View File

@ -755,7 +755,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
if( overwrite )
{
if( wxFileExists( iniFilename ) && !wxRemoveFile( iniFilename ) )
throw Exception::AccessDenied( "Failed to overwrite settings; permission to file was denied." );
throw Exception::AccessDenied(iniFilename).SetBothMsgs(wxLt("Failed to overwrite existing settings file; permission was denied."));
}
// Bind into wxConfigBase to allow wx to use our config internally, and delete whatever

View File

@ -26,6 +26,7 @@
#include "CDVD/CDVD.h"
#include "Elfheader.h"
#include "Patch.h"
#include "R5900Exceptions.h"
__aligned16 SysMtgsThread mtgsThread;
__aligned16 AppCoreThread CoreThread;
@ -108,7 +109,13 @@ static void _Suspend()
void AppCoreThread::Suspend( bool isBlocking )
{
if( !GetSysExecutorThread().ProcessMethodSelf( _Suspend ) )
if (IsSelf())
{
// this should never fail...
bool result = GetSysExecutorThread().Rpc_TryInvokeAsync( _Suspend );
pxAssert(result);
}
else if (!GetSysExecutorThread().Rpc_TryInvoke( _Suspend ))
_parent::Suspend(true);
}
@ -392,12 +399,44 @@ void AppCoreThread::UploadStateCopy( const VmStateBuffer& copy )
paused_core.AllowResume();
}
static uint m_except_threshold = 0;
void AppCoreThread::ExecuteTaskInThread()
{
PostCoreStatus( CoreThread_Started );
m_except_threshold = 0;
_parent::ExecuteTaskInThread();
}
void AppCoreThread::DoCpuExecute()
{
try {
_parent::DoCpuExecute();
}
catch (BaseR5900Exception& ex)
{
Console.Error( ex.FormatMessage() );
// [TODO] : Debugger Hook!
if( ++m_except_threshold > 6 )
{
// If too many TLB Misses occur, we're probably going to crash and
// the game is probably running miserably.
m_except_threshold = 0;
//Suspend();
// [TODO] Issue error dialog to the user here...
Console.Error( "Too many execution errors. VM execution has been suspended!" );
// Hack: this keeps the EE thread from running more code while the SysExecutor
// thread catches up and signals it for suspension.
m_ExecMode = ExecMode_Closing;
}
}
}
// --------------------------------------------------------------------------------------
// BaseSysExecEvent_ScopedCore / SysExecEvent_CoreThreadClose / SysExecEvent_CoreThreadPause
// --------------------------------------------------------------------------------------

View File

@ -142,6 +142,8 @@ public:
virtual void UploadStateCopy( const VmStateBuffer& copy );
protected:
virtual void DoCpuExecute();
virtual void OnResumeReady();
virtual void OnResumeInThread( bool IsSuspended );
virtual void OnSuspendInThread();

View File

@ -48,8 +48,7 @@ protected:
public:
AppGameDatabase() {}
virtual ~AppGameDatabase() throw() {
// deque deletes its contents automatically.
Console.WriteLn( "(GameDB) Destroying..." );
Console.WriteLn( "(GameDB) Unloading..." );
}
AppGameDatabase& LoadFromFile(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial" );

View File

@ -138,7 +138,7 @@ void Pcsx2App::ReadUserModeSettings()
// first time startup, so give the user the choice of user mode:
FirstTimeWizard wiz( NULL );
if( !wiz.RunWizard( wiz.GetUsermodePage() ) )
throw Exception::StartupAborted( L"Startup aborted: User canceled FirstTime Wizard." );
throw Exception::StartupAborted( L"User canceled FirstTime Wizard." );
// Save user's new settings
IniSaver saver( *conf_usermode );
@ -166,7 +166,7 @@ void Pcsx2App::ReadUserModeSettings()
// If we skip this check, it's very likely that actions like creating Memory Cards will fail.
FirstTimeWizard wiz( NULL );
if( !wiz.RunWizard( /*wiz.GetPostUsermodePage()*/ wiz.GetUsermodePage() ) )
throw Exception::StartupAborted( L"Startup aborted: User canceled Configuration Wizard." );
throw Exception::StartupAborted( L"User canceled Configuration Wizard." );
// Save user's new settings
IniSaver saver( *conf_usermode );
@ -193,7 +193,9 @@ void Pcsx2App::DetectCpuAndUserMode()
{
// Note: due to memcpy_fast, we need minimum MMX even for interpreters. This will
// hopefully change later once we have a dynamically recompiled memcpy.
throw Exception::HardwareDeficiency(L"MMX Extensions not available.", _("PCSX2 requires cpu with MMX instruction to run."));
throw Exception::HardwareDeficiency()
.SetDiagMsg(L"Critical Failure: MMX Extensions not available.")
.SetUserMsg(_("MMX extensions are not available. PCSX2 requires cpu with MMX extension support to run."));
}
ReadUserModeSettings();
@ -260,8 +262,8 @@ void Pcsx2App::AllocateCoreStuffs()
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") );
exconf += 12;
exconf += exconf.Heading( pxE( ".Popup:RecompilerInit",
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" )
exconf += exconf.Heading( pxE( ".Popup:RecompilerInit:Header",
L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:" )
);
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
@ -269,63 +271,55 @@ void Pcsx2App::AllocateCoreStuffs()
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
);
exconf += scrollableTextArea | pxSizerFlags::StdExpand();
exconf += 6;
exconf += scrollableTextArea | pxExpand.Border(wxALL, 16);
if( !m_CoreAllocs->IsRecAvailable_EE() )
if( BaseException* ex = m_CoreAllocs->GetException_EE() )
{
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
g_Conf->EmuOptions.Recompiler.EnableEE = false;
scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.EnableEE = false;
}
if( !m_CoreAllocs->IsRecAvailable_IOP() )
if( BaseException* ex = m_CoreAllocs->GetException_IOP() )
{
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() ) {
scrollableTextArea->AppendText( L"* microVU0\n\n" );
if( BaseException* ex = m_CoreAllocs->GetException_MicroVU0() )
{
scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
}
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
if( BaseException* ex = m_CoreAllocs->GetException_MicroVU1() )
{
scrollableTextArea->AppendText( L"* microVU1\n\n" );
scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
if( BaseException* ex = m_CoreAllocs->GetException_SuperVU0() )
{
scrollableTextArea->AppendText( L"* SuperVU0\n\n" );
scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
}
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
if( BaseException* ex = m_CoreAllocs->GetException_SuperVU1() )
{
scrollableTextArea->AppendText( L"* SuperVU1\n\n" );
scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
}
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter();
exconf += exconf.Heading( pxE(".Popup:RecompilerInit:Footer",
L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. "
L"You may have to manually re-enable the recompilers listed above, if you resolve the errors." )
);
exconf.ShowModal();
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
L"These errors are the result of memory allocation failures (see the program log for details). "
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
L"These recompilers have been disabled and interpreters will be used in their place. "
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
);*/
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
// return false;
pxIssueConfirmation( exconf, MsgButtons().OK() );
}
}

View File

@ -37,33 +37,28 @@ namespace Exception
//
class CannotApplySettings : public BaseException
{
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings, BaseException )
DEFINE_EXCEPTION_MESSAGES( CannotApplySettings )
public:
bool IsVerbose;
bool IsVerbose;
protected:
BaseApplicableConfigPanel* m_Panel;
BaseApplicableConfigPanel* m_Panel;
protected:
CannotApplySettings() { IsVerbose = true; }
public:
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings )
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const char* msg=wxLt("Cannot apply new settings, one of the settings is invalid."), bool isVerbose = true )
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel )
{
BaseException::InitBaseEx( msg );
m_Panel = thispanel;
IsVerbose = isVerbose;
}
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const wxString& msg_eng, const wxString& msg_xlt )
{
BaseException::InitBaseEx( msg_eng, msg_xlt );
SetBothMsgs(wxLt("Cannot apply new settings, one of the settings is invalid."));
m_Panel = thispanel;
IsVerbose = true;
}
BaseApplicableConfigPanel* GetPanel()
{
return m_Panel;
}
virtual CannotApplySettings& Quiet() { IsVerbose = false; return *this; }
BaseApplicableConfigPanel* GetPanel() { return m_Panel; }
};
}

View File

@ -93,7 +93,7 @@ CpuUsageProviderMSW::CpuUsageProviderMSW()
throw Exception::RuntimeError( "(CpuUsageProviderMSW) CoInitializeSecurity failed: No good security packages! .. whatever tht means." );
case E_OUTOFMEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) CoInitializeSecurity failed with an unknown error code: %d", hr ), wxEmptyString );
@ -221,7 +221,7 @@ void CpuUsageProviderMSW::UpdateStats()
break;
case WBEM_E_OUT_OF_MEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) WMI Object Enumeration failed with an unknown error code: %d", hRes ), wxEmptyString );

View File

@ -104,14 +104,13 @@ bool FirstTimeWizard::UsermodePage::PrepForApply()
if( path.FileExists() )
{
// FIXME: There's already a file by the same name.. not sure what we should do here.
throw Exception::BadStream( path.ToString(),
L"Targeted documents folder is already occupied by a file.",
pxE( ".Error:DocsFolderFileConflict",
throw Exception::BadStream( path.ToString() )
.SetDiagMsg(L"Targeted documents folder is already occupied by a file.")
.SetUserMsg(pxE( ".Error:DocsFolderFileConflict",
L"PCSX2 cannot create a documents folder in the requested location. "
L"The path name matches an existing file. Delete the file or change the documents location, "
L"and then try again."
)
);
));
}
if( !path.Exists() )

View File

@ -308,7 +308,18 @@ void pxEvtHandler::ProcessEvent( SysExecEvent* evt )
}
}
bool pxEvtHandler::ProcessMethodSelf( FnType_Void* method )
bool pxEvtHandler::Rpc_TryInvokeAsync( FnType_Void* method )
{
if( wxThread::GetCurrentId() != m_OwnerThreadId )
{
PostEvent( new SysExecEvent_MethodVoid(method) );
return true;
}
return false;
}
bool pxEvtHandler::Rpc_TryInvoke( FnType_Void* method )
{
if( wxThread::GetCurrentId() != m_OwnerThreadId )
{

View File

@ -47,7 +47,6 @@ void GSPanel::InitDefaultAccelerators()
m_Accels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot");
m_Accels->Map( AAC( WXK_F8 ).Shift().Cmd(), "Sys_TakeSnapshot");
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle" );
//m_Accels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
m_Accels->Map( AAC( WXK_F11 ), "Sys_FreezeGS" );

View File

@ -121,16 +121,12 @@ void Panels::BiosSelectorPanel::Apply()
int sel = m_ComboBox->GetSelection();
if( sel == wxNOT_FOUND )
{
throw Exception::CannotApplySettings( this,
// English Log
L"User did not specify a valid BIOS selection.",
// Translated
pxE( ".Error:BIOS:InvalidSelection",
throw Exception::CannotApplySettings(this)
.SetDiagMsg(L"User did not specify a valid BIOS selection.")
.SetUserMsg( pxE( ".Error:BIOS:InvalidSelection",
L"Please select a valid BIOS. If you are unable to make a valid selection "
L"then press cancel to close the Configuration panel."
)
);
) );
}
g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox->GetClientData(sel)];

View File

@ -142,10 +142,9 @@ void Panels::GSWindowSettingsPanel::Apply()
long xr, yr;
if( !m_text_WindowWidth->GetValue().ToLong( &xr ) || !m_text_WindowHeight->GetValue().ToLong( &yr ) )
throw Exception::CannotApplySettings( this,
L"User submitted non-numeric window size parameters!",
_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<")
);
throw Exception::CannotApplySettings( this )
.SetDiagMsg(L"User submitted non-numeric window size parameters!")
.SetUserMsg(_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<"));
appconf.WindowSize.x = xr;
appconf.WindowSize.y = yr;

View File

@ -58,7 +58,7 @@ namespace Exception
class NotEnumerablePlugin : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, wxLt("File is not a PCSX2 plugin") );
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
};
}
@ -89,7 +89,7 @@ public:
: m_plugpath( plugpath )
{
if( !m_plugin.Load( m_plugpath ) )
throw Exception::BadStream( m_plugpath, "File is not a valid dynamic library." );
throw Exception::BadStream( m_plugpath ).SetBothMsgs("File is not a valid dynamic library.");
wxDoNotLogInThisScope please;
m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" );
@ -241,7 +241,8 @@ void ApplyOverValidStateEvent::InvokeEvent()
int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector:ConfirmShutdown" );
if( result == wxID_CANCEL )
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel(), "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false );
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel() ).Quiet()
.SetDiagMsg(L"Cannot apply settings: canceled by user because plugins changed while the emulation state was active.");
}
// --------------------------------------------------------------------------------------
@ -465,13 +466,9 @@ void Panels::PluginSelectorPanel::Apply()
{
wxString plugname( pi->GetShortname() );
throw Exception::CannotApplySettings( this,
// English Log
wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str() ),
// Translated
wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg()
);
throw Exception::CannotApplySettings( this )
.SetDiagMsg(wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str()) )
.SetUserMsg(wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg() );
}
g_Conf->BaseFilenames.Plugins[pid] = GetFilename((int)m_ComponentBoxes->Get(pid).GetClientData(sel));
@ -498,7 +495,7 @@ void Panels::PluginSelectorPanel::Apply()
try
{
if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() )
throw Exception::CannotApplySettings( this, "User canceled plugin load process.", false );
throw Exception::CannotApplySettings( this ).Quiet().SetDiagMsg(L"User canceled plugin load process.");
}
catch( Exception::PluginError& ex )
{
@ -506,15 +503,12 @@ void Panels::PluginSelectorPanel::Apply()
wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() );
throw Exception::CannotApplySettings( this,
// Diagnostic
ex.FormatDiagnosticMessage(),
// Translated
wxsFormat( _("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
throw Exception::CannotApplySettings( this )
.SetDiagMsg(ex.FormatDiagnosticMessage())
.SetUserMsg(wxsFormat(
_("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
plugname.c_str(), ex.FormatDisplayMessage().c_str()
) + GetApplyFailedMsg()
);
) + GetApplyFailedMsg());
}
}

View File

@ -144,9 +144,12 @@ void Panels::FramelimiterPanel::Apply()
}
catch( Exception::ParseError& )
{
throw Exception::CannotApplySettings( this,
wxLt("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.")
);
throw Exception::CannotApplySettings( this )
.SetDiagMsg(wxsFormat(
L"Error while parsing either NTSC or PAL framerate settings.\n\tNTSC Input = %s\n\tPAL Input = %s",
m_text_BaseNtsc->GetValue(), m_text_BasePal->GetValue()
) )
.SetUserMsg(_("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics."));
}
appfps.SanityCheck();

View File

@ -40,25 +40,41 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
thr.Read( ident );
if( strcmp(SavestateIdentString, ident) )
throw Exception::SaveStateLoadError( thr.GetStreamName(),
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
throw Exception::SaveStateLoadError( thr.GetStreamName() )
.SetDiagMsg(wxsFormat( L"Unrecognized file signature while loading savestate. [sig = %s]", ident ))
.SetUserMsg(_("This is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2."));
u32 savever;
thr.Read( savever );
if( (savever >> 16) != (g_SaveVersion >> 16) )
throw Exception::SaveStateLoadError( thr.GetStreamName(),
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
// Major version mismatch. Means we can't load this savestate at all. Support for it
// was removed entirely.
if( savever > g_SaveVersion )
throw Exception::SaveStateLoadError( thr.GetStreamName(),
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
);
throw Exception::SaveStateLoadError( thr.GetStreamName() )
.SetDiagMsg(wxsFormat( L"Savestate uses an unsupported or unknown savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
.SetUserMsg(_("Cannot load this savestate. The state is from an incompatible edition of PCSX2 that is either newer than this version, or is no longer supported."));
// check for a "minor" version incompatibility; which happens if the savestate being loaded is a newer version
// than the emulator recognizes. 99% chance that trying to load it will just corrupt emulation or crash.
if( (savever >> 16) != (g_SaveVersion >> 16) )
throw Exception::SaveStateLoadError( thr.GetStreamName() )
.SetDiagMsg(wxsFormat( L"Savestate uses an unknown (future?!) savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
.SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2."));
};
class gzError : public Exception::BadStream
{
DEFINE_STREAM_EXCEPTION( gzError, BadStream, wxLt("Invalid or corrupted gzip archive") )
};
class gzReadError : public gzError
{
};
class gzWriteError : public gzError
{
};
// --------------------------------------------------------------------------------------
@ -79,7 +95,7 @@ public:
: m_filename( filename )
{
if( NULL == (m_gzfp = gzopen( m_filename.ToUTF8(), "rb" )) )
throw Exception::CannotCreateStream( m_filename, "Cannot open file for reading." );
throw Exception::CannotCreateStream( m_filename ).SetDiagMsg(L"Cannot open file for reading.");
#if defined(ZLIB_VERNUM) && (ZLIB_VERNUM >= 0x1240)
gzbuffer(m_gzfp, 0x100000); // 1mb buffer for zlib internal operations
@ -97,7 +113,8 @@ public:
{
int result = gzread( m_gzfp, dest, size );
if( result == -1)
throw Exception::BadStream( m_filename, "Data read failed: Invalid or corrupted gzip archive." );
//throw Exception::gzError( m_filename );
throw Exception::BadStream( m_filename ).SetBothMsgs(wxLt("Data read failed: Invalid or corrupted gzip archive."));
if( (size_t)result < size )
throw Exception::EndOfStream( m_filename );
@ -136,7 +153,9 @@ protected:
ScopedCoreThreadPause paused_core;
if( !SysHasValidState() )
throw Exception::RuntimeError( L"Cannot complete state freeze request; the virtual machine state is reset.", _("You'll need to start a new virtual machine before you can save its state.") );
throw Exception::RuntimeError()
.SetDiagMsg(L"SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
.SetUserMsg(L"There is no active virtual machine state to download or save." );
memSavingState(m_dest_buffer).FreezeAll();

View File

@ -191,7 +191,8 @@ public:
void ProcessEvent( SysExecEvent* evt );
void ProcessEvent( SysExecEvent& evt );
bool ProcessMethodSelf( FnType_Void* method );
bool Rpc_TryInvokeAsync( FnType_Void* method );
bool Rpc_TryInvoke( FnType_Void* method );
void SetActiveThread();
protected:
@ -227,9 +228,14 @@ public:
void ProcessEvent( SysExecEvent* evt );
void ProcessEvent( SysExecEvent& evt );
bool ProcessMethodSelf( void (*evt)() )
bool Rpc_TryInvokeAsync( void (*evt)() )
{
return m_EvtHandler ? m_EvtHandler->ProcessMethodSelf( evt ) : false;
return m_EvtHandler ? m_EvtHandler->Rpc_TryInvokeAsync( evt ) : false;
}
bool Rpc_TryInvoke( void (*evt)() )
{
return m_EvtHandler ? m_EvtHandler->Rpc_TryInvoke( evt ) : false;
}
protected:

View File

@ -23,8 +23,9 @@
#define DIRENTRY_SIZE 16
//////////////////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------------------
// romdir structure (packing required!)
// --------------------------------------------------------------------------------------
//
#if defined(_MSC_VER)
# pragma pack(1)
@ -41,20 +42,16 @@ struct romdir
# pragma pack()
#endif
//////////////////////////////////////////////////////////////////////////////////////////
u32 BiosVersion; // Used in Memory, Misc, CDVD
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename, const wxString& msg_diag, const wxString& msg_user )
// --------------------------------------------------------------------------------------
// Exception::BiosLoadFailed (implementations)
// --------------------------------------------------------------------------------------
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename )
{
wxString diag( msg_user.IsEmpty() ?
L"BIOS has not been configured, or the configuration has been corrupted." : msg_user
);
wxString user( msg_user.IsEmpty() ?
_("The PS2 BIOS has not been configured, or the configuration has been corrupted. Please re-configure.") : msg_user.c_str()
);
m_message_diag = L"BIOS has not been configured, or the configuration has been corrupted.";
m_message_user = _("The PS2 BIOS could not be loaded. The BIOS has not been configured, or the configuration has been corrupted. Please re-configure.");
BaseException::InitBaseEx( diag, user );
StreamName = filename;
}
@ -156,10 +153,9 @@ void LoadBIOS()
s64 filesize = Path::GetFileSize( Bios );
if( filesize <= 0 )
{
throw Exception::BiosLoadFailed( Bios,
L"Configured BIOS file does not exist.",
_("The configured BIOS file does not exist. Please re-configure.")
);
throw Exception::BiosLoadFailed( Bios )
.SetDiagMsg(L"Configured BIOS file does not exist.")
.SetUserMsg(_("The configured BIOS file does not exist. Please re-configure."));
}
wxFile fp( Bios );
@ -168,10 +164,9 @@ void LoadBIOS()
BiosVersion = GetBiosVersion();
if( BiosVersion == -1 )
{
throw Exception::BiosLoadFailed( Bios,
L"Configured BIOS file is not a valid PS2 BIOS.",
_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure.")
);
throw Exception::BiosLoadFailed( Bios )
.SetDiagMsg(L"Configured BIOS file is not a valid PS2 BIOS.")
.SetUserMsg(_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure."));
}
Console.WriteLn("Bios Version %d.%d", BiosVersion >> 8, BiosVersion & 0xff);

View File

@ -19,12 +19,12 @@ namespace Exception
{
class BiosLoadFailed : public FileNotFound
{
public:
DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed )
DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed, FileNotFound )
DEFINE_EXCEPTION_MESSAGES( BiosLoadFailed )
DEFINE_STREAM_EXCEPTION_ACCESSORS( BiosLoadFailed )
explicit BiosLoadFailed( const wxString& filename,
const wxString& msg_diag=wxEmptyString,
const wxString& msg_user=wxEmptyString );
public:
BiosLoadFailed( const wxString& streamName );
};
}

View File

@ -42,7 +42,7 @@ using namespace vtlb_private;
#ifdef PCSX2_DEVBUILD
#define verify(x) {if (!(x)) { (*(u8*)0)=3; }}
#else
#define verify jASSUME
#define verify pxAssume
#endif
namespace vtlb_private
@ -221,32 +221,35 @@ void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value)
MemOp_w1<128,mem128_t>(mem,value);
}
/////////////////////////////////////////////////////////////////////////
// Error / TLB Miss Handlers
// ===========================================================================================
// Error / TLB Miss Handlers
// ===========================================================================================
// Important: Throwing exceptions isn't reliable *yet* because memory ops don't flush
// the PC prior to invoking the indirect handlers. That feature will likely be added to
// debug and dev builds soon, and later on to release builds as well.
//
static const char* _getModeStr( u32 mode )
{
return (mode==0) ? "read" : "write";
}
// Generates a tlbMiss Exception
// Note: Don't throw exceptions yet, they cause a crash when otherwise
// there would be a (slight) chance the game continues (rama).
static __forceinline void vtlb_Miss(u32 addr,u32 mode)
{
Console.Error( "vtlb miss : addr 0x%X, mode %d [%s]", addr, mode, _getModeStr(mode) );
//verify(false);
//throw R5900Exception::TLBMiss( addr, !!mode );
if( IsDevBuild )
Cpu->ThrowException( R5900Exception::TLBMiss( addr, !!mode ) );
else
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
}
// Just dies a horrible death for now.
// Eventually should generate a BusError exception.
// BusError exception: more serious than a TLB miss. If properly emulated the PS2 kernel
// itself would invoke a diagnostic/assertion screen that displays the cpu state at the
// time of the exception.
static __forceinline void vtlb_BusError(u32 addr,u32 mode)
{
Console.Error( "vtlb bus error : addr 0x%X, mode %d\n", addr, _getModeStr(mode) );
//verify(false);
throw R5900Exception::BusError( addr, !!mode );
// Throwing exceptions isn't reliable *yet* because memory ops don't flush
// the PC prior to invoking the indirect handlers.
if( IsDevBuild )
Cpu->ThrowException( R5900Exception::BusError( addr, !!mode ) );
else
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
}
///// Virtual Mapping Errors (TLB Miss)
@ -307,8 +310,9 @@ void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { Console.Er
void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.Error("vtlbDefaultPhyWrite128: 0x%X",addr); verify(false); }
//////////////////////////////////////////////////////////////////////////////////////////
// VTLB Public API -- Init/Term/RegisterHandler stuff
// ===========================================================================================
// VTLB Public API -- Init/Term/RegisterHandler stuff
// ===========================================================================================
//
// Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior
@ -582,7 +586,7 @@ void vtlb_Core_Alloc()
// Win32 just needs this, since malloc always maps below 2GB.
vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 );
if( vtlbdata.alloc_base == NULL )
throw Exception::OutOfMemory( "Fatal Error: could not allocate 42Meg buffer for PS2's mappable system ram." );
throw Exception::OutOfMemory( L"PS2 mappable system ram (42 megs)" );
#endif
}

View File

@ -26,30 +26,28 @@ void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode
{
case EINVAL:
pxFailDev( L"Invalid argument" );
throw Exception::Stream( streamname, "Invalid argument" );
throw Exception::Stream( streamname ).SetDiagMsg(L"Invalid argument" );
case EACCES: // Access denied!
throw Exception::AccessDenied( streamname );
case EMFILE: // Too many open files!
throw Exception::CannotCreateStream( streamname, "Too many open files" ); // File handle allocation failure
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files"); // File handle allocation failure
case EEXIST:
throw Exception::CannotCreateStream( streamname, "File already exists" );
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"File already exists");
case ENOENT: // File not found!
throw Exception::FileNotFound( streamname );
case EPIPE:
throw Exception::BadStream( streamname, "Broken pipe" );
throw Exception::BadStream( streamname ).SetDiagMsg(L"Broken pipe");
case EBADF:
throw Exception::BadStream( streamname, "Bad file number" );
throw Exception::BadStream( streamname ).SetDiagMsg(L"Bad file number");
default:
throw Exception::Stream( streamname,
wxsFormat( L"General file/stream error [errno: %d]", errcode )
);
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General file/stream error [errno: %d]", errcode ));
}
}
@ -70,22 +68,20 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
throw Exception::FileNotFound( streamname );
case ERROR_TOO_MANY_OPEN_FILES:
throw Exception::CannotCreateStream( streamname, "Too many open files" );
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files");
case ERROR_ACCESS_DENIED:
throw Exception::AccessDenied( streamname );
case ERROR_INVALID_HANDLE:
throw Exception::BadStream( streamname, "Stream object or handle is invalid" );
throw Exception::BadStream( streamname ).SetDiagMsg(L"Stream object or handle is invalid");
case ERROR_SHARING_VIOLATION:
throw Exception::AccessDenied( streamname, "Sharing violation" );
throw Exception::AccessDenied( streamname ).SetDiagMsg(L"Sharing violation");
default:
{
throw Exception::Stream( streamname,
wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error )
);
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error ));
}
}
}

View File

@ -19,35 +19,6 @@
#include "App.h"
#include "ConsoleLogger.h"
Exception::WinApiError::WinApiError( const char* msg )
{
ErrorId = GetLastError();
BaseException::InitBaseEx( msg );
}
wxString Exception::WinApiError::GetMsgFromWindows() const
{
if (!ErrorId)
return wxString();
const DWORD BUF_LEN = 2048;
TCHAR t_Msg[BUF_LEN];
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
}
wxString Exception::WinApiError::FormatDisplayMessage() const
{
return m_message_user + L"\n\n" + GetMsgFromWindows();
}
wxString Exception::WinApiError::FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\t" + GetMsgFromWindows();
}
// --------------------------------------------------------------------------------------
// Win32 Console Pipes
// As a courtesy and convenience, we redirect stdout/stderr to the console and logfile.
@ -102,7 +73,7 @@ protected:
continue;
}
throw Exception::WinApiError( "ReadFile from pipe failed." );
throw Exception::WinApiError().SetDiagMsg(L"ReadFile from pipe failed.");
}
if( u32_Read <= 3 )
@ -120,7 +91,7 @@ protected:
{
Yield();
if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) )
throw Exception::WinApiError( "Error peeking Pipe." );
throw Exception::WinApiError().SetDiagMsg(L"Error peeking Pipe.");
if( u32_avail == 0 ) break;
@ -190,10 +161,10 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
try
{
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
throw Exception::WinApiError( "CreatePipe failed." );
throw Exception::WinApiError().SetDiagMsg(L"CreatePipe failed.");
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
throw Exception::WinApiError( "SetStdHandle failed." );
throw Exception::WinApiError().SetDiagMsg(L"SetStdHandle failed.");
// Note: Don't use GetStdHandle to "confirm" the handle.
//
@ -224,7 +195,7 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
// the constructor, so re-pack a new exception:
Cleanup();
throw Exception::RuntimeError( ex.FormatDiagnosticMessage(), ex.FormatDisplayMessage() );
throw Exception::RuntimeError().SetDiagMsg( ex.FormatDiagnosticMessage() ).SetUserMsg( ex.FormatDisplayMessage() );
}
catch( BaseException& ex )
{

View File

@ -772,7 +772,7 @@ static void recAlloc()
recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" );
if( recMem == NULL )
throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." );
throw Exception::OutOfMemory( L"R3000A recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
@ -782,7 +782,7 @@ static void recAlloc()
m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 );
if( m_recBlockAlloc == NULL )
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." );
throw Exception::OutOfMemory( L"R3000A BASEBLOCK lookup tables" );
u8* curpos = m_recBlockAlloc;
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
@ -796,7 +796,7 @@ static void recAlloc()
}
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." );
throw Exception::OutOfMemory( L"R3000 InstCache." );
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
_DynGen_Dispatchers();

View File

@ -17,6 +17,8 @@
#include "Common.h"
#include "Memory.h"
#include "R5900Exceptions.h"
#include "R5900OpcodeTables.h"
#include "iR5900.h"
@ -61,6 +63,8 @@ bool g_cpuFlushedPC, g_recompilingDelaySlot, g_maySignalException;
#define X86
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
static ScopedPtr<BaseR5900Exception> m_vmException;
static u8 *recMem = NULL; // the recompiled blocks will be here
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
@ -534,10 +538,9 @@ static const uint m_recBlockAllocSize =
static void recThrowHardwareDeficiency( const wxChar* extFail )
{
throw Exception::HardwareDeficiency(
wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail),
wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
);
throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail))
.SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
}
static void recAlloc()
@ -569,7 +572,7 @@ static void recAlloc()
}
if( recMem == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating recompiled code buffer." );
throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
@ -579,7 +582,7 @@ static void recAlloc()
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
if( m_recBlockAlloc == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating BASEBLOCK tables." );
throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" );
u8* curpos = m_recBlockAlloc;
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
@ -595,7 +598,7 @@ static void recAlloc()
}
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating InstCache." );
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
// No errors.. Proceed with initialization:
@ -722,12 +725,14 @@ static void recExitExecution()
static void recCheckExecutionState()
{
if( eeRecIsReset || GetCoreThread().HasPendingStateChangeRequest() )
if( eeRecIsReset || m_vmException || GetCoreThread().HasPendingStateChangeRequest() )
{
recExitExecution();
}
}
static bool m_recExecutingCode = false;
static void recExecute()
{
// Implementation Notes:
@ -735,7 +740,9 @@ static void recExecute()
#if PCSX2_SEH
eeRecIsReset = false;
m_vmException = NULL;
g_EEFreezeRegs = true;
ScopedBool executing(m_recExecutingCode);
try {
EnterRecompiledCode();
@ -766,6 +773,8 @@ static void recExecute()
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
}
#endif
if(m_vmException) m_vmException->Rethrow();
}
////////////////////////////////////////////////////
@ -1813,6 +1822,18 @@ StartRecomp:
s_pCurBlockEx = NULL;
}
// The only *safe* way to throw exceptions from the context of recompiled code.
// The exception is cached and the recompiler is exited safely using either an
// SEH unwind (MSW) or setjmp/longjmp (GCC).
void recThrowException( const BaseR5900Exception& ex )
{
if (!m_recExecutingCode) ex.Rethrow();
m_vmException = ex.Clone();
recExitExecution();
}
R5900cpu recCpu =
{
recAlloc,
@ -1823,5 +1844,6 @@ R5900cpu recCpu =
recExecute,
recCheckExecutionState,
recThrowException,
recClear,
};

View File

@ -17,6 +17,7 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include <deque>
#include "microVU.h"
//------------------------------------------------------------------
@ -64,10 +65,9 @@ const __aligned(32) mVU_Globals mVUglob = {
//------------------------------------------------------------------
_f void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
throw Exception::HardwareDeficiency(
wxsFormat( L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail),
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
);
throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
.SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
}
// Only run this once per VU! ;)
@ -96,7 +96,7 @@ _f void mVUinit(VURegs* vuRegsPtr, int vuIndex) {
}
mVU->dispCache = SysMmapEx(NULL, mVUdispCacheSize, 0, (mVU->index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
if (!mVU->dispCache) throw Exception::OutOfMemory("microVU Error: Failed to allocate dispatcher memory!");
if (!mVU->dispCache) throw Exception::OutOfMemory( mVU->index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(mVU->dispCache, 0xcc, mVUdispCacheSize);
// Setup Entrance/Exit Points
@ -165,12 +165,8 @@ void mVUresizeCache(mV, u32 size) {
if (size > (u32)mVUcacheMaxSize) { if (mVU->cacheSize==mVUcacheMaxSize) return; size = mVUcacheMaxSize; }
if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb);
// Give SysMmapEx a NULL and let the OS pick the memory for us: mVU can work with any
// address the operating system gives us, and unlike the EE/IOP there's not much convenience
// to debugging if the address is known anyway due to mVU's complex memory layouts (caching).
u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1" : "Micro VU0"));
if(!cache && !mVU->cache) throw Exception::OutOfMemory("microVU Error: Failed to allocate recompiler memory!");
u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache"));
if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) );
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); return; }
if (mVU->cache) {
HostSys::Munmap(mVU->cache, mVU->cacheSize);
@ -272,7 +268,7 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
microProgramQuick& quick = mVU->prog.quick[startPC/8];
microProgramList& list = mVU->prog.prog [startPC/8];
if(!quick.prog) { // If null, we need to search for new program
deque<microProgram*>::iterator it = list.list->begin();
deque<microProgram*>::iterator it( list.list->begin() );
for ( ; it != list.list->end(); it++) {
if (mVUcmpProg<vuIndex>(*it[0], 0)) {
quick.block = it[0]->block[startPC/8];
@ -282,15 +278,30 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
return mVUentryGet(mVU, quick.block, startPC, pState);
}
}
// If cleared and program not found, make a new program instance
mVU->prog.cleared = 0;
mVU->prog.isSame = 1;
mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8);
void* entryPoint = mVUblockFetch(mVU, startPC, pState);
quick.block = mVU->prog.cur->block[startPC/8];
quick.prog = mVU->prog.cur;
list.list->push_front(mVU->prog.cur);
return entryPoint;
// Exception note: It's bad news if the recompiler throws any exceptions, so we have a clause to
// assert if an exception occurs. The rec should be pretty much exception safe, except for
// critical errors that would result in a crash regardless.
try {
mVU->prog.cleared = 0;
mVU->prog.isSame = 1;
mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8);
void* entryPoint = mVUblockFetch(mVU, startPC, pState);
quick.block = mVU->prog.cur->block[startPC/8];
quick.prog = mVU->prog.cur;
list.list->push_front(mVU->prog.cur);
return entryPoint;
} catch( BaseException& ex ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + ex.FormatDiagnosticMessage(), mVU->index) );
} catch( std::exception& ex ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + Exception::RuntimeError(ex).FormatDiagnosticMessage(), mVU->index) );
}
return NULL;
}
// If list.quick, then we've already found and recompiled the program ;)
mVU->prog.isSame = -1;

View File

@ -33,7 +33,7 @@ protected:
void alloc(int size) {
mData = SysMmapEx(NULL, size, 0, "nVif_BlockBuffer");
if (!mData) throw Exception::OutOfMemory("nVif Error: Failed to allocate recompiler memory!");
if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)");
clear();
}
void dealloc(u8* &dPtr, int size) {

View File

@ -83,8 +83,7 @@ public:
if( bucket.Chain = (T*)_aligned_realloc( bucket.Chain, sizeof(T)*(bucket.Size+1), 16), bucket.Chain==NULL ) {
throw Exception::OutOfMemory(
wxsFormat(L"Out of memory re-allocating hash bucket (bucket size=%d)", bucket.Size+1),
wxEmptyString
wxsFormat(L"HashBucket Chain (bucket size=%d)", bucket.Size+1)
);
}
memcpy_const(&bucket.Chain[bucket.Size++], &dataPtr, sizeof(T));

View File

@ -2008,8 +2008,10 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr)
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
pDest = &Path1Buffer[Path1WritePos*16];
pxAssumeMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
//DevCon.Warning("Storing size %x PATH 1", size);
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce

View File

@ -360,13 +360,13 @@ static void SuperVUAlloc(int vuindex)
if (s_recVUMem == NULL)
{
throw Exception::VirtualMemoryMapConflict(
// untranslated diagnostic msg, use exception's default for translation
wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ),
// Translated message
_("Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory ranges required.")
);
throw Exception::VirtualMemoryMapConflict()
.SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ))
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
L"ranges required, and will not be available for use. This is not a critical error, since "
L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
));
}
ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE);
@ -453,7 +453,7 @@ void SuperVUReset(int vuindex)
if (s_recVUMem == NULL)
return;
//jASSUME( s_recVUMem != NULL );
//pxAssume( s_recVUMem != NULL );
if (vuindex < 0)
{
@ -470,7 +470,6 @@ void SuperVUReset(int vuindex)
else
{
DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex);
list<VuFunctionHeader*>::iterator it;
if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8));
if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8));