Fix script interpreter stack for x86_64

Alot of stack and event variables are pointers. Align the size of
all script and event variable types to sizeof(intptr_t) so that
the CPU needs only one fetch insn on 64bit archs.

Tested on x86 and x86_64 and found no different script behaviours
compared to the binary from id.
Savegames on x86_64 do work, but are not compatible to x86 and vice
versa (among other issues, the stack is written to file as-is).
x86 builds can still load savegames from the official binary and
vice versa.
This commit is contained in:
dhewg 2011-12-01 21:30:02 +01:00 committed by Daniel Gibson
parent dc86a8a02c
commit f8efcf5e90
12 changed files with 240 additions and 110 deletions

View file

@ -92,15 +92,15 @@ idEventDef::idEventDef( const char *command, const char *formatspec, char return
switch( formatspec[ i ] ) { switch( formatspec[ i ] ) {
case D_EVENT_FLOAT : case D_EVENT_FLOAT :
bits |= 1 << i; bits |= 1 << i;
argsize += sizeof( float ); argsize += sizeof( intptr_t );
break; break;
case D_EVENT_INTEGER : case D_EVENT_INTEGER :
argsize += sizeof( int ); argsize += sizeof( intptr_t );
break; break;
case D_EVENT_VECTOR : case D_EVENT_VECTOR :
argsize += sizeof( idVec3 ); argsize += E_EVENT_SIZEOF_VEC;
break; break;
case D_EVENT_STRING : case D_EVENT_STRING :

View file

@ -36,6 +36,9 @@ Event are used for scheduling tasks and for linking script commands.
#define D_EVENT_MAXARGS 8 // if changed, enable the CREATE_EVENT_CODE define in Event.cpp to generate switch statement for idClass::ProcessEventArgPtr. #define D_EVENT_MAXARGS 8 // if changed, enable the CREATE_EVENT_CODE define in Event.cpp to generate switch statement for idClass::ProcessEventArgPtr.
// running the game will then generate c:\doom\base\events.txt, the contents of which should be copied into the switch statement. // running the game will then generate c:\doom\base\events.txt, the contents of which should be copied into the switch statement.
// stack size of idVec3, aligned to native pointer size
#define E_EVENT_SIZEOF_VEC ((sizeof(idVec3) + (sizeof(intptr_t) - 1)) & ~(sizeof(intptr_t) - 1))
#define D_EVENT_VOID ( ( char )0 ) #define D_EVENT_VOID ( ( char )0 )
#define D_EVENT_INTEGER 'd' #define D_EVENT_INTEGER 'd'
#define D_EVENT_FLOAT 'f' #define D_EVENT_FLOAT 'f'

View file

@ -745,7 +745,7 @@ void idInterpreter::CallEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) { switch( format[ i ] ) {
case D_EVENT_INTEGER : case D_EVENT_INTEGER :
var.intPtr = ( int * )&localstack[ start + pos ]; var.intPtr = ( int * )&localstack[ start + pos ];
data[ i ] = int( *var.floatPtr ); ( *( int * )&data[ i ] ) = int( *var.floatPtr );
break; break;
case D_EVENT_FLOAT : case D_EVENT_FLOAT :
@ -1808,9 +1808,7 @@ bool idInterpreter::Execute( void ) {
case OP_PUSH_V: case OP_PUSH_V:
var_a = GetVariable( st->a ); var_a = GetVariable( st->a );
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->x ) ); PushVector(*var_a.vectorPtr);
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->y ) );
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->z ) );
break; break;
case OP_PUSH_OBJ: case OP_PUSH_OBJ:

View file

@ -30,7 +30,7 @@ If you have questions concerning this license or the applicable additional terms
#define __SCRIPT_INTERPRETER_H__ #define __SCRIPT_INTERPRETER_H__
#define MAX_STACK_DEPTH 64 #define MAX_STACK_DEPTH 64
#define LOCALSTACK_SIZE 6144 #define LOCALSTACK_SIZE (6144 * 2)
typedef struct prstack_s { typedef struct prstack_s {
int s; int s;
@ -60,7 +60,8 @@ private:
void PopParms( int numParms ); void PopParms( int numParms );
void PushString( const char *string ); void PushString( const char *string );
void Push( int value ); void PushVector( const idVec3 &vector );
void Push( intptr_t value );
const char *FloatToString( float value ); const char *FloatToString( float value );
void AppendString( idVarDef *def, const char *from ); void AppendString( idVarDef *def, const char *from );
void SetString( idVarDef *def, const char *from ); void SetString( idVarDef *def, const char *from );
@ -135,12 +136,25 @@ ID_INLINE void idInterpreter::PopParms( int numParms ) {
idInterpreter::Push idInterpreter::Push
==================== ====================
*/ */
ID_INLINE void idInterpreter::Push( int value ) { ID_INLINE void idInterpreter::Push( intptr_t value ) {
if ( localstackUsed + sizeof( int ) > LOCALSTACK_SIZE ) { if ( localstackUsed + sizeof( intptr_t ) > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" ); Error( "Push: locals stack overflow\n" );
} }
*( int * )&localstack[ localstackUsed ] = value; *( intptr_t * )&localstack[ localstackUsed ] = value;
localstackUsed += sizeof( int ); localstackUsed += sizeof( intptr_t );
}
/*
====================
idInterpreter::PushVector
====================
*/
ID_INLINE void idInterpreter::PushVector( const idVec3 &vector ) {
if ( localstackUsed + E_EVENT_SIZEOF_VEC > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" );
}
*( idVec3 * )&localstack[ localstackUsed ] = vector;
localstackUsed += E_EVENT_SIZEOF_VEC;
} }
/* /*

View file

@ -33,20 +33,20 @@ If you have questions concerning this license or the applicable additional terms
// simple types. function types are dynamically allocated // simple types. function types are dynamically allocated
idTypeDef type_void( ev_void, &def_void, "void", 0, NULL ); idTypeDef type_void( ev_void, &def_void, "void", 0, NULL );
idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( void * ), NULL ); idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( intptr_t ), NULL );
idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( void * ), NULL ); idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( intptr_t ), NULL );
idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL ); idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL );
idTypeDef type_float( ev_float, &def_float, "float", sizeof( float ), NULL ); idTypeDef type_float( ev_float, &def_float, "float", sizeof( intptr_t ), NULL );
idTypeDef type_vector( ev_vector, &def_vector, "vector", sizeof( idVec3 ), NULL ); idTypeDef type_vector( ev_vector, &def_vector, "vector", E_EVENT_SIZEOF_VEC, NULL );
idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( int * ), NULL ); // stored as entity number pointer idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( intptr_t ), NULL ); // stored as entity number pointer
idTypeDef type_field( ev_field, &def_field, "field", sizeof( void * ), NULL ); idTypeDef type_field( ev_field, &def_field, "field", sizeof( intptr_t ), NULL );
idTypeDef type_function( ev_function, &def_function, "function", sizeof( void * ), &type_void ); idTypeDef type_function( ev_function, &def_function, "function", sizeof( intptr_t ), &type_void );
idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( int ), NULL ); idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( intptr_t ), NULL );
idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( void * ), NULL ); idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( intptr_t ), NULL );
idTypeDef type_object( ev_object, &def_object, "object", sizeof( int * ), NULL ); // stored as entity number pointer idTypeDef type_object( ev_object, &def_object, "object", sizeof( intptr_t ), NULL ); // stored as entity number pointer
idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( int ), NULL ); // only used for jump opcodes idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( intptr_t ), NULL ); // only used for jump opcodes
idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( int ), NULL ); // only used for function call and thread opcodes idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( intptr_t ), NULL ); // only used for function call and thread opcodes
idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( int ), NULL ); idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( intptr_t ), NULL );
idVarDef def_void( &type_void ); idVarDef def_void( &type_void );
idVarDef def_scriptevent( &type_scriptevent ); idVarDef def_scriptevent( &type_scriptevent );
@ -898,7 +898,7 @@ idScriptObject::Save
================ ================
*/ */
void idScriptObject::Save( idSaveGame *savefile ) const { void idScriptObject::Save( idSaveGame *savefile ) const {
size_t size; int size;
if ( type == &type_object && data == NULL ) { if ( type == &type_object && data == NULL ) {
// Write empty string for uninitialized object // Write empty string for uninitialized object
@ -918,7 +918,7 @@ idScriptObject::Restore
*/ */
void idScriptObject::Restore( idRestoreGame *savefile ) { void idScriptObject::Restore( idRestoreGame *savefile ) {
idStr typeName; idStr typeName;
size_t size; int size;
savefile->ReadString( typeName ); savefile->ReadString( typeName );
@ -931,7 +931,7 @@ void idScriptObject::Restore( idRestoreGame *savefile ) {
savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() ); savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
} }
savefile->ReadInt( (int &)size ); savefile->ReadInt( size );
if ( size != type->Size() ) { if ( size != type->Size() ) {
savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() ); savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
} }
@ -1226,6 +1226,44 @@ void idProgram::AddDefToNameList( idVarDef *def, const char *name ) {
varDefNames[i]->AddDef( def ); varDefNames[i]->AddDef( def );
} }
/*
==============
idProgram::ReserveMem
reserves memory for global variables and returns the starting pointer
==============
*/
byte *idProgram::ReserveMem(int size) {
byte *res = &variables[ numVariables ];
numVariables += size;
if ( numVariables > sizeof( variables ) ) {
throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
}
memset( res, 0, size );
return res;
}
/*
============
idProgram::AllocVarDef
============
*/
idVarDef *idProgram::AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope) {
idVarDef *def;
def = new idVarDef( type );
def->scope = scope;
def->numUsers = 1;
def->num = varDefs.Append( def );
// add the def to the list with defs with this name and set the name pointer
AddDefToNameList( def, name );
return def;
}
/* /*
============ ============
idProgram::AllocDef idProgram::AllocDef
@ -1239,13 +1277,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
idVarDef *def_z; idVarDef *def_z;
// allocate a new def // allocate a new def
def = new idVarDef( type ); def = AllocVarDef(type, name, scope);
def->scope = scope;
def->numUsers = 1;
def->num = varDefs.Append( def );
// add the def to the list with defs with this name and set the name pointer
AddDefToNameList( def, name );
if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) { if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) {
// //
@ -1259,7 +1291,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
scope->value.functionPtr->locals += type->Size(); scope->value.functionPtr->locals += type->Size();
} else if ( scope->TypeDef()->Inherits( &type_object ) ) { } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float ); idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float );
idTypeDef *type = GetType( newtype, true ); idTypeDef *ftype = GetType( newtype, true );
// set the value to the variable's position in the object // set the value to the variable's position in the object
def->value.ptrOffset = scope->TypeDef()->Size(); def->value.ptrOffset = scope->TypeDef()->Size();
@ -1267,30 +1299,52 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
// make automatic defs for the vectors elements // make automatic defs for the vectors elements
// origin can be accessed as origin_x, origin_y, and origin_z // origin can be accessed as origin_x, origin_y, and origin_z
sprintf( element, "%s_x", def->Name() ); sprintf( element, "%s_x", def->Name() );
def_x = AllocDef( type, element, scope, constant ); def_x = AllocDef( ftype, element, scope, constant );
sprintf( element, "%s_y", def->Name() ); sprintf( element, "%s_y", def->Name() );
def_y = AllocDef( type, element, scope, constant ); def_y = AllocDef( ftype, element, scope, constant );
def_y->value.ptrOffset = def_x->value.ptrOffset + type_float.Size(); def_y->value.ptrOffset = def_x->value.ptrOffset + sizeof(float);
sprintf( element, "%s_z", def->Name() ); sprintf( element, "%s_z", def->Name() );
def_z = AllocDef( type, element, scope, constant ); def_z = AllocDef( ftype, element, scope, constant );
def_z->value.ptrOffset = def_y->value.ptrOffset + type_float.Size(); def_z->value.ptrOffset = def_y->value.ptrOffset + sizeof(float);
} else { } else {
idTypeDef newtype( ev_float, &def_float, "vector float", 0, NULL );
idTypeDef *ftype = GetType( newtype, true );
// make automatic defs for the vectors elements // make automatic defs for the vectors elements
// origin can be accessed as origin_x, origin_y, and origin_z // origin can be accessed as origin_x, origin_y, and origin_z
sprintf( element, "%s_x", def->Name() ); sprintf( element, "%s_x", def->Name() );
def_x = AllocDef( &type_float, element, scope, constant ); def_x = AllocVarDef( ftype, element, scope );
sprintf( element, "%s_y", def->Name() ); sprintf( element, "%s_y", def->Name() );
def_y = AllocDef( &type_float, element, scope, constant ); def_y = AllocVarDef( ftype, element, scope );
sprintf( element, "%s_z", def->Name() ); sprintf( element, "%s_z", def->Name() );
def_z = AllocDef( &type_float, element, scope, constant ); def_z = AllocVarDef( ftype, element, scope );
// point the vector def to the x coordinate // get the memory for the full vector and point the _x, _y and _z
def->value = def_x->value; // defs at the vector member offsets
def->initialized = def_x->initialized; if ( scope->Type() == ev_function ) {
// vector on stack
def->value.stackOffset = scope->value.functionPtr->locals;
def->initialized = idVarDef::stackVariable;
scope->value.functionPtr->locals += type->Size();
def_x->value.stackOffset = def->value.stackOffset;
def_y->value.stackOffset = def_x->value.stackOffset + sizeof(float);
def_z->value.stackOffset = def_y->value.stackOffset + sizeof(float);
} else {
// global vector
def->value.bytePtr = ReserveMem(type->Size());
def_x->value.bytePtr = def->value.bytePtr;
def_y->value.bytePtr = def_x->value.bytePtr + sizeof(float);
def_z->value.bytePtr = def_y->value.bytePtr + sizeof(float);
}
def_x->initialized = def->initialized;
def_y->initialized = def->initialized;
def_z->initialized = def->initialized;
} }
} else if ( scope->TypeDef()->Inherits( &type_object ) ) { } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
// //
@ -1317,13 +1371,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
// //
// global variable // global variable
// //
def->value.bytePtr = &variables[ numVariables ]; def->value.bytePtr = ReserveMem(def->TypeDef()->Size());
numVariables += def->TypeDef()->Size();
if ( numVariables > sizeof( variables ) ) {
throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
}
memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
} }
return def; return def;

View file

@ -470,6 +470,8 @@ private:
int top_files; int top_files;
void CompileStats( void ); void CompileStats( void );
byte *ReserveMem(int size);
idVarDef *AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope);
public: public:
idVarDef *returnDef; idVarDef *returnDef;

View file

@ -92,15 +92,15 @@ idEventDef::idEventDef( const char *command, const char *formatspec, char return
switch( formatspec[ i ] ) { switch( formatspec[ i ] ) {
case D_EVENT_FLOAT : case D_EVENT_FLOAT :
bits |= 1 << i; bits |= 1 << i;
argsize += sizeof( float ); argsize += sizeof( intptr_t );
break; break;
case D_EVENT_INTEGER : case D_EVENT_INTEGER :
argsize += sizeof( int ); argsize += sizeof( intptr_t );
break; break;
case D_EVENT_VECTOR : case D_EVENT_VECTOR :
argsize += sizeof( idVec3 ); argsize += E_EVENT_SIZEOF_VEC;
break; break;
case D_EVENT_STRING : case D_EVENT_STRING :

View file

@ -36,6 +36,9 @@ Event are used for scheduling tasks and for linking script commands.
#define D_EVENT_MAXARGS 8 // if changed, enable the CREATE_EVENT_CODE define in Event.cpp to generate switch statement for idClass::ProcessEventArgPtr. #define D_EVENT_MAXARGS 8 // if changed, enable the CREATE_EVENT_CODE define in Event.cpp to generate switch statement for idClass::ProcessEventArgPtr.
// running the game will then generate c:\doom\base\events.txt, the contents of which should be copied into the switch statement. // running the game will then generate c:\doom\base\events.txt, the contents of which should be copied into the switch statement.
// stack size of idVec3, aligned to native pointer size
#define E_EVENT_SIZEOF_VEC ((sizeof(idVec3) + (sizeof(intptr_t) - 1)) & ~(sizeof(intptr_t) - 1))
#define D_EVENT_VOID ( ( char )0 ) #define D_EVENT_VOID ( ( char )0 )
#define D_EVENT_INTEGER 'd' #define D_EVENT_INTEGER 'd'
#define D_EVENT_FLOAT 'f' #define D_EVENT_FLOAT 'f'

View file

@ -745,7 +745,7 @@ void idInterpreter::CallEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) { switch( format[ i ] ) {
case D_EVENT_INTEGER : case D_EVENT_INTEGER :
var.intPtr = ( int * )&localstack[ start + pos ]; var.intPtr = ( int * )&localstack[ start + pos ];
data[ i ] = int( *var.floatPtr ); ( *( int * )&data[ i ] ) = int( *var.floatPtr );
break; break;
case D_EVENT_FLOAT : case D_EVENT_FLOAT :
@ -1808,9 +1808,7 @@ bool idInterpreter::Execute( void ) {
case OP_PUSH_V: case OP_PUSH_V:
var_a = GetVariable( st->a ); var_a = GetVariable( st->a );
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->x ) ); PushVector(*var_a.vectorPtr);
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->y ) );
Push( *reinterpret_cast<int *>( &var_a.vectorPtr->z ) );
break; break;
case OP_PUSH_OBJ: case OP_PUSH_OBJ:

View file

@ -30,7 +30,7 @@ If you have questions concerning this license or the applicable additional terms
#define __SCRIPT_INTERPRETER_H__ #define __SCRIPT_INTERPRETER_H__
#define MAX_STACK_DEPTH 64 #define MAX_STACK_DEPTH 64
#define LOCALSTACK_SIZE 6144 #define LOCALSTACK_SIZE (6144 * 2)
typedef struct prstack_s { typedef struct prstack_s {
int s; int s;
@ -60,7 +60,8 @@ private:
void PopParms( int numParms ); void PopParms( int numParms );
void PushString( const char *string ); void PushString( const char *string );
void Push( int value ); void PushVector( const idVec3 &vector );
void Push( intptr_t value );
const char *FloatToString( float value ); const char *FloatToString( float value );
void AppendString( idVarDef *def, const char *from ); void AppendString( idVarDef *def, const char *from );
void SetString( idVarDef *def, const char *from ); void SetString( idVarDef *def, const char *from );
@ -135,12 +136,25 @@ ID_INLINE void idInterpreter::PopParms( int numParms ) {
idInterpreter::Push idInterpreter::Push
==================== ====================
*/ */
ID_INLINE void idInterpreter::Push( int value ) { ID_INLINE void idInterpreter::Push( intptr_t value ) {
if ( localstackUsed + sizeof( int ) > LOCALSTACK_SIZE ) { if ( localstackUsed + sizeof( intptr_t ) > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" ); Error( "Push: locals stack overflow\n" );
} }
*( int * )&localstack[ localstackUsed ] = value; *( intptr_t * )&localstack[ localstackUsed ] = value;
localstackUsed += sizeof( int ); localstackUsed += sizeof( intptr_t );
}
/*
====================
idInterpreter::PushVector
====================
*/
ID_INLINE void idInterpreter::PushVector( const idVec3 &vector ) {
if ( localstackUsed + E_EVENT_SIZEOF_VEC > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" );
}
*( idVec3 * )&localstack[ localstackUsed ] = vector;
localstackUsed += E_EVENT_SIZEOF_VEC;
} }
/* /*

View file

@ -33,20 +33,20 @@ If you have questions concerning this license or the applicable additional terms
// simple types. function types are dynamically allocated // simple types. function types are dynamically allocated
idTypeDef type_void( ev_void, &def_void, "void", 0, NULL ); idTypeDef type_void( ev_void, &def_void, "void", 0, NULL );
idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( void * ), NULL ); idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( intptr_t ), NULL );
idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( void * ), NULL ); idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( intptr_t ), NULL );
idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL ); idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL );
idTypeDef type_float( ev_float, &def_float, "float", sizeof( float ), NULL ); idTypeDef type_float( ev_float, &def_float, "float", sizeof( intptr_t ), NULL );
idTypeDef type_vector( ev_vector, &def_vector, "vector", sizeof( idVec3 ), NULL ); idTypeDef type_vector( ev_vector, &def_vector, "vector", E_EVENT_SIZEOF_VEC, NULL );
idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( int * ), NULL ); // stored as entity number pointer idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( intptr_t ), NULL ); // stored as entity number pointer
idTypeDef type_field( ev_field, &def_field, "field", sizeof( void * ), NULL ); idTypeDef type_field( ev_field, &def_field, "field", sizeof( intptr_t ), NULL );
idTypeDef type_function( ev_function, &def_function, "function", sizeof( void * ), &type_void ); idTypeDef type_function( ev_function, &def_function, "function", sizeof( intptr_t ), &type_void );
idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( int ), NULL ); idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( intptr_t ), NULL );
idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( void * ), NULL ); idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( intptr_t ), NULL );
idTypeDef type_object( ev_object, &def_object, "object", sizeof( int * ), NULL ); // stored as entity number pointer idTypeDef type_object( ev_object, &def_object, "object", sizeof( intptr_t ), NULL ); // stored as entity number pointer
idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( int ), NULL ); // only used for jump opcodes idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( intptr_t ), NULL ); // only used for jump opcodes
idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( int ), NULL ); // only used for function call and thread opcodes idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( intptr_t ), NULL ); // only used for function call and thread opcodes
idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( int ), NULL ); idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( intptr_t ), NULL );
idVarDef def_void( &type_void ); idVarDef def_void( &type_void );
idVarDef def_scriptevent( &type_scriptevent ); idVarDef def_scriptevent( &type_scriptevent );
@ -898,7 +898,7 @@ idScriptObject::Save
================ ================
*/ */
void idScriptObject::Save( idSaveGame *savefile ) const { void idScriptObject::Save( idSaveGame *savefile ) const {
size_t size; int size;
if ( type == &type_object && data == NULL ) { if ( type == &type_object && data == NULL ) {
// Write empty string for uninitialized object // Write empty string for uninitialized object
@ -918,7 +918,7 @@ idScriptObject::Restore
*/ */
void idScriptObject::Restore( idRestoreGame *savefile ) { void idScriptObject::Restore( idRestoreGame *savefile ) {
idStr typeName; idStr typeName;
size_t size; int size;
savefile->ReadString( typeName ); savefile->ReadString( typeName );
@ -931,7 +931,7 @@ void idScriptObject::Restore( idRestoreGame *savefile ) {
savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() ); savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
} }
savefile->ReadInt( (int &)size ); savefile->ReadInt( size );
if ( size != type->Size() ) { if ( size != type->Size() ) {
savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() ); savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
} }
@ -1226,6 +1226,44 @@ void idProgram::AddDefToNameList( idVarDef *def, const char *name ) {
varDefNames[i]->AddDef( def ); varDefNames[i]->AddDef( def );
} }
/*
==============
idProgram::ReserveMem
reserves memory for global variables and returns the starting pointer
==============
*/
byte *idProgram::ReserveMem(int size) {
byte *res = &variables[ numVariables ];
numVariables += size;
if ( numVariables > sizeof( variables ) ) {
throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
}
memset( res, 0, size );
return res;
}
/*
============
idProgram::AllocVarDef
============
*/
idVarDef *idProgram::AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope) {
idVarDef *def;
def = new idVarDef( type );
def->scope = scope;
def->numUsers = 1;
def->num = varDefs.Append( def );
// add the def to the list with defs with this name and set the name pointer
AddDefToNameList( def, name );
return def;
}
/* /*
============ ============
idProgram::AllocDef idProgram::AllocDef
@ -1239,13 +1277,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
idVarDef *def_z; idVarDef *def_z;
// allocate a new def // allocate a new def
def = new idVarDef( type ); def = AllocVarDef(type, name, scope);
def->scope = scope;
def->numUsers = 1;
def->num = varDefs.Append( def );
// add the def to the list with defs with this name and set the name pointer
AddDefToNameList( def, name );
if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) { if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) {
// //
@ -1259,7 +1291,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
scope->value.functionPtr->locals += type->Size(); scope->value.functionPtr->locals += type->Size();
} else if ( scope->TypeDef()->Inherits( &type_object ) ) { } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float ); idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float );
idTypeDef *type = GetType( newtype, true ); idTypeDef *ftype = GetType( newtype, true );
// set the value to the variable's position in the object // set the value to the variable's position in the object
def->value.ptrOffset = scope->TypeDef()->Size(); def->value.ptrOffset = scope->TypeDef()->Size();
@ -1267,30 +1299,52 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
// make automatic defs for the vectors elements // make automatic defs for the vectors elements
// origin can be accessed as origin_x, origin_y, and origin_z // origin can be accessed as origin_x, origin_y, and origin_z
sprintf( element, "%s_x", def->Name() ); sprintf( element, "%s_x", def->Name() );
def_x = AllocDef( type, element, scope, constant ); def_x = AllocDef( ftype, element, scope, constant );
sprintf( element, "%s_y", def->Name() ); sprintf( element, "%s_y", def->Name() );
def_y = AllocDef( type, element, scope, constant ); def_y = AllocDef( ftype, element, scope, constant );
def_y->value.ptrOffset = def_x->value.ptrOffset + type_float.Size(); def_y->value.ptrOffset = def_x->value.ptrOffset + sizeof(float);
sprintf( element, "%s_z", def->Name() ); sprintf( element, "%s_z", def->Name() );
def_z = AllocDef( type, element, scope, constant ); def_z = AllocDef( ftype, element, scope, constant );
def_z->value.ptrOffset = def_y->value.ptrOffset + type_float.Size(); def_z->value.ptrOffset = def_y->value.ptrOffset + sizeof(float);
} else { } else {
idTypeDef newtype( ev_float, &def_float, "vector float", 0, NULL );
idTypeDef *ftype = GetType( newtype, true );
// make automatic defs for the vectors elements // make automatic defs for the vectors elements
// origin can be accessed as origin_x, origin_y, and origin_z // origin can be accessed as origin_x, origin_y, and origin_z
sprintf( element, "%s_x", def->Name() ); sprintf( element, "%s_x", def->Name() );
def_x = AllocDef( &type_float, element, scope, constant ); def_x = AllocVarDef( ftype, element, scope );
sprintf( element, "%s_y", def->Name() ); sprintf( element, "%s_y", def->Name() );
def_y = AllocDef( &type_float, element, scope, constant ); def_y = AllocVarDef( ftype, element, scope );
sprintf( element, "%s_z", def->Name() ); sprintf( element, "%s_z", def->Name() );
def_z = AllocDef( &type_float, element, scope, constant ); def_z = AllocVarDef( ftype, element, scope );
// point the vector def to the x coordinate // get the memory for the full vector and point the _x, _y and _z
def->value = def_x->value; // defs at the vector member offsets
def->initialized = def_x->initialized; if ( scope->Type() == ev_function ) {
// vector on stack
def->value.stackOffset = scope->value.functionPtr->locals;
def->initialized = idVarDef::stackVariable;
scope->value.functionPtr->locals += type->Size();
def_x->value.stackOffset = def->value.stackOffset;
def_y->value.stackOffset = def_x->value.stackOffset + sizeof(float);
def_z->value.stackOffset = def_y->value.stackOffset + sizeof(float);
} else {
// global vector
def->value.bytePtr = ReserveMem(type->Size());
def_x->value.bytePtr = def->value.bytePtr;
def_y->value.bytePtr = def_x->value.bytePtr + sizeof(float);
def_z->value.bytePtr = def_y->value.bytePtr + sizeof(float);
}
def_x->initialized = def->initialized;
def_y->initialized = def->initialized;
def_z->initialized = def->initialized;
} }
} else if ( scope->TypeDef()->Inherits( &type_object ) ) { } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
// //
@ -1317,13 +1371,7 @@ idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scop
// //
// global variable // global variable
// //
def->value.bytePtr = &variables[ numVariables ]; def->value.bytePtr = ReserveMem(def->TypeDef()->Size());
numVariables += def->TypeDef()->Size();
if ( numVariables > sizeof( variables ) ) {
throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
}
memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
} }
return def; return def;

View file

@ -456,6 +456,8 @@ private:
int top_files; int top_files;
void CompileStats( void ); void CompileStats( void );
byte *ReserveMem(int size);
idVarDef *AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope);
public: public:
idVarDef *returnDef; idVarDef *returnDef;