Merge pull request #431 from samisalreadytaken/dev

vscript saverestore and debugger fixes
This commit is contained in:
Blixibon 2025-07-23 22:18:01 -05:00 committed by GitHub
commit 734130a497
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 654 additions and 322 deletions

View File

@ -5146,6 +5146,11 @@ bool CScriptConvarAccessor::Init()
AddBlockedConVar( "cl_allowdownload" ); AddBlockedConVar( "cl_allowdownload" );
AddBlockedConVar( "cl_allowupload" ); AddBlockedConVar( "cl_allowupload" );
AddBlockedConVar( "cl_downloadfilter" ); AddBlockedConVar( "cl_downloadfilter" );
#ifdef GAME_DLL
AddBlockedConVar( "script_connect_debugger_on_mapspawn" );
#else
AddBlockedConVar( "script_connect_debugger_on_mapspawn_client" );
#endif
return true; return true;
} }

View File

@ -106,6 +106,7 @@
} while(0) } while(0)
#endif #endif
#define Verify( x ) Assert(x) #define Verify( x ) Assert(x)
#define STATIC_ASSERT( x ) static_assert( x, #x )
#else #else
#define DebuggerBreak() ((void)0) #define DebuggerBreak() ((void)0)
#define Assert( x ) ((void)0) #define Assert( x ) ((void)0)
@ -113,12 +114,15 @@
#define AssertMsg1( x, msg, a1 ) ((void)0) #define AssertMsg1( x, msg, a1 ) ((void)0)
#define AssertMsg2( x, msg, a1, a2 ) ((void)0) #define AssertMsg2( x, msg, a1, a2 ) ((void)0)
#define Verify( x ) x #define Verify( x ) x
#define STATIC_ASSERT( x )
#endif // _DEBUG #endif // _DEBUG
#endif #endif
#include <tier0/dbg.h> #include <tier0/dbg.h>
#define STATIC_ASSERT COMPILE_TIME_ASSERT
// Misdefined for GCC in platform.h // Misdefined for GCC in platform.h
#undef UNREACHABLE #undef UNREACHABLE

View File

@ -275,9 +275,13 @@ static inline void PutStr( CBuffer *buffer, const string_t &str )
#ifdef SQDBG_VALIDATE_SENT_MSG #ifdef SQDBG_VALIDATE_SENT_MSG
for ( unsigned int i = 0; i < str.len; i++ ) for ( unsigned int i = 0; i < str.len; i++ )
{ {
AssertMsg( IN_RANGE_CHAR( str.ptr[i], 0x20, 0x7E ) && if ( str.ptr[i] == '\\' && ( str.ptr[i+1] == '\\' || str.ptr[i+1] == '\"' ) )
( ( str.ptr[i] != '\\' && str.ptr[i] != '\"' ) || ( i && str.ptr[i-1] == '\\' ) ), {
"control char in json string" ); i++;
continue;
}
AssertMsg( str.ptr[i] != '\\' && IN_RANGE_CHAR( str.ptr[i], 0x20, 0x7E ), "control char in json string" );
} }
#endif #endif
} }
@ -433,7 +437,7 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
idx += printhex< true, false >( idx += printhex< true, false >(
mem + idx, mem + idx,
buffer->Capacity() - idx, buffer->Capacity() - idx,
(SQChar)*(unsigned char*)c ); (SQUnsignedChar)*(unsigned char*)c );
} }
} }
} }
@ -503,6 +507,7 @@ static inline void PutInt( CBuffer *buffer, I val )
template < bool padding, typename I > template < bool padding, typename I >
static inline void PutHex( CBuffer *buffer, I val ) static inline void PutHex( CBuffer *buffer, I val )
{ {
STATIC_ASSERT( IS_UNSIGNED( I ) );
buffer->base.Ensure( buffer->Size() + countdigits<16>( val ) + 1 ); buffer->base.Ensure( buffer->Size() + countdigits<16>( val ) + 1 );
int len = printhex< padding >( buffer->Base() + buffer->Size(), buffer->Capacity() - buffer->Size(), val ); int len = printhex< padding >( buffer->Base() + buffer->Size(), buffer->Capacity() - buffer->Size(), val );
buffer->size += len; buffer->size += len;
@ -699,7 +704,7 @@ public:
} }
else else
{ {
PutHex< false >( m_pBuffer, val ); PutHex< false >( m_pBuffer, cast_unsigned( I, val ) );
} }
PutChar( m_pBuffer, ']' ); PutChar( m_pBuffer, ']' );
PutChar( m_pBuffer, '\"' ); PutChar( m_pBuffer, '\"' );
@ -850,7 +855,7 @@ private:
else else
{ {
buf = m_Allocator->Alloc(5); buf = m_Allocator->Alloc(5);
int i = printhex< true, true, false >( buf, 5, token ); int i = printhex< true, true, false >( buf, 5, (unsigned char)token );
Assert( i == 4 ); Assert( i == 4 );
buf[i] = 0; buf[i] = 0;
} }
@ -877,6 +882,24 @@ private:
m_error[len] = 0; m_error[len] = 0;
} }
bool IsValue( char token )
{
switch ( token )
{
case Token_String:
case Token_Integer:
case Token_Float:
case Token_False:
case Token_True:
case Token_Null:
case Token_Table:
case Token_Array:
return true;
default:
return false;
}
}
char NextToken( string_t &token ) char NextToken( string_t &token )
{ {
while ( m_cur < m_end ) while ( m_cur < m_end )
@ -1206,7 +1229,7 @@ err_eof:
type = NextToken( token ); type = NextToken( token );
type = ParseValue( type, token, &kv->val ); type = ParseValue( type, token, &kv->val );
if ( type == Token_Error ) if ( !IsValue( type ) )
{ {
SetError( "invalid token %s @ %i", Char(type), Index() ); SetError( "invalid token %s @ %i", Char(type), Index() );
return Token_Error; return Token_Error;
@ -1239,7 +1262,7 @@ err_eof:
for (;;) for (;;)
{ {
if ( type == Token_Error ) if ( !IsValue( type ) )
{ {
SetError( "expected '%c', got %s @ %i", ']', Char(type), Index() ); SetError( "expected '%c', got %s @ %i", ']', Char(type), Index() );
return Token_Error; return Token_Error;
@ -1315,7 +1338,7 @@ err_eof:
value->type = JSON_NULL; value->type = JSON_NULL;
return type; return type;
default: default:
return type; return Token_Error;
} }
} }
}; };

View File

@ -842,7 +842,7 @@ public:
m_pRecvBufPtr( m_pRecvBuf ), m_pRecvBufPtr( m_pRecvBuf ),
m_bWSAInit( false ) m_bWSAInit( false )
{ {
Assert( sizeof(m_pRecvBuf) <= ( 1 << ( sizeof(CMessagePool::message_t::len) * 8 ) ) ); STATIC_ASSERT( sizeof(m_pRecvBuf) <= ( 1 << ( sizeof(CMessagePool::message_t::len) * 8 ) ) );
} }
}; };

View File

@ -5,7 +5,7 @@
// Squirrel Debugger // Squirrel Debugger
// //
#define SQDBG_SV_VER 5 #define SQDBG_SV_VER 6
#include "sqdbg.h" #include "sqdbg.h"
@ -116,6 +116,7 @@ void sqdbg_sleep( int ms )
#define memzero(p) memset( (char*)(p), 0, sizeof(*(p)) ) #define memzero(p) memset( (char*)(p), 0, sizeof(*(p)) )
#define ALIGN(v, a) (((v) + ((a)-1)) & ~((a)-1)) #define ALIGN(v, a) (((v) + ((a)-1)) & ~((a)-1))
#define ROUND(v, a) ((v) + (a) - (v) % (a))
#ifndef _WIN32 #ifndef _WIN32
#undef offsetof #undef offsetof
@ -137,13 +138,23 @@ void sqdbg_sleep( int ms )
#define _SC(s) s #define _SC(s) s
#endif #endif
#if defined(SQUNICODE) && !defined(WCHAR_SIZE) #ifdef SQUNICODE
#ifdef _WIN32 #ifdef _WIN32
#ifndef WCHAR_SIZE
#define WCHAR_SIZE 2 #define WCHAR_SIZE 2
#endif
typedef uint16_t SQUnsignedChar;
#else #else
#ifndef WCHAR_SIZE
#define WCHAR_SIZE 4 #define WCHAR_SIZE 4
#endif #endif
typedef uint32_t SQUnsignedChar;
#endif #endif
#else
typedef unsigned char SQUnsignedChar;
#endif
STATIC_ASSERT( sizeof(SQChar) == sizeof(SQUnsignedChar) );
#ifndef scstrlen #ifndef scstrlen
#ifdef SQUNICODE #ifdef SQUNICODE
@ -272,10 +283,14 @@ void sqdbg_sleep( int ms )
#define SUPPORTS_DEREF_OP #define SUPPORTS_DEREF_OP
#if SQUIRREL_VERSION_NUMBER >= 300 #if SQUIRREL_VERSION_NUMBER >= 300
#define CHAINABLE_FUNCPROTO #define ACCESSIBLE_FUNCPROTO
#endif #endif
#endif #endif
#if defined(SQDBG_SUPPORTS_FUNCPROTO_LIST) && !defined(ACCESSIBLE_FUNCPROTO)
#define ACCESSIBLE_FUNCPROTO
#endif
#include "str.h" #include "str.h"
#include "json.h" #include "json.h"
#include "protocol.h" #include "protocol.h"
@ -641,12 +656,9 @@ public:
Assert( vm->_top == top ); Assert( vm->_top == top );
} }
}; };
#define STACKCHECK( vm ) CStackCheck stackcheck( vm )
#else #else
class CStackCheck #define STACKCHECK( vm ) (void)0
{
public:
CStackCheck( HSQUIRRELVM ) {}
};
#endif #endif
@ -659,7 +671,6 @@ public:
typedef unsigned int hgroup_t; typedef unsigned int hgroup_t;
static const hnode_t INVALID_HANDLE = (hnode_t)-1; static const hnode_t INVALID_HANDLE = (hnode_t)-1;
#pragma pack(push, 4)
struct node_t struct node_t
{ {
void *func; void *func;
@ -669,7 +680,6 @@ public:
sample_t sampleStart; sample_t sampleStart;
hnode_t id; hnode_t id;
}; };
#pragma pack(pop)
struct nodetag_t struct nodetag_t
{ {
@ -1118,7 +1128,7 @@ public:
if ( tag ) if ( tag )
{ {
return STRLEN(PROF_GROUP_OUTPUT_TEMPLATE) + return STRLEN(PROF_GROUP_OUTPUT_TEMPLATE) +
ALIGN( tag->_len, PROF_GROUP_NAME_LEN_ALIGNMENT ) + ROUND( tag->_len, PROF_GROUP_NAME_LEN_ALIGNMENT ) +
1; 1;
} }
@ -1203,7 +1213,7 @@ public:
memcpy( buf, group->tag->_val, sq_rsl(len) ); memcpy( buf, group->tag->_val, sq_rsl(len) );
buf += len; size -= len; buf += len; size -= len;
for ( int i = ALIGN( len, PROF_GROUP_NAME_LEN_ALIGNMENT ) - len; i-- > 0; ) for ( int i = ROUND( len, PROF_GROUP_NAME_LEN_ALIGNMENT ) - len; i-- > 0; )
{ {
*buf++ = ' '; *buf++ = ' ';
size--; size--;
@ -1972,6 +1982,9 @@ typedef enum
VARREF_INSTRUCTIONS, VARREF_INSTRUCTIONS,
VARREF_OUTERS, VARREF_OUTERS,
VARREF_LITERALS, VARREF_LITERALS,
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
VARREF_FUNCTIONS,
#endif
VARREF_METAMETHODS, VARREF_METAMETHODS,
VARREF_ATTRIBUTES, VARREF_ATTRIBUTES,
VARREF_CALLSTACK, VARREF_CALLSTACK,
@ -1993,6 +2006,9 @@ inline bool IsObjectRef( EVARREF type )
type == VARREF_INSTRUCTIONS || type == VARREF_INSTRUCTIONS ||
type == VARREF_OUTERS || type == VARREF_OUTERS ||
type == VARREF_LITERALS || type == VARREF_LITERALS ||
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
type == VARREF_FUNCTIONS ||
#endif
type == VARREF_METAMETHODS || type == VARREF_METAMETHODS ||
type == VARREF_ATTRIBUTES || type == VARREF_ATTRIBUTES ||
type == VARREF_CALLSTACK ); type == VARREF_CALLSTACK );
@ -2079,6 +2095,9 @@ struct objref_t
DELEGABLE_META, DELEGABLE_META,
CUSTOMMEMBER, CUSTOMMEMBER,
STACK, STACK,
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
FUNCPROTO,
#endif
INT, INT,
VIRTUAL_REF, VIRTUAL_REF,
VIRTUAL_SIZE, VIRTUAL_SIZE,
@ -3022,7 +3041,7 @@ void SQDebugServer::Attach( HSQUIRRELVM vm )
sq_addref( m_pRootVM, &m_EnvGetVal ); sq_addref( m_pRootVM, &m_EnvGetVal );
{ {
CStackCheck stackcheck( m_pRootVM ); STACKCHECK( m_pRootVM );
SQObjectPtr ref; SQObjectPtr ref;
sqdbg_get_debugger_ref( m_pRootVM, ref ); sqdbg_get_debugger_ref( m_pRootVM, ref );
@ -3700,12 +3719,12 @@ void SQDebugServer::ProcessRequest( const json_table_t &table, int seq )
ProfSwitchThread( m_pCurVM ); ProfSwitchThread( m_pCurVM );
#endif #endif
OnRequest_RestartFrame( *arguments, seq );
RestoreCachedInstructions(); RestoreCachedInstructions();
ClearCachedInstructions(); ClearCachedInstructions();
RemoveReturnValues(); RemoveReturnValues();
OnRequest_RestartFrame( *arguments, seq );
} }
#endif #endif
else if ( command.IsEqualTo( "gotoTargets" ) ) else if ( command.IsEqualTo( "gotoTargets" ) )
@ -3735,12 +3754,12 @@ void SQDebugServer::ProcessRequest( const json_table_t &table, int seq )
ProfSwitchThread( m_pCurVM ); ProfSwitchThread( m_pCurVM );
#endif #endif
OnRequest_Goto( *arguments, seq );
RestoreCachedInstructions(); RestoreCachedInstructions();
ClearCachedInstructions(); ClearCachedInstructions();
RemoveReturnValues(); RemoveReturnValues();
OnRequest_Goto( *arguments, seq );
} }
else if ( command.IsEqualTo( "next" ) ) else if ( command.IsEqualTo( "next" ) )
{ {
@ -4227,7 +4246,7 @@ void SQDebugServer::OnRequest_SetFunctionBreakpoints( const json_table_t &argume
int line = 0; int line = 0;
// function source: funcname,filename:line // function source: funcname,filename:line
for ( int j = name.len - 1; j > 1; j-- ) for ( int j = name.len - 1; j >= 0; j-- )
{ {
if ( !line && name.ptr[j] == ':' ) if ( !line && name.ptr[j] == ':' )
{ {
@ -5341,7 +5360,7 @@ static void Escape( char *dst, unsigned int *len, unsigned int size )
break; break;
} }
SQChar val = (SQChar)((unsigned char*)dst)[0]; SQUnsignedChar val = (SQUnsignedChar)((unsigned char*)dst)[0];
_memmove( dst + 2 + sizeof(SQChar) * 2, _memmove( dst + 2 + sizeof(SQChar) * 2,
dst + 1, dst + 1,
@ -5699,21 +5718,21 @@ getfloat:
char *buf = ScratchPad( size ); char *buf = ScratchPad( size );
int len; int len;
if ( _integer(obj) > (SQInteger)( 1 << ( ( sizeof(SQChar) << 3 ) - 1 ) ) ) // Allow both signed and unsigned char values ( -1 == 255, -128 == 128, -127 == 129 )
if ( _integer(obj) >
(SQInteger)( (SQUnsignedChar)-1 >> (int)( sizeof(SQChar) >= sizeof(SQInteger) ) ) ||
_integer(obj) <
(SQInteger)-( ( (SQUnsignedChar)-1 >> 1 ) + 1 ) )
{ {
len = printint( buf, size, _integer(obj) ); len = printint( buf, size, _integer(obj) );
return { buf, (unsigned int)len }; return { buf, (unsigned int)len };
} }
SQChar ch = (SQChar)_integer(obj); SQUnsignedChar ch = (SQUnsignedChar)_integer(obj);
if ( !( flags & kFS_Hexadecimal ) ) if ( !( flags & kFS_Hexadecimal ) )
{ {
#ifdef SQUNICODE len = printint( buf, size, (SQUnsignedInteger)ch );
len = printint( buf, size, ch );
#else
len = printint( buf, size, (unsigned char)ch );
#endif
} }
else else
{ {
@ -5734,9 +5753,9 @@ getfloat:
buf[len++] = (char)ch; buf[len++] = (char)ch;
} }
#ifdef SQUNICODE #ifdef SQUNICODE
else if ( IsValidUnicode( &ch, 1 ) ) else if ( IsValidUnicode( (SQChar*)&ch, 1 ) )
{ {
len += SQUnicodeToUTF8( buf + len, size - len - 1, &ch, 1 ); len += SQUnicodeToUTF8( buf + len, size - len - 1, (SQChar*)&ch, 1 );
} }
#endif #endif
else else
@ -5745,7 +5764,7 @@ getfloat:
buf[len++] = 'x'; buf[len++] = 'x';
#ifdef SQUNICODE #ifdef SQUNICODE
if ( ch <= (SQChar)0xFF ) if ( ch <= 0xFF )
{ {
len += printhex< true, false, false >( buf + len, size, (unsigned char)ch ); len += printhex< true, false, false >( buf + len, size, (unsigned char)ch );
} }
@ -5945,7 +5964,7 @@ getfloat:
} }
else else
{ {
buf.PutHex( _table(obj)->CountUsed(), false ); buf.PutHex( (SQUnsignedInteger)_table(obj)->CountUsed(), false );
} }
buf.Put('}'); buf.Put('}');
@ -6056,6 +6075,9 @@ getfloat:
} }
case OT_CLOSURE: case OT_CLOSURE:
case OT_NATIVECLOSURE: case OT_NATIVECLOSURE:
#ifdef ACCESSIBLE_FUNCPROTO
case OT_FUNCPROTO:
#endif
{ {
const SQObjectPtr *name; const SQObjectPtr *name;
@ -6063,10 +6085,17 @@ getfloat:
{ {
name = &_fp(_closure(obj)->_function)->_name; name = &_fp(_closure(obj)->_function)->_name;
} }
else else if ( sq_type(obj) == OT_NATIVECLOSURE )
{ {
name = &_nativeclosure(obj)->_name; name = &_nativeclosure(obj)->_name;
} }
#ifdef ACCESSIBLE_FUNCPROTO
else if ( sq_type(obj) == OT_FUNCPROTO )
{
name = &_funcproto(obj)->_name;
}
#endif
else UNREACHABLE();
if ( sq_type(*name) == OT_STRING ) if ( sq_type(*name) == OT_STRING )
{ {
@ -6195,7 +6224,7 @@ SQString *SQDebugServer::GetLocalVarName( const SQFunctionProto *func, const SQI
const SQLocalVarInfo &var = func->_localvarinfos[i]; const SQLocalVarInfo &var = func->_localvarinfos[i];
if ( (unsigned int)var._pos == pos && if ( (unsigned int)var._pos == pos &&
var._start_op <= ip + s_nTargetAssignment && var._end_op + 1 >= ip ) var._start_op <= ip + s_nTargetAssignment && var._end_op >= ip )
{ {
return sq_type(var._name) == OT_STRING ? _string(var._name) : NULL; return sq_type(var._name) == OT_STRING ? _string(var._name) : NULL;
} }
@ -6235,12 +6264,48 @@ void SQDebugServer::PrintOuter( const SQFunctionProto *func, int pos, stringbufe
void SQDebugServer::PrintLiteral( const SQFunctionProto *func, int pos, stringbufext_t &buf ) void SQDebugServer::PrintLiteral( const SQFunctionProto *func, int pos, stringbufext_t &buf )
{ {
string_t val = GetValue( func->_literals[pos] ); const SQObjectPtr &val = func->_literals[pos];
if ( val.len > 64 ) switch ( sq_type(val) )
val.len = 64; {
case OT_INTEGER:
case OT_FLOAT:
case OT_BOOL:
case OT_NULL:
case OT_STRING:
{
string_t str = GetValue( val );
buf.Puts( val ); if ( str.len > 64 )
str.len = 64;
buf.Puts( str );
break;
}
case OT_CLASS:
case OT_INSTANCE:
{
const classdef_t *def =
FindClassDef( sq_type(val) == OT_CLASS ? _class(val) : _instance(val)->_class );
if ( def && def->name.ptr )
{
buf.Puts( GetType( val ) );
buf.Put( ' ' );
string_t str;
str.Assign( def->name.ptr + FMT_PTR_LEN + 1, def->name.len - FMT_PTR_LEN - 1 );
if ( str.len > 64 - 9 )
str.len = 64 - 9;
buf.Puts( str );
break;
}
}
default:
buf.Puts( GetType( val ) );
}
} }
void SQDebugServer::PrintStackTarget( const SQFunctionProto *func, const SQInstruction *instr, void SQDebugServer::PrintStackTarget( const SQFunctionProto *func, const SQInstruction *instr,
@ -6286,10 +6351,20 @@ void SQDebugServer::DescribeInstruction( const SQInstruction *instr, const SQFun
switch ( instr->op ) switch ( instr->op )
{ {
case _OP_LOADNULLS: case _OP_LOADNULLS:
{
if ( instr->_arg1 == 1 )
{ {
PrintStackVar( func, instr, instr->_arg0, buf ); PrintStackVar( func, instr, instr->_arg0, buf );
}
else
{
buf.Put( '[' );
buf.PutInt( (int)instr->_arg0 );
buf.Put( ']' );
buf.Put( ' ' ); buf.Put( ' ' );
buf.PutInt( instr->_arg1 ); buf.PutInt( instr->_arg1 );
}
break; break;
} }
case _OP_LOADINT: case _OP_LOADINT:
@ -7849,6 +7924,13 @@ bool SQDebugServer::Get( const objref_t &obj, SQObjectPtr &value )
return false; return false;
} }
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
case objref_t::FUNCPROTO:
{
value = *obj.ptr;
return true;
}
#endif
case objref_t::INT: case objref_t::INT:
{ {
value = (SQInteger)obj.val; value = (SQInteger)obj.val;
@ -8036,6 +8118,23 @@ bool SQDebugServer::Set( const objref_t &obj, const SQObjectPtr &value )
return false; return false;
} }
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
case objref_t::FUNCPROTO:
{
if ( sq_type(value) == OT_FUNCPROTO )
{
*obj.ptr = value;
return true;
}
else if ( sq_type(value) == OT_CLOSURE )
{
*obj.ptr = _closure(value)->_function;
return true;
}
return false;
}
#endif
default: UNREACHABLE(); default: UNREACHABLE();
} }
} }
@ -8396,9 +8495,6 @@ public:
int opbufidx = -1; int opbufidx = -1;
int unaryidx = -1; int unaryidx = -1;
// Recursively parsing unary operators adds the complexity
// of keeping track of and reverting to the previous token
// Using an operator stack is simpler but limits the amount
unsigned char unarybuf[ SQDBG_COMPILER_MAX_UNARY_STACK ]; unsigned char unarybuf[ SQDBG_COMPILER_MAX_UNARY_STACK ];
unsigned char opbuf[2]; unsigned char opbuf[2];
char deleteop = 0; char deleteop = 0;
@ -10486,7 +10582,7 @@ private:
{ {
if ( ISREFCOUNTED( sq_type(val) ) && sq_type(val) != OT_STRING ) if ( ISREFCOUNTED( sq_type(val) ) && sq_type(val) != OT_STRING )
{ {
val = (SQInteger)_refcounted(val); val = (SQInteger)(uintptr_t)_refcounted(val);
return true; return true;
} }
else if ( sq_type(val) == OT_NULL ) else if ( sq_type(val) == OT_NULL )
@ -11189,6 +11285,7 @@ private:
token._string.IsEqualTo("throw") || token._string.IsEqualTo("throw") ||
token._string.IsEqualTo("static") || token._string.IsEqualTo("static") ||
token._string.IsEqualTo("return") || token._string.IsEqualTo("return") ||
token._string.IsEqualTo("resume") ||
token._string.IsEqualTo("foreach") || token._string.IsEqualTo("foreach") ||
token._string.IsEqualTo("function") ) token._string.IsEqualTo("function") )
{ {
@ -12099,11 +12196,8 @@ bool SQDebugServer::GetObj_Var( const SQObjectPtr &var, const SQObjectPtr &key,
_integer(key) >= 0 && _integer(key) < _string(var)->_len ) _integer(key) >= 0 && _integer(key) < _string(var)->_len )
{ {
out.type = (objref_t::EOBJREF)( objref_t::INT | objref_t::READONLY ); out.type = (objref_t::EOBJREF)( objref_t::INT | objref_t::READONLY );
#ifdef SQUNICODE // Sign will be extended
out.val = (int)_string(var)->_val[ _integer(key) ]; out.val = (int)_string(var)->_val[ _integer(key) ];
#else
out.val = (int)(unsigned char)_string(var)->_val[ _integer(key) ];
#endif
value = (SQInteger)out.val; value = (SQInteger)out.val;
return true; return true;
} }
@ -12625,11 +12719,13 @@ bool SQDebugServer::GetObj_VarRef( const varref_t *ref, string_t &expression, ob
} }
case VARREF_OUTERS: case VARREF_OUTERS:
{ {
AssertClient( sq_type(ref->GetVar()) == OT_CLOSURE ); SQObject target = ref->GetVar();
if ( sq_type(ref->GetVar()) == OT_CLOSURE ) AssertClient( sq_type(target) == OT_CLOSURE );
if ( sq_type(target) == OT_CLOSURE )
{ {
SQClosure *pClosure = _closure(ref->GetVar()); SQClosure *pClosure = _closure(target);
SQFunctionProto *func = _fp(pClosure->_function); SQFunctionProto *func = _fp(pClosure->_function);
for ( int i = 0; i < func->_noutervalues; i++ ) for ( int i = 0; i < func->_noutervalues; i++ )
@ -12649,16 +12745,18 @@ bool SQDebugServer::GetObj_VarRef( const varref_t *ref, string_t &expression, ob
} }
case VARREF_LITERALS: case VARREF_LITERALS:
{ {
AssertClient( sq_type(ref->GetVar()) == OT_CLOSURE ); SQObject target = ref->GetVar();
if ( sq_type(ref->GetVar()) == OT_CLOSURE ) AssertClient( sq_type(target) == OT_FUNCPROTO );
if ( sq_type(target) == OT_FUNCPROTO )
{ {
int idx; int idx;
if ( atoi( expression, &idx ) && if ( atoi( expression, &idx ) &&
idx >= 0 && idx < (int)_fp(_closure(ref->GetVar())->_function)->_nliterals ) idx >= 0 && idx < (int)_funcproto(target)->_nliterals )
{ {
out.type = objref_t::PTR; out.type = objref_t::PTR;
out.ptr = &_fp(_closure(ref->GetVar())->_function)->_literals[idx]; out.ptr = &_funcproto(target)->_literals[idx];
value = *out.ptr; value = *out.ptr;
return true; return true;
} }
@ -12666,6 +12764,29 @@ bool SQDebugServer::GetObj_VarRef( const varref_t *ref, string_t &expression, ob
return false; return false;
} }
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
case VARREF_FUNCTIONS:
{
SQObject target = ref->GetVar();
AssertClient( sq_type(target) == OT_FUNCPROTO );
if ( sq_type(target) == OT_FUNCPROTO )
{
int idx;
if ( atoi( expression, &idx ) &&
idx >= 0 && idx < (int)_funcproto(target)->_nfunctions )
{
out.type = objref_t::FUNCPROTO;
out.ptr = &_funcproto(target)->_functions[idx];
value = *out.ptr;
return true;
}
}
return false;
}
#endif
case VARREF_METAMETHODS: case VARREF_METAMETHODS:
{ {
int mm = -1; int mm = -1;
@ -12711,29 +12832,45 @@ bool SQDebugServer::GetObj_VarRef( const varref_t *ref, string_t &expression, ob
} }
case VARREF_STACK: case VARREF_STACK:
{ {
AssertClient( expression.len > 2 ); AssertClient( expression.len > 5 );
if ( expression.len <= 2 ) if ( expression.len <= 5 )
return false; return false;
while ( expression.len > 3 && expression.ptr[expression.len-1] != ']' ) while ( expression.len > 5 && expression.ptr[expression.len-1] != ']' )
expression.len--; expression.len--;
expression.ptr++; expression.ptr++;
expression.len -= 2; expression.len -= 2;
AssertClient( expression.ptr[-1] == '[' );
char *pIdx = strchr( expression.ptr, ']' );
string_t strFrame( expression.ptr, pIdx - expression.ptr );
HSQUIRRELVM vm = ref->GetThread();
int frame;
if ( !pIdx || !strtoint( strFrame, &frame ) ||
frame < 0 || frame >= (int)vm->_callsstacksize )
return false;
int stackbase = GetStackBase( vm, frame );
expression.ptr += strFrame.len + 2;
expression.len -= strFrame.len + 2;
AssertClient( expression.ptr[-1] == '[' );
int idx; int idx;
if ( strtoint( expression, &idx ) && if ( !strtoint( expression, &idx ) ||
idx >= 0 && idx < (int)ref->GetThread()->_stack.size() ) stackbase + idx < 0 || stackbase + idx >= (int)vm->_stack.size() )
{ return false;
out.type = objref_t::PTR; out.type = objref_t::PTR;
out.ptr = &ref->GetThread()->_stack._vals[idx]; out.ptr = &vm->_stack._vals[ stackbase + idx ];
value = *out.ptr; value = *out.ptr;
return true; return true;
} }
return false;
}
case VARREF_INSTRUCTIONS: case VARREF_INSTRUCTIONS:
case VARREF_CALLSTACK: case VARREF_CALLSTACK:
{ {
@ -13609,7 +13746,7 @@ void SQDebugServer::FillCompletions( const SQObjectPtr &target, HSQUIRRELVM vm,
if ( def && if ( def &&
sq_type(def->metamembers) != OT_NULL && sq_type(def->metamembers) != OT_NULL &&
_instance(target)->GetMetaMethod( vm, MT_GET, mm ) ) _instance(env)->GetMetaMethod( vm, MT_GET, mm ) )
{ {
for ( unsigned int i = 0; i < _array(def->metamembers)->_values.size(); i++ ) for ( unsigned int i = 0; i < _array(def->metamembers)->_values.size(); i++ )
{ {
@ -14938,12 +15075,11 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
break; break;
} }
case OT_CLOSURE: case OT_CLOSURE:
#ifdef CHAINABLE_FUNCPROTO #ifdef ACCESSIBLE_FUNCPROTO
// Only reachable through compiler address deref
case OT_FUNCPROTO: case OT_FUNCPROTO:
#endif #endif
{ {
#ifdef CHAINABLE_FUNCPROTO #ifdef ACCESSIBLE_FUNCPROTO
SQFunctionProto *func = ( sq_type(target) == OT_CLOSURE ) ? SQFunctionProto *func = ( sq_type(target) == OT_CLOSURE ) ?
_fp(_closure(target)->_function) : _fp(_closure(target)->_function) :
_funcproto(target); _funcproto(target);
@ -15026,7 +15162,7 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
} }
else else
{ {
buf.PutHex( nparams, false ); buf.PutHex( (unsigned int)nparams, false );
} }
buf.Puts("..."); buf.Puts("...");
@ -15071,18 +15207,36 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
SetVirtualHint( elem ); SetVirtualHint( elem );
} }
#ifdef CHAINABLE_FUNCPROTO #ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
if ( sq_type(target) == OT_CLOSURE ) if ( func->_nfunctions )
#endif
{ {
wjson_table_t elem = variables.AppendTable();
elem.SetString( "name", INTERNAL_TAG("functions") );
elem.SetString( "value", GetValue( func->_nfunctions, flags ) );
elem.SetInt( "variablesReference", ToVarRef( VARREF_FUNCTIONS, ToSQObject( func ) ) );
SetVirtualHint( elem );
}
#endif
if ( func->_noutervalues ) if ( func->_noutervalues )
{ {
wjson_table_t elem = variables.AppendTable(); wjson_table_t elem = variables.AppendTable();
elem.SetString( "name", INTERNAL_TAG("outervalues") ); elem.SetString( "name", INTERNAL_TAG("outervalues") );
elem.SetString( "value", GetValue( func->_noutervalues, flags ) ); elem.SetString( "value", GetValue( func->_noutervalues, flags ) );
#ifdef ACCESSIBLE_FUNCPROTO
int v = ( sq_type(target) == OT_CLOSURE ) ? ToVarRef( VARREF_OUTERS, target ) : -1;
elem.SetInt( "variablesReference", v );
#else
Assert( sq_type(target) == OT_CLOSURE );
elem.SetInt( "variablesReference", ToVarRef( VARREF_OUTERS, target ) ); elem.SetInt( "variablesReference", ToVarRef( VARREF_OUTERS, target ) );
#endif
SetVirtualHint( elem ); SetVirtualHint( elem );
} }
#ifdef ACCESSIBLE_FUNCPROTO
if ( sq_type(target) == OT_CLOSURE )
#endif
{
#ifdef CLOSURE_ENV_ISVALID #ifdef CLOSURE_ENV_ISVALID
if ( CLOSURE_ENV_ISVALID( _closure(target)->_env ) ) if ( CLOSURE_ENV_ISVALID( _closure(target)->_env ) )
{ {
@ -15140,7 +15294,7 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
} }
else else
{ {
buf.PutHex( nparams < 0 ? -nparams : nparams, false ); buf.PutHex( (unsigned int)( nparams < 0 ? -nparams : nparams ), false );
} }
if ( nparams < 0 ) if ( nparams < 0 )
@ -15486,6 +15640,40 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
break; break;
} }
#ifdef SQDBG_SUPPORTS_FUNCPROTO_LIST
case VARREF_FUNCTIONS:
{
SQObject target = ref->GetVar();
if ( sq_type(target) != OT_FUNCPROTO )
{
DAP_ERROR_RESPONSE( seq, "variables" );
DAP_ERROR_BODY( 0, "invalid object" );
DAP_SEND();
return;
}
SQFunctionProto *func = _funcproto(target);
DAP_START_RESPONSE( seq, "variables" );
DAP_SET_TABLE( body );
wjson_array_t variables = body.SetArray( "variables" );
for ( int i = 0; i < func->_nfunctions; i++ )
{
const SQObjectPtr &val = func->_functions[i];
wjson_table_t elem = variables.AppendTable();
elem.SetIntString( "name", i );
JSONSetString( elem, "value", val, flags );
elem.SetString( "type", GetType( val ) );
elem.SetInt( "variablesReference", ToVarRef( val ) );
}
DAP_SEND();
break;
}
#endif
case VARREF_METAMETHODS: case VARREF_METAMETHODS:
{ {
SQObject target = ref->GetVar(); SQObject target = ref->GetVar();
@ -15673,17 +15861,42 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
DAP_SET_TABLE( body ); DAP_SET_TABLE( body );
wjson_array_t variables = body.SetArray( "variables" ); wjson_array_t variables = body.SetArray( "variables" );
int stackbase = -1; int stackbase = 0;
int callframe = 0; int callframe = -1;
int next = vm->_callsstacksize ? vm->_callsstack[0]._prevstkbase : 0;
int idx = 0;
const int max = vm->_stack.size();
if ( vm->_callsstacksize ) for (;;)
stackbase = vm->_callsstack[callframe]._prevstkbase;
for ( int i = 0; i < (int)vm->_stack.size(); i++ )
{ {
const SQObjectPtr &val = vm->_stack._vals[i]; callframe++;
if ( i > vm->_top && sq_type(val) == OT_NULL ) if ( callframe < vm->_callsstacksize )
{
stackbase = next;
if ( callframe + 1 < vm->_callsstacksize )
{
next = stackbase + vm->_callsstack[ callframe + 1 ]._prevstkbase;
}
else
{
next = max;
}
}
else
{
if ( callframe )
callframe--;
next = max;
}
for ( ; idx < next; idx++ )
{
const SQObjectPtr &val = vm->_stack._vals[idx];
if ( idx > vm->_top && sq_type(val) == OT_NULL )
continue; continue;
wjson_table_t elem = variables.AppendTable(); wjson_table_t elem = variables.AppendTable();
@ -15693,16 +15906,28 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
if ( !( flags & kFS_Hexadecimal ) ) if ( !( flags & kFS_Hexadecimal ) )
{ {
name.PutInt( i ); name.PutInt( callframe );
} }
else else
{ {
name.PutHex( i, false ); name.PutHex( (unsigned int)callframe, false );
}
name.Put(']');
name.Put('[');
if ( !( flags & kFS_Hexadecimal ) )
{
name.PutInt( idx - stackbase );
}
else
{
name.PutHex( (unsigned int)( idx - stackbase ), false );
} }
name.Put(']'); name.Put(']');
if ( stackbase == i ) if ( idx == stackbase )
{ {
name.Put('*'); name.Put('*');
@ -15722,11 +15947,8 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
} }
} }
#endif #endif
if ( ++callframe < vm->_callsstacksize )
stackbase += vm->_callsstack[callframe]._prevstkbase;
} }
else if ( vm->_top == i ) else if ( vm->_top == idx )
{ {
name.Put('_'); name.Put('_');
} }
@ -15737,6 +15959,10 @@ void SQDebugServer::OnRequest_Variables( const json_table_t &arguments, int seq
if ( ShouldPageArray( val, 16 * ARRAY_PAGE_LIMIT ) ) if ( ShouldPageArray( val, 16 * ARRAY_PAGE_LIMIT ) )
elem.SetInt( "indexedVariables", (int)_array(val)->_values.size() ); elem.SetInt( "indexedVariables", (int)_array(val)->_values.size() );
} }
if ( next == max )
break;
}
DAP_SEND(); DAP_SEND();
break; break;
@ -15865,7 +16091,7 @@ void SQDebugServer::OnRequest_SetVariable( const json_table_t &arguments, int se
DAP_ERROR_BODY( 0, "could not set '{name}'" ); DAP_ERROR_BODY( 0, "could not set '{name}'" );
error.SetBool( "showUser", true ); error.SetBool( "showUser", true );
wjson_table_t variables = error.SetTable( "variables" ); wjson_table_t variables = error.SetTable( "variables" );
JSONSetString( variables, "name", obj.key ); variables.SetString( "name", strName );
DAP_SEND(); DAP_SEND();
return; return;
} }
@ -16342,7 +16568,7 @@ void SQDebugServer::OnRequest_Disassemble( const json_table_t &arguments, int se
#ifdef SUPPORTS_RESTART_FRAME #ifdef SUPPORTS_RESTART_FRAME
void SQDebugServer::OnRequest_RestartFrame( const json_table_t &arguments, int seq ) void SQDebugServer::OnRequest_RestartFrame( const json_table_t &arguments, int seq )
{ {
Assert( m_State == ThreadState_Suspended ); AssertClient( m_State != ThreadState_Running );
HSQUIRRELVM vm; HSQUIRRELVM vm;
int frame; int frame;
@ -16846,7 +17072,7 @@ bool SQDebugServer::InstructionStep( HSQUIRRELVM vm, SQVM::CallInfo *ci, int ins
SQInstruction *instrEnd = func->_instructions + func->_ninstructions; SQInstruction *instrEnd = func->_instructions + func->_ninstructions;
SQInstruction *ip = ci->_ip - instrOffset; SQInstruction *ip = ci->_ip - instrOffset;
Assert( ip >= func->_instructions && ip < instrEnd ); Assert( ip >= func->_instructions );
{ {
for (;;) for (;;)
@ -16973,7 +17199,7 @@ bool SQDebugServer::Step( HSQUIRRELVM vm, SQVM::CallInfo *ci )
ClearCachedInstructions(); ClearCachedInstructions();
SQFunctionProto *func = _fp(_closure(ci->_closure)->_function); SQFunctionProto *func = _fp(_closure(ci->_closure)->_function);
Assert( ci->_ip >= func->_instructions && ci->_ip < func->_instructions + func->_ninstructions ); Assert( ci->_ip >= func->_instructions );
// Check if this function was compiled with debug info // Check if this function was compiled with debug info
// The first op is going to be a line op // The first op is going to be a line op
@ -17000,7 +17226,7 @@ bool SQDebugServer::Step( HSQUIRRELVM vm, SQVM::CallInfo *ci )
_CacheInstruction( func, func->_instructions + op ); _CacheInstruction( func, func->_instructions + op );
// Set break point at every possible jump target // Set break point at every possible jump target
for ( SQInstruction *ip = ci->_ip + 1; ip <= func->_instructions + op; ip++ ) for ( SQInstruction *ip = ci->_ip; ip <= func->_instructions + op; ip++ )
{ {
if ( IsJumpOp( ip ) && GetJumpCount( ip ) != 0 ) if ( IsJumpOp( ip ) && GetJumpCount( ip ) != 0 )
{ {
@ -17040,6 +17266,14 @@ void SQDebugServer::CacheInstruction( SQInstruction *instr )
void SQDebugServer::ClearCachedInstructions() void SQDebugServer::ClearCachedInstructions()
{ {
#ifdef SQDBG_WEAK_INSTRUCTION_REF
for ( int i = m_CachedInstructions.Size(); i--; )
{
cachedinstr_t &cached = m_CachedInstructions[i];
__ObjRelease( cached.func );
}
#endif
m_CachedInstructions.Clear(); m_CachedInstructions.Clear();
} }
@ -17050,10 +17284,7 @@ void SQDebugServer::RestoreCachedInstructions()
cachedinstr_t &cached = m_CachedInstructions[i]; cachedinstr_t &cached = m_CachedInstructions[i];
#ifdef SQDBG_WEAK_INSTRUCTION_REF #ifdef SQDBG_WEAK_INSTRUCTION_REF
if ( cached.func && sq_type(cached.func->_obj) == OT_FUNCPROTO ) if ( cached.func && sq_type(cached.func->_obj) == OT_FUNCPROTO )
{
_funcproto(cached.func->_obj)->_instructions[ cached.index ] = cached.instr; _funcproto(cached.func->_obj)->_instructions[ cached.index ] = cached.instr;
__ObjRelease( cached.func );
}
#else #else
if ( cached.ip ) if ( cached.ip )
*cached.ip = cached.instr; *cached.ip = cached.instr;
@ -17068,10 +17299,7 @@ void SQDebugServer::UndoRestoreCachedInstructions()
cachedinstr_t &cached = m_CachedInstructions[i]; cachedinstr_t &cached = m_CachedInstructions[i];
#ifdef SQDBG_WEAK_INSTRUCTION_REF #ifdef SQDBG_WEAK_INSTRUCTION_REF
if ( cached.func && sq_type(cached.func->_obj) == OT_FUNCPROTO ) if ( cached.func && sq_type(cached.func->_obj) == OT_FUNCPROTO )
{
memzero( &_funcproto(cached.func->_obj)->_instructions[ cached.index ] ); memzero( &_funcproto(cached.func->_obj)->_instructions[ cached.index ] );
__ObjAddRef( cached.func );
}
#else #else
if ( cached.ip ) if ( cached.ip )
memzero( cached.ip ); memzero( cached.ip );
@ -17337,7 +17565,15 @@ int SQDebugServer::AddFunctionBreakpoint( const string_t &func, const string_t &
SQChar *pSrc = pFunc + funcsize; SQChar *pSrc = pFunc + funcsize;
sqstring_t wfunc, wsrc; sqstring_t wfunc, wsrc;
if ( func.IsEmpty() )
{
wfunc.Assign( _SC("") );
}
else
{
wfunc.Assign( pFunc, UTF8ToSQUnicode( pFunc, funcsize, func.ptr, func.len ) ); wfunc.Assign( pFunc, UTF8ToSQUnicode( pFunc, funcsize, func.ptr, func.len ) );
}
if ( funcsrc.IsEmpty() ) if ( funcsrc.IsEmpty() )
{ {
@ -17828,6 +18064,10 @@ sqstring_t SQDebugServer::PrintDisassembly( SQClosure *target, SQChar *scratch,
int idx; int idx;
if ( func->_ndefaultparams && ( idx = (int)func->_ndefaultparams - ( nparams - i ) ) >= 0 ) if ( func->_ndefaultparams && ( idx = (int)func->_ndefaultparams - ( nparams - i ) ) >= 0 )
{ {
len = STRLEN(" = ");
memcpy( buf, _SC(" = "), sq_rsl(len) );
buf += len;
const SQObjectPtr &val = target->_defaultparams[idx]; const SQObjectPtr &val = target->_defaultparams[idx];
string_t str; string_t str;
@ -17838,19 +18078,39 @@ sqstring_t SQDebugServer::PrintDisassembly( SQClosure *target, SQChar *scratch,
case OT_BOOL: case OT_BOOL:
case OT_NULL: case OT_NULL:
case OT_STRING: case OT_STRING:
str = GetValue( val, kFS_NoAddr ); str = GetValue( val );
len = min( str.len, DISASM_MAX_PARAM_NAME_LEN - 3 );
break; break;
case OT_CLASS:
case OT_INSTANCE:
{
const classdef_t *def =
FindClassDef( sq_type(val) == OT_CLASS ? _class(val) : _instance(val)->_class );
if ( def && def->name.ptr )
{
str = GetType( val );
len = min( (int)str.len, DISASM_MAX_PARAM_NAME_LEN - 4 );
#ifdef SQUNICODE
UTF8ToSQUnicode( buf, _bs, str.ptr, len );
#else
memcpy( buf, str.ptr, sq_rsl(len) );
#endif
buf += len;
*buf++ = ' ';
str.Assign( def->name.ptr + FMT_PTR_LEN + 1, def->name.len - FMT_PTR_LEN - 1 );
len = min( (int)str.len, DISASM_MAX_PARAM_NAME_LEN - 4 - len );
break;
}
}
default: default:
str = GetType( val ); str = GetType( val );
len = min( (int)str.len, DISASM_MAX_PARAM_NAME_LEN - 3 );
} }
len = STRLEN(" = ");
memcpy( buf, _SC(" = "), sq_rsl(len) );
buf += len;
len = min( str.len, DISASM_MAX_PARAM_NAME_LEN - 3 );
#ifdef SQUNICODE #ifdef SQUNICODE
UTF8ToSQUnicode( buf, _bs, str.ptr, str.len ); UTF8ToSQUnicode( buf, _bs, str.ptr, len );
#else #else
memcpy( buf, str.ptr, sq_rsl(len) ); memcpy( buf, str.ptr, sq_rsl(len) );
#endif #endif
@ -18871,6 +19131,8 @@ void SQDebugServer::DebugHook( HSQUIRRELVM vm, int type,
if ( m_pCurVM->ci ) if ( m_pCurVM->ci )
{ {
if ( m_pCurVM->_suspended ) if ( m_pCurVM->_suspended )
{
if ( m_pCurVM->ci->_ip )
{ {
SQInstruction *pip = m_pCurVM->ci->_ip - 1; SQInstruction *pip = m_pCurVM->ci->_ip - 1;
@ -18921,6 +19183,7 @@ void SQDebugServer::DebugHook( HSQUIRRELVM vm, int type,
} }
} }
} }
}
else else
{ {
if ( sq_type(m_pCurVM->ci->_closure) == OT_NATIVECLOSURE && if ( sq_type(m_pCurVM->ci->_closure) == OT_NATIVECLOSURE &&
@ -18928,7 +19191,7 @@ void SQDebugServer::DebugHook( HSQUIRRELVM vm, int type,
( IsEqual( _SC("wakeup"), _string(_nativeclosure(m_pCurVM->ci->_closure)->_name) ) || ( IsEqual( _SC("wakeup"), _string(_nativeclosure(m_pCurVM->ci->_closure)->_name) ) ||
IsEqual( _SC("call"), _string(_nativeclosure(m_pCurVM->ci->_closure)->_name) ) ) ) IsEqual( _SC("call"), _string(_nativeclosure(m_pCurVM->ci->_closure)->_name) ) ) )
{ {
m_nCalls += (int)( vm->ci - vm->_callsstack ) + 1; m_nCalls += (int)( vm->ci - vm->_callsstack ) + ( type != SQ_HOOK_CALL );
} }
} }
} }
@ -20302,7 +20565,7 @@ HSQDEBUGSERVER sqdbg_attach_debugger( HSQUIRRELVM vm )
{ {
CDebuggerScriptRef *ref = NULL; CDebuggerScriptRef *ref = NULL;
CStackCheck stackcheck( vm ); STACKCHECK( vm );
sq_pushregistrytable( vm ); sq_pushregistrytable( vm );
sq_pushstring( vm, _SC(SQDBG_SV_TAG), -1 ); sq_pushstring( vm, _SC(SQDBG_SV_TAG), -1 );
@ -20366,7 +20629,7 @@ HSQDEBUGSERVER sqdbg_attach_debugger( HSQUIRRELVM vm )
void sqdbg_destroy_debugger( HSQUIRRELVM vm ) void sqdbg_destroy_debugger( HSQUIRRELVM vm )
{ {
CStackCheck stackcheck( vm ); STACKCHECK( vm );
sq_pushregistrytable( vm ); sq_pushregistrytable( vm );
sq_pushstring( vm, _SC(SQDBG_SV_TAG), -1 ); sq_pushstring( vm, _SC(SQDBG_SV_TAG), -1 );

View File

@ -75,6 +75,21 @@ bool atox( string_t str, I *out );
template < typename I > template < typename I >
bool atoo( string_t str, I *out ); bool atoo( string_t str, I *out );
template < typename I >
struct _as_unsigned { typedef I T; };
template <>
struct _as_unsigned< int > { typedef unsigned int T; };
#ifdef _SQ64
template <>
struct _as_unsigned< SQInteger > { typedef SQUnsignedInteger T; };
#endif
#define as_unsigned_type( I ) typename _as_unsigned<I>::T
#define cast_unsigned( I, v ) (as_unsigned_type(I)(v))
#define IS_UNSIGNED( I ) ((I)0 < (I)-1)
#define _isdigit( c ) \ #define _isdigit( c ) \
IN_RANGE_CHAR( c, '0', '9' ) IN_RANGE_CHAR( c, '0', '9' )
@ -403,9 +418,10 @@ struct sqstring_t
unsigned int i = 0; unsigned int i = 0;
do do
{ {
if ( ptr[i] > 0x7E || other.ptr[i] != (char)ptr[i] ) if ( (SQUnsignedChar)ptr[i] > 0x7E || other.ptr[i] != (char)ptr[i] )
{ {
AssertMsg( ptr[i] <= 0x7E, "not implemented" ); // > 0x7E can be reached through completions request
// unicode identifiers are not supported, ignore them
return false; return false;
} }
} }
@ -556,6 +572,8 @@ struct stringbufbase_t
template < typename I > template < typename I >
void PutHex( I value, bool padding = true ) void PutHex( I value, bool padding = true )
{ {
STATIC_ASSERT( IS_UNSIGNED( I ) );
int space = BytesLeft(); int space = BytesLeft();
if ( space < 3 ) if ( space < 3 )
@ -590,9 +608,9 @@ bool string_t::IsEqualTo( const sqstring_t &other ) const
{ {
// Used for comparing against locals and outers, // Used for comparing against locals and outers,
// implement unicode conversion if locals can have unicode characters // implement unicode conversion if locals can have unicode characters
if ( other.ptr[i] > 0x7E || (char)other.ptr[i] != ptr[i] ) if ( (SQUnsignedChar)other.ptr[i] > 0x7E || (char)other.ptr[i] != ptr[i] )
{ {
AssertMsg( other.ptr[i] <= 0x7E, "not implemented" ); AssertMsg( (SQUnsignedChar)other.ptr[i] <= 0x7E, "not implemented" );
return false; return false;
} }
} }
@ -675,7 +693,7 @@ inline int printint( C *buf, int size, I value )
value /= 10; value /= 10;
buf[i--] = !neg ? ( '0' + c ) : ( '0' - c ); buf[i--] = !neg ? ( '0' + c ) : ( '0' - c );
} }
while ( value && i >= 0 ); while ( value );
return len; return len;
} }
@ -683,10 +701,11 @@ inline int printint( C *buf, int size, I value )
template < bool padding, bool prefix, bool uppercase, typename C, typename I > template < bool padding, bool prefix, bool uppercase, typename C, typename I >
inline int printhex( C *buf, int size, I value ) inline int printhex( C *buf, int size, I value )
{ {
STATIC_ASSERT( IS_UNSIGNED( as_unsigned_type( I ) ) );
Assert( buf ); Assert( buf );
Assert( size > 0 ); Assert( size > 0 );
int len = ( prefix ? 2 : 0 ) + ( padding ? sizeof(I) * 2 : countdigits<16>( value ) ); int len = ( prefix ? 2 : 0 ) + ( padding ? sizeof(I) * 2 : countdigits<16>( cast_unsigned( I, value ) ) );
if ( len > size ) if ( len > size )
len = size; len = size;
@ -695,11 +714,11 @@ inline int printhex( C *buf, int size, I value )
do do
{ {
C c = value & 0xf; C c = cast_unsigned( I, value ) & 0xf;
value >>= 4; *(as_unsigned_type(I)*)&value >>= 4;
buf[i--] = c + ( ( c < 10 ) ? '0' : ( ( uppercase ? 'A' : 'a' ) - 10 ) ); buf[i--] = c + ( ( c < 10 ) ? '0' : ( ( uppercase ? 'A' : 'a' ) - 10 ) );
} }
while ( value && i >= 0 ); while ( value );
if ( padding ) if ( padding )
{ {
@ -725,6 +744,7 @@ inline int printhex( C *buf, int size, I value )
template < typename C, typename I > template < typename C, typename I >
inline int printoct( C *buf, int size, I value ) inline int printoct( C *buf, int size, I value )
{ {
STATIC_ASSERT( IS_UNSIGNED( I ) );
Assert( buf ); Assert( buf );
Assert( size > 0 ); Assert( size > 0 );
@ -741,7 +761,7 @@ inline int printoct( C *buf, int size, I value )
value >>= 3; value >>= 3;
buf[i--] = '0' + c; buf[i--] = '0' + c;
} }
while ( value && i >= 0 ); while ( value );
if ( i >= 0 ) if ( i >= 0 )
buf[i--] = '0'; buf[i--] = '0';
@ -1302,7 +1322,7 @@ doescape:
else else
{ {
mbc[bytes++] = 'x'; mbc[bytes++] = 'x';
bytes += printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQChar)cp ); bytes += printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQUnsignedChar)cp );
} }
goto write; goto write;
@ -1339,7 +1359,7 @@ x7ff:
mbc[bytes++] = '\\'; mbc[bytes++] = '\\';
mbc[bytes++] = 'x'; mbc[bytes++] = 'x';
bytes = bytes + printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQChar)cp ); bytes = bytes + printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQUnsignedChar)cp );
goto write; goto write;
} }
} }

View File

@ -306,7 +306,7 @@ public:
void Free( void *ptr ) void Free( void *ptr )
{ {
Assert( !SEQUENTIAL ); STATIC_ASSERT( !SEQUENTIAL );
Assert( m_Memory ); Assert( m_Memory );
Assert( ptr ); Assert( ptr );
@ -364,7 +364,7 @@ public:
void ReleaseShrink() void ReleaseShrink()
{ {
Assert( SEQUENTIAL ); STATIC_ASSERT( SEQUENTIAL );
if ( !m_Memory ) if ( !m_Memory )
return; return;
@ -412,7 +412,7 @@ public:
void Release() void Release()
{ {
Assert( SEQUENTIAL ); STATIC_ASSERT( SEQUENTIAL );
if ( !m_Memory || ( !m.LastFreeChunk() && !m.LastFreeIndex() ) ) if ( !m_Memory || ( !m.LastFreeChunk() && !m.LastFreeIndex() ) )
return; return;
@ -437,7 +437,7 @@ public:
void ReleaseTop() void ReleaseTop()
{ {
Assert( SEQUENTIAL ); STATIC_ASSERT( SEQUENTIAL );
m.SetLastFreeChunk( m.PrevChunk() ); m.SetLastFreeChunk( m.PrevChunk() );
m.SetLastFreeIndex( m.PrevIndex() ); m.SetLastFreeIndex( m.PrevIndex() );
@ -455,23 +455,23 @@ public:
vector() : base(), size(0) vector() : base(), size(0)
{ {
Assert( !bExternalMem ); STATIC_ASSERT( !bExternalMem );
} }
vector( CAllocator &a ) : base(a), size(0) vector( CAllocator &a ) : base(a), size(0)
{ {
Assert( bExternalMem ); STATIC_ASSERT( bExternalMem );
} }
vector( I count ) : base(), size(0) vector( I count ) : base(), size(0)
{ {
Assert( !bExternalMem ); STATIC_ASSERT( !bExternalMem );
base.Alloc( count * sizeof(T) ); base.Alloc( count * sizeof(T) );
} }
vector( const vector< T > &src ) : base() vector( const vector< T > &src ) : base()
{ {
Assert( !bExternalMem ); STATIC_ASSERT( !bExternalMem );
base.Alloc( src.base.Size() ); base.Alloc( src.base.Size() );
size = src.size; size = src.size;

View File

@ -284,6 +284,14 @@ public:
WriteObject( (const SQObjectPtr&)obj, pBuffer, writeState ); WriteObject( (const SQObjectPtr&)obj, pBuffer, writeState );
} }
void WriteObject( SQGenerator *pObj, CUtlBuffer* pBuffer, WriteStateMap& writeState )
{
SQObject obj;
obj._type = OT_GENERATOR;
obj._unVal.pUserPointer = pObj;
WriteObject( (const SQObjectPtr&)obj, pBuffer, writeState );
}
void ReadObject( SQObjectPtr &obj, CUtlBuffer* pBuffer, ReadStateMap& readState ); void ReadObject( SQObjectPtr &obj, CUtlBuffer* pBuffer, ReadStateMap& readState );
// Do not implicity add/remove ref // Do not implicity add/remove ref
@ -3405,7 +3413,8 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
#ifdef _DEBUG #ifdef _DEBUG
bool bAsserted = false; bool bAsserted = false;
if ( pThis->_noutervalues && pThis->_name._type == OT_STRING && pThis->_name._unVal.pString ) if ( pThis->_noutervalues && pThis->_name._type == OT_STRING && pThis->_name._unVal.pString &&
pThis->_outervalues[0]._type == OT_USERPOINTER )
{ {
Assert( pThis->_noutervalues == 1 ); Assert( pThis->_noutervalues == 1 );
Assert( pThis->_outervalues[0]._type == OT_USERPOINTER ); Assert( pThis->_outervalues[0]._type == OT_USERPOINTER );
@ -3708,23 +3717,25 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
if ( pThis->_callsstacksize ) if ( pThis->_callsstacksize )
{ {
int stackidx = -1; for ( int i = 0; i < pThis->_callsstacksize; i++ )
for ( int i = pThis->_callsstacksize; i--; )
{ {
const SQVM::CallInfo *ci = &pThis->_callsstack[i]; const SQVM::CallInfo *ci = &pThis->_callsstack[i];
if ( pThis->ci == ci ) Assert( ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions &&
stackidx = i; ci->_ip < ci->_closure._unVal.pClosure->_function->_instructions +
ci->_closure._unVal.pClosure->_function->_ninstructions );
Assert( !ci->_generator );
Assert( ci->_ip && ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions );
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci->_etraps ); Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci->_etraps );
Assert( ci->_closure._type == OT_CLOSURE && ci->_closure._unVal.pClosure ); Assert( ci->_closure._type == OT_CLOSURE && ci->_closure._unVal.pClosure );
WriteObject( ci->_closure, pBuffer, writeState ); WriteObject( ci->_closure, pBuffer, writeState );
int offset = (int)ci->_ip - (int)ci->_closure._unVal.pClosure->_function->_instructions; Assert( ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions <= INT_MAX );
pBuffer->PutChar( ci->_generator != 0 );
if ( ci->_generator )
WriteObject( ci->_generator, pBuffer, writeState );
int offset = ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions;
pBuffer->PutInt( offset ); pBuffer->PutInt( offset );
pBuffer->PutInt( ci->_etraps ); pBuffer->PutInt( ci->_etraps );
pBuffer->PutInt( ci->_prevstkbase ); pBuffer->PutInt( ci->_prevstkbase );
@ -3733,16 +3744,18 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
pBuffer->PutInt( ci->_ncalls ); pBuffer->PutInt( ci->_ncalls );
pBuffer->PutChar( ci->_root ); pBuffer->PutChar( ci->_root );
for ( int j = ci->_etraps; j--; ) for ( int j = 0; j < ci->_etraps; j++ )
{ {
const SQExceptionTrap &et = pThis->_etraps[j]; const SQExceptionTrap &et = pThis->_etraps[j];
pBuffer->PutInt( et._extarget );
pBuffer->PutInt( et._stackbase );
pBuffer->PutInt( et._stacksize ); pBuffer->PutInt( et._stacksize );
Assert( et._ip == ci->_ip ); pBuffer->PutInt( et._stackbase );
Assert( et._ip - ci->_ip <= INT_MAX );
pBuffer->PutInt( et._ip - ci->_ip );
pBuffer->PutInt( et._extarget );
} }
} }
int stackidx = pThis->ci - pThis->_callsstack;
Assert( stackidx >= 0 && stackidx < pThis->_callsstacksize ); Assert( stackidx >= 0 && stackidx < pThis->_callsstacksize );
pBuffer->PutInt( stackidx ); pBuffer->PutInt( stackidx );
} }
@ -3773,29 +3786,37 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
WriteObject( pThis->_closure, pBuffer, writeState ); WriteObject( pThis->_closure, pBuffer, writeState );
const SQVM::CallInfo &ci = pThis->_ci; const SQVM::CallInfo *ci = &pThis->_ci;
Assert( !ci._generator ); Assert( pThis->_closure._unVal.pClosure == ci->_closure._unVal.pClosure );
Assert( pThis->_closure._unVal.pClosure == ci._closure._unVal.pClosure ); Assert( ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions &&
Assert( ci._ip && ci._ip >= ci._closure._unVal.pClosure->_function->_instructions ); ci->_ip < ci->_closure._unVal.pClosure->_function->_instructions +
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci._etraps ); ci->_closure._unVal.pClosure->_function->_ninstructions );
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci->_etraps );
int offset = (int)ci._ip - (int)ci._closure._unVal.pClosure->_function->_instructions; Assert( ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions <= INT_MAX );
pBuffer->PutChar( ci->_generator != 0 );
if ( ci->_generator )
WriteObject( ci->_generator, pBuffer, writeState );
int offset = ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions;
pBuffer->PutInt( offset ); pBuffer->PutInt( offset );
pBuffer->PutInt( ci._etraps ); pBuffer->PutInt( ci->_etraps );
pBuffer->PutInt( ci._prevstkbase ); pBuffer->PutInt( ci->_prevstkbase );
pBuffer->PutInt( ci._prevtop ); pBuffer->PutInt( ci->_prevtop );
pBuffer->PutInt( ci._target ); pBuffer->PutInt( ci->_target );
pBuffer->PutInt( ci._ncalls ); pBuffer->PutInt( ci->_ncalls );
pBuffer->PutChar( ci._root ); pBuffer->PutChar( ci->_root );
for ( int j = ci._etraps; j--; ) for ( int j = 0; j < ci->_etraps; j++ )
{ {
const SQExceptionTrap &et = pThis->_etraps[j]; const SQExceptionTrap &et = pThis->_etraps[j];
pBuffer->PutInt( et._extarget );
pBuffer->PutInt( et._stackbase );
pBuffer->PutInt( et._stacksize ); pBuffer->PutInt( et._stacksize );
Assert( et._ip == ci._ip ); pBuffer->PutInt( et._stackbase );
Assert( et._ip - ci->_ip <= INT_MAX );
pBuffer->PutInt( et._ip - ci->_ip );
pBuffer->PutInt( et._extarget );
} }
int stacksize = pThis->_stack.size(); int stacksize = pThis->_stack.size();
@ -3809,7 +3830,6 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
} }
case OT_USERDATA: case OT_USERDATA:
case OT_USERPOINTER: case OT_USERPOINTER:
Assert(0);
break; break;
default: default:
AssertMsgAlways( 0, "SquirrelVM::WriteObject: unknown type" ); AssertMsgAlways( 0, "SquirrelVM::WriteObject: unknown type" );
@ -3853,26 +3873,10 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
case OT_STRING: case OT_STRING:
{ {
int len = pBuffer->GetInt(); int len = pBuffer->GetInt();
char *psz; char *psz = (char*)pBuffer->PeekGet( 0 );
pBuffer->SeekGet( CUtlBuffer::SEEK_CURRENT, len );
if ( len < 1024 ) Assert( pBuffer->IsValid() );
{
psz = (char*)stackalloc( len );
}
else
{
psz = (char*)malloc( len );
}
pBuffer->Get( psz, len );
obj._unVal.pString = SQString::Create( _ss(vm_), psz, len ); obj._unVal.pString = SQString::Create( _ss(vm_), psz, len );
if ( len >= 1024 )
{
free( psz );
}
break; break;
} }
case OT_TABLE: case OT_TABLE:
@ -4358,10 +4362,10 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
if ( pThis->_callsstacksize ) if ( pThis->_callsstacksize )
{ {
if ( pThis->_callsstacksize >= pThis->_alloccallsstacksize ) while ( pThis->_callsstacksize >= pThis->_alloccallsstacksize )
pThis->GrowCallStack(); pThis->GrowCallStack();
for ( int i = pThis->_callsstacksize; i--; ) for ( int i = 0; i < pThis->_callsstacksize; i++ )
{ {
SQVM::CallInfo *ci = &pThis->_callsstack[i]; SQVM::CallInfo *ci = &pThis->_callsstack[i];
@ -4369,23 +4373,31 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
ReadObject( closure, pBuffer, readState ); ReadObject( closure, pBuffer, readState );
Assert( closure._type == OT_CLOSURE && closure._unVal.pClosure ); Assert( closure._type == OT_CLOSURE && closure._unVal.pClosure );
int offset = pBuffer->GetInt(); if ( pBuffer->GetChar() )
int funcsize = sizeof(SQInstruction) * closure._unVal.pClosure->_function->_ninstructions;
int start = (int)(closure._unVal.pClosure->_function->_instructions);
int pos = start + offset;
ci->_ip = (SQInstruction*)pos;
Assert( pos < (start + funcsize) );
// don't read past boundary
if ( pos >= (start + funcsize) )
{ {
ci->_ip = (SQInstruction*)start; SQObject generator;
ReadObject( generator, pBuffer, readState );
Assert( generator._type == OT_GENERATOR && generator._unVal.pGenerator );
ci->_generator = generator._unVal.pGenerator;
}
else
{
ci->_generator = NULL;
} }
int offset = pBuffer->GetInt();
SQInstruction *start = closure._unVal.pClosure->_function->_instructions;
SQInstruction *end = start + closure._unVal.pClosure->_function->_ninstructions;
SQInstruction *pos = start + offset;
Assert( pos >= start && pos < end );
if ( pos < start || pos >= end )
pos = start;
ci->_ip = pos;
ci->_literals = closure._unVal.pClosure->_function->_literals; ci->_literals = closure._unVal.pClosure->_function->_literals;
ci->_closure = closure; ci->_closure = closure;
ci->_generator = NULL;
ci->_etraps = pBuffer->GetInt(); ci->_etraps = pBuffer->GetInt();
ci->_prevstkbase = pBuffer->GetInt(); ci->_prevstkbase = pBuffer->GetInt();
ci->_prevtop = pBuffer->GetInt(); ci->_prevtop = pBuffer->GetInt();
@ -4395,13 +4407,13 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
pThis->_etraps.resize( ci->_etraps ); pThis->_etraps.resize( ci->_etraps );
for ( int j = ci->_etraps; j--; ) for ( int j = 0; j < ci->_etraps; j++ )
{ {
SQExceptionTrap &et = pThis->_etraps[j]; SQExceptionTrap &et = pThis->_etraps[j];
et._extarget = pBuffer->GetInt();
et._stackbase = pBuffer->GetInt();
et._stacksize = pBuffer->GetInt(); et._stacksize = pBuffer->GetInt();
et._ip = ci->_ip; et._stackbase = pBuffer->GetInt();
et._ip = ci->_ip + pBuffer->GetInt();
et._extarget = pBuffer->GetInt();
} }
} }
@ -4448,41 +4460,49 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
pThis->_state = (SQGenerator::SQGeneratorState)state; pThis->_state = (SQGenerator::SQGeneratorState)state;
SQVM::CallInfo &ci = pThis->_ci; SQVM::CallInfo *ci = &pThis->_ci;
int offset = pBuffer->GetInt(); if ( pBuffer->GetChar() )
int funcsize = sizeof(SQInstruction) * closure._unVal.pClosure->_function->_ninstructions;
int start = (int)(closure._unVal.pClosure->_function->_instructions);
int pos = start + offset;
ci._ip = (SQInstruction*)pos;
Assert( pos < (start + funcsize) );
// don't read past boundary
if ( pos >= (start + funcsize) )
{ {
ci._ip = (SQInstruction*)start; SQObject generator;
ReadObject( generator, pBuffer, readState );
Assert( generator._type == OT_GENERATOR && generator._unVal.pGenerator );
ci->_generator = generator._unVal.pGenerator;
}
else
{
ci->_generator = NULL;
} }
ci._literals = closure._unVal.pClosure->_function->_literals; int offset = pBuffer->GetInt();
ci._closure = closure; SQInstruction *start = closure._unVal.pClosure->_function->_instructions;
ci._generator = NULL; SQInstruction *end = start + closure._unVal.pClosure->_function->_ninstructions;
ci._etraps = pBuffer->GetInt(); SQInstruction *pos = start + offset;
ci._prevstkbase = pBuffer->GetInt();
ci._prevtop = pBuffer->GetInt();
ci._target = pBuffer->GetInt();
ci._ncalls = pBuffer->GetInt();
ci._root = pBuffer->GetChar();
pThis->_etraps.resize( ci._etraps ); Assert( pos >= start && pos < end );
for ( int j = ci._etraps; j--; ) if ( pos < start || pos >= end )
pos = start;
ci->_ip = pos;
ci->_literals = closure._unVal.pClosure->_function->_literals;
ci->_closure = closure;
ci->_etraps = pBuffer->GetInt();
ci->_prevstkbase = pBuffer->GetInt();
ci->_prevtop = pBuffer->GetInt();
ci->_target = pBuffer->GetInt();
ci->_ncalls = pBuffer->GetInt();
ci->_root = pBuffer->GetChar();
pThis->_etraps.resize( ci->_etraps );
for ( int j = 0; j < ci->_etraps; j++ )
{ {
SQExceptionTrap &et = pThis->_etraps[j]; SQExceptionTrap &et = pThis->_etraps[j];
et._extarget = pBuffer->GetInt();
et._stackbase = pBuffer->GetInt();
et._stacksize = pBuffer->GetInt(); et._stacksize = pBuffer->GetInt();
et._ip = ci._ip; et._stackbase = pBuffer->GetInt();
et._ip = ci->_ip + pBuffer->GetInt();
et._extarget = pBuffer->GetInt();
} }
int stacksize = pBuffer->GetInt(); int stacksize = pBuffer->GetInt();
@ -4496,10 +4516,7 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
} }
case OT_USERDATA: case OT_USERDATA:
case OT_USERPOINTER: case OT_USERPOINTER:
{
Assert(0);
break; break;
}
default: default:
AssertMsgAlways( 0, "SquirrelVM::ReadObject: serialisation error" ); AssertMsgAlways( 0, "SquirrelVM::ReadObject: serialisation error" );
} }