From 1577ac3a29e942800f41dbcc20cd8eff6641e347 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Tue, 29 Oct 2024 16:51:51 -0400 Subject: [PATCH] Change engine VM memory layout as follows: 0 to 0x7FFFFFFF: reserved. 0x80000000 to 0x80000000 + num_globals - 1: global pointers. 0x80000000 + num_globals to 0x80000000 + num_globals + num_entities * num_entityfields - 1: entity field pointers. Note that there are no instructions yet to _make_ global pointers, or to load values from them. This is the beginning of implementing the pointer instruction set. --- prvm_exec.c | 82 +++++++++++++++------------------ prvm_execprogram.h | 111 ++++++++++++++++++++++++++++----------------- 2 files changed, 105 insertions(+), 88 deletions(-) diff --git a/prvm_exec.c b/prvm_exec.c index e7f54680..02f03398 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -860,7 +860,7 @@ static int PRVM_LeaveFunction (prvm_prog_t *prog) f->tprofile_total += prog->stack[prog->depth].tprofile_acc; f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc; } - + return prog->stack[prog->depth].s; } @@ -922,6 +922,35 @@ extern cvar_t prvm_traceqc; extern cvar_t prvm_statementprofiling; extern qbool prvm_runawaycheck; +#define PRVM_GLOBALSBASE 0x80000000 + +// These do not change. +#define CACHE_UNCHANGING() \ + mstatement_t *cached_statements = prog->statements; \ + qbool cached_allowworldwrites = prog->allowworldwrites; \ + unsigned int cached_flag = prog->flag; \ + unsigned int cached_vmglobals_1 = prog->numglobals - 1; \ + unsigned int cached_vmglobals_3 = prog->numglobals - 3; \ + unsigned int cached_vmglobalsstart = PRVM_GLOBALSBASE; \ + unsigned int cached_vmglobal1 = cached_vmglobalsstart + 1; \ + unsigned int cached_vmentity0start = cached_vmglobalsstart + prog->numglobals; \ + unsigned int cached_vmentity1start = cached_vmentity0start + prog->entityfields; \ + unsigned int cached_entityfields = prog->entityfields; \ + unsigned int cached_entityfields_2 = prog->entityfields - 2; \ + prvm_vec_t *globals = prog->globals.fp; \ + prvm_vec_t *global1 = prog->globals.fp + 1 + +// These may become out of date when a builtin is called, and are updated accordingly. +#define CACHE_CHANGING(DECLARE) \ + DECLARE(prvm_vec_t *) cached_edictsfields = prog->edictsfields.fp; \ + DECLARE(prvm_vec_t *) cached_edictsfields_entity1 = cached_edictsfields + prog->entityfields; \ + DECLARE(unsigned int) cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; \ + DECLARE(unsigned int) cached_entityfieldsarea_entityfields_2 = prog->entityfieldsarea - prog->entityfields - 2; \ + DECLARE(unsigned int) cached_max_edicts = prog->max_edicts + +#define DO_DECLARE(t) t +#define NO_DECLARE(t) + #ifdef PROFILING #ifdef CONFIG_MENU /* @@ -940,21 +969,8 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag double calltime; double tm, starttm; prvm_vec_t tempfloat; - // these may become out of date when a builtin is called, and are updated accordingly - prvm_vec_t *cached_edictsfields = prog->edictsfields.fp; - unsigned int cached_entityfields = prog->entityfields; - unsigned int cached_entityfields_3 = prog->entityfields - 3; - unsigned int cached_entityfieldsarea = prog->entityfieldsarea; - unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; - unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; - unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; - unsigned int cached_max_edicts = prog->max_edicts; - // these do not change - mstatement_t *cached_statements = prog->statements; - qbool cached_allowworldwrites = prog->allowworldwrites; - unsigned int cached_flag = prog->flag; - - prvm_vec_t *globals = prog->globals.fp; + CACHE_UNCHANGING(); + CACHE_CHANGING(DO_DECLARE); calltime = Sys_DirtyTime(); @@ -1049,21 +1065,8 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa double calltime; double tm, starttm; prvm_vec_t tempfloat; - // these may become out of date when a builtin is called, and are updated accordingly - prvm_vec_t *cached_edictsfields = prog->edictsfields.fp; - unsigned int cached_entityfields = prog->entityfields; - unsigned int cached_entityfields_3 = prog->entityfields - 3; - unsigned int cached_entityfieldsarea = prog->entityfieldsarea; - unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; - unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; - unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; - unsigned int cached_max_edicts = prog->max_edicts; - // these do not change - mstatement_t *cached_statements = prog->statements; - qbool cached_allowworldwrites = prog->allowworldwrites; - unsigned int cached_flag = prog->flag; - - prvm_vec_t *globals = prog->globals.fp; + CACHE_UNCHANGING(); + CACHE_CHANGING(DO_DECLARE); calltime = Sys_DirtyTime(); @@ -1162,21 +1165,8 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa double calltime; double tm, starttm; prvm_vec_t tempfloat; - // these may become out of date when a builtin is called, and are updated accordingly - prvm_vec_t *cached_edictsfields = prog->edictsfields.fp; - unsigned int cached_entityfields = prog->entityfields; - unsigned int cached_entityfields_3 = prog->entityfields - 3; - unsigned int cached_entityfieldsarea = prog->entityfieldsarea; - unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; - unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; - unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; - unsigned int cached_max_edicts = prog->max_edicts; - // these do not change - mstatement_t *cached_statements = prog->statements; - qbool cached_allowworldwrites = prog->allowworldwrites; - unsigned int cached_flag = prog->flag; - - prvm_vec_t *globals = prog->globals.fp; + CACHE_UNCHANGING(); + CACHE_CHANGING(DO_DECLARE); calltime = Sys_DirtyTime(); diff --git a/prvm_execprogram.h b/prvm_execprogram.h index 34dd8d29..68d0a673 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -1,5 +1,6 @@ extern cvar_t prvm_garbagecollection_enable; int i; +prvm_uint_t addr; // NEED to reset startst after calling this! startst may or may not be clobbered! #define ADVANCE_PROFILE_BEFORE_JUMP() \ prog->xfunction->profile += (st - startst); \ @@ -229,7 +230,7 @@ int i; &&handle_OP_GE_I, &&handle_OP_LT_I, &&handle_OP_GT_I, - + &&handle_OP_LE_IF, &&handle_OP_GE_IF, &&handle_OP_LT_IF, @@ -274,7 +275,7 @@ int i; &&handle_OP_GSTOREP_ENT, &&handle_OP_GSTOREP_FLD, &&handle_OP_GSTOREP_S, - &&handle_OP_GSTOREP_FNC, + &&handle_OP_GSTOREP_FNC, &&handle_OP_GSTOREP_V, &&handle_OP_GADDRESS, &&handle_OP_GLOAD_I, @@ -478,37 +479,60 @@ int i; HANDLE_OPCODE(OP_STOREP_ENT): HANDLE_OPCODE(OP_STOREP_FLD): // integers HANDLE_OPCODE(OP_STOREP_FNC): // pointers - if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields) + if ((addr = (prvm_uint_t)OPB->_int - cached_vmentity1start) < cached_entityfieldsarea_entityfields) { - if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea) - { - PRE_ERROR(); - prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); - goto cleanup; - } - if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites) + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + } + else if ((addr = (prvm_uint_t)OPB->_int - cached_vmglobal1) < cached_vmglobals_1) + { + // OK global write. + ptr = (prvm_eval_t *)(global1 + addr); + } + else if ((prvm_uint_t)OPB->_int - cached_vmentity0start < cached_entityfields) + { + if (!cached_allowworldwrites) { PRE_ERROR(); VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int); + // Perform entity write anyway. } + ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; } - ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); ptr->_int = OPA->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_STOREP_S): - if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields) + if ((addr = (prvm_uint_t)OPB->_int - cached_vmentity1start) < cached_entityfieldsarea_entityfields) { - if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea) - { - PRE_ERROR(); - prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); - goto cleanup; - } - if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites) + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + } + else if ((addr = (prvm_uint_t)OPB->_int - cached_vmglobal1) < cached_vmglobals_1) + { + // OK global write. + ptr = (prvm_eval_t *)(global1 + addr); + } + else if ((prvm_uint_t)OPB->_int - cached_vmentity0start < cached_entityfields) + { + if (!cached_allowworldwrites) { PRE_ERROR(); VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int); + // Perform entity write anyway. } + ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; } // refresh the garbage collection on the string - this guards // against a certain sort of repeated migration to earlier @@ -516,25 +540,35 @@ int i; // being freed for being unused if(prvm_garbagecollection_enable.integer) PRVM_GetString(prog, OPA->_int); - ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); ptr->_int = OPA->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_STOREP_V): - if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3) + if ((addr = (prvm_uint_t)OPB->_int - cached_vmentity1start) < cached_entityfieldsarea_entityfields_2) { - if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3) - { - PRE_ERROR(); - prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); - goto cleanup; - } - if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites) + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + } + else if ((addr = (prvm_uint_t)OPB->_int - cached_vmglobal1) < cached_vmglobals_3) + { + // OK global write. + ptr = (prvm_eval_t *)(global1 + OPB->_int); + } + else if ((prvm_uint_t)OPB->_int - cached_vmentity0start < cached_entityfields_2) + { + if (!cached_allowworldwrites) { PRE_ERROR(); VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int); + // Perform entity write anyway. } + ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; } - ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); ptr->ivector[0] = OPA->ivector[0]; ptr->ivector[1] = OPA->ivector[1]; ptr->ivector[2] = OPA->ivector[2]; @@ -561,7 +595,7 @@ int i; goto cleanup; } #endif - OPC->_int = OPA->edict * cached_entityfields + OPB->_int; + OPC->_int = cached_vmentity0start + OPA->edict * cached_entityfields + OPB->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_LOAD_F): @@ -613,7 +647,7 @@ int i; prog->error_cmd("%s attempted to read an out of bounds edict number", prog->name); goto cleanup; } - if ((prvm_uint_t)OPB->_int > cached_entityfields_3) + if ((prvm_uint_t)OPB->_int >= cached_entityfields_2) { PRE_ERROR(); prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int); @@ -691,7 +725,7 @@ int i; HANDLE_OPCODE(OP_CALL6): HANDLE_OPCODE(OP_CALL7): HANDLE_OPCODE(OP_CALL8): -#ifdef PRVMTIMEPROFILING +#ifdef PRVMTIMEPROFILING tm = Sys_DirtyTime(); prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; starttm = tm; @@ -724,21 +758,14 @@ int i; if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber]) { prog->builtins[builtinnumber](prog); -#ifdef PRVMTIMEPROFILING +#ifdef PRVMTIMEPROFILING tm = Sys_DirtyTime(); enterfunc->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; prog->xfunction->tbprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; starttm = tm; #endif // builtins may cause ED_Alloc() to be called, update cached variables - cached_edictsfields = prog->edictsfields.fp; - cached_entityfields = prog->entityfields; - cached_entityfields_3 = prog->entityfields - 3; - cached_entityfieldsarea = prog->entityfieldsarea; - cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; - cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; - cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; - cached_max_edicts = prog->max_edicts; + CACHE_CHANGING(NO_DECLARE); // these do not change //cached_statements = prog->statements; //cached_allowworldwrites = prog->allowworldwrites; @@ -757,7 +784,7 @@ int i; HANDLE_OPCODE(OP_DONE): HANDLE_OPCODE(OP_RETURN): -#ifdef PRVMTIMEPROFILING +#ifdef PRVMTIMEPROFILING tm = Sys_DirtyTime(); prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; starttm = tm; -- 2.39.2