mirror of
https://github.com/dhewm/dhewm3-sdk.git
synced 2024-11-25 14:01:10 +00:00
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:
parent
dc86a8a02c
commit
f8efcf5e90
12 changed files with 240 additions and 110 deletions
|
@ -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 :
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 :
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue