From 3c1679a5f2b24ab5e0a301dde14de609df3677b1 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Thu, 31 Oct 2024 19:40:21 -0400 Subject: [PATCH] Add ADD_PIW, GLOBALADDRESS, LOADA_* and LOADP_* instructions. This is used by FTEQCC array and pointer support. --- prvm_edict.c | 23 ++++- prvm_exec.c | 9 +- prvm_execprogram.h | 207 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 191 insertions(+), 48 deletions(-) diff --git a/prvm_edict.c b/prvm_edict.c index 3f97d38e..f753385d 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -2316,7 +2316,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[1] = prog->statements[i].operand[2] = op; break; - case OP_STORE_I: case OP_ADD_I: case OP_ADD_FI: case OP_ADD_IF: @@ -2326,7 +2325,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data case OP_CONV_IF: case OP_CONV_FI: case OP_LOAD_I: - case OP_STOREP_I: case OP_BITAND_I: case OP_BITOR_I: case OP_MUL_I: @@ -2335,7 +2333,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data case OP_NE_I: case OP_NOT_I: case OP_DIV_VF: - case OP_STORE_P: case OP_LE_I: case OP_GE_I: case OP_LT_I: @@ -2419,6 +2416,23 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data case OP_LOAD_S: case OP_LOAD_FNC: case OP_LOAD_V: + case OP_LOAD_P: + case OP_ADD_PIW: + case OP_GLOBALADDRESS: + case OP_LOADA_F: + case OP_LOADA_V: + case OP_LOADA_S: + case OP_LOADA_ENT: + case OP_LOADA_FLD: + case OP_LOADA_FNC: + case OP_LOADA_I: + case OP_LOADP_F: + case OP_LOADP_V: + case OP_LOADP_S: + case OP_LOADP_ENT: + case OP_LOADP_FLD: + case OP_LOADP_FNC: + case OP_LOADP_I: if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals) prog->error_cmd("%s: out of bounds global index (statement %d)", __func__, i); prog->statements[i].op = op; @@ -2446,6 +2460,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data case OP_STOREP_S: case OP_STOREP_FNC: case OP_STOREP_V: + case OP_STOREP_I: if (c) //Spike -- DP is alergic to pointers in QC. Try to avoid too many nasty surprises. Con_DPrintf("%s: storep-with-offset is not permitted in %s\n", __func__, prog->name); if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals) @@ -2461,6 +2476,8 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data case OP_STORE_S: case OP_STORE_FNC: case OP_STORE_V: + case OP_STORE_I: + case OP_STORE_P: case OP_STATE: if (a >= prog->progs_numglobals || b >= prog->progs_numglobals) prog->error_cmd("%s: out of bounds global index (statement %d) in %s", __func__, i, prog->name); diff --git a/prvm_exec.c b/prvm_exec.c index 02f03398..8cfc97a9 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -929,11 +929,12 @@ extern qbool prvm_runawaycheck; mstatement_t *cached_statements = prog->statements; \ qbool cached_allowworldwrites = prog->allowworldwrites; \ unsigned int cached_flag = prog->flag; \ + unsigned int cached_vmglobals = prog->numglobals; \ unsigned int cached_vmglobals_1 = prog->numglobals - 1; \ + unsigned int cached_vmglobals_2 = prog->numglobals - 2; \ 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_vmglobal1 = PRVM_GLOBALSBASE + 1; \ + unsigned int cached_vmentity0start = PRVM_GLOBALSBASE + prog->numglobals; \ unsigned int cached_vmentity1start = cached_vmentity0start + prog->entityfields; \ unsigned int cached_entityfields = prog->entityfields; \ unsigned int cached_entityfields_2 = prog->entityfields - 2; \ @@ -944,6 +945,8 @@ extern qbool prvm_runawaycheck; #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 = prog->entityfieldsarea; \ + DECLARE(unsigned int) cached_entityfieldsarea_2 = prog->entityfieldsarea - 2; \ 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 diff --git a/prvm_execprogram.h b/prvm_execprogram.h index ce532edb..6b112342 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -1,6 +1,7 @@ extern cvar_t prvm_garbagecollection_enable; int i; -prvm_uint_t ofs, addr; +prvm_uint_t addr, ofs; +prvm_eval_t *src; // NEED to reset startst after calling this! startst may or may not be clobbered! #define ADVANCE_PROFILE_BEFORE_JUMP() \ prog->xfunction->profile += (st - startst); \ @@ -205,26 +206,26 @@ prvm_uint_t ofs, addr; NULL, NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + &&handle_OP_GLOBALADDRESS, + &&handle_OP_ADD_PIW, + &&handle_OP_LOADA_F, + &&handle_OP_LOADA_V, + &&handle_OP_LOADA_S, + &&handle_OP_LOADA_ENT, + &&handle_OP_LOADA_FLD, + &&handle_OP_LOADA_FNC, + &&handle_OP_LOADA_I, &&handle_OP_STORE_P, + &&handle_OP_LOAD_P, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + &&handle_OP_LOADP_F, + &&handle_OP_LOADP_V, + &&handle_OP_LOADP_S, + &&handle_OP_LOADP_ENT, + &&handle_OP_LOADP_FLD, + &&handle_OP_LOADP_FNC, + &&handle_OP_LOADP_I, &&handle_OP_LE_I, &&handle_OP_GE_I, @@ -479,26 +480,26 @@ prvm_uint_t ofs, addr; HANDLE_OPCODE(OP_STOREP_ENT): HANDLE_OPCODE(OP_STOREP_FLD): // integers HANDLE_OPCODE(OP_STOREP_FNC): // pointers - ofs = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; - if ((addr = ofs - cached_vmentity1start) < cached_entityfieldsarea_entityfields) + addr = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; + if ((ofs = addr - cached_vmentity1start) < cached_entityfieldsarea_entityfields) { // OK entity write. - ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + ofs); } - else if ((addr = ofs - cached_vmglobal1) < cached_vmglobals_1) + else if ((ofs = addr - cached_vmglobal1) < cached_vmglobals_1) { // OK global write. - ptr = (prvm_eval_t *)(global1 + addr); + ptr = (prvm_eval_t *)(global1 + ofs); } - else if ((addr = ofs - cached_vmentity0start) < cached_entityfields) + else if ((ofs = addr - cached_vmentity0start) < cached_entityfields) { if (!cached_allowworldwrites) { PRE_ERROR(); - VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, addr)->s_name), OPB->_int, OPC->_int); + VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, ofs)->s_name), OPB->_int, OPC->_int); // Perform entity write anyway. } - ptr = (prvm_eval_t *)(cached_edictsfields + addr); + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); } else { @@ -509,26 +510,26 @@ prvm_uint_t ofs, addr; ptr->_int = OPA->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_STOREP_S): - ofs = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; - if ((addr = ofs - cached_vmentity1start) < cached_entityfieldsarea_entityfields) + addr = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; + if ((ofs = addr - cached_vmentity1start) < cached_entityfieldsarea_entityfields) { // OK entity write. - ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + ofs); } - else if ((addr = ofs - cached_vmglobal1) < cached_vmglobals_1) + else if ((ofs = addr - cached_vmglobal1) < cached_vmglobals_1) { // OK global write. - ptr = (prvm_eval_t *)(global1 + addr); + ptr = (prvm_eval_t *)(global1 + ofs); } - else if ((addr = ofs - cached_vmentity0start) < cached_entityfields) + else if ((ofs = addr - cached_vmentity0start) < cached_entityfields) { if (!cached_allowworldwrites) { PRE_ERROR(); - VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, addr)->s_name), OPB->_int, OPC->_int); + VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, ofs)->s_name), OPB->_int, OPC->_int); // Perform entity write anyway. } - ptr = (prvm_eval_t *)(cached_edictsfields + addr); + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); } else { @@ -545,26 +546,26 @@ prvm_uint_t ofs, addr; ptr->_int = OPA->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_STOREP_V): - ofs = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; - if ((addr = ofs - cached_vmentity1start) < cached_entityfieldsarea_entityfields_2) + addr = (prvm_uint_t)OPB->_int + (prvm_uint_t)OPC->_int; + if ((ofs = addr - cached_vmentity1start) < cached_entityfieldsarea_entityfields_2) { // OK entity write. - ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + addr); + ptr = (prvm_eval_t *)(cached_edictsfields_entity1 + ofs); } - else if ((addr = ofs - cached_vmglobal1) < cached_vmglobals_3) + else if ((ofs = addr - cached_vmglobal1) < cached_vmglobals_3) { // OK global write. - ptr = (prvm_eval_t *)(global1 + addr); + ptr = (prvm_eval_t *)(global1 + ofs); } - else if ((addr = ofs - cached_vmentity0start) < cached_entityfields_2) + else if ((ofs = addr - cached_vmentity0start) < cached_entityfields_2) { if (!cached_allowworldwrites) { PRE_ERROR(); - VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, addr)->s_name), OPB->_int, OPC->_int); + VM_Warning(prog, "Attempted assignment to world.%s (edictnum 0 field %i+%i)\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, ofs)->s_name), OPB->_int, OPC->_int); // Perform entity write anyway. } - ptr = (prvm_eval_t *)(cached_edictsfields + addr); + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); } else { @@ -605,6 +606,7 @@ prvm_uint_t ofs, addr; HANDLE_OPCODE(OP_LOAD_FLD): HANDLE_OPCODE(OP_LOAD_ENT): HANDLE_OPCODE(OP_LOAD_FNC): + HANDLE_OPCODE(OP_LOAD_P): if ((prvm_uint_t)OPA->edict >= cached_max_edicts) { PRE_ERROR(); @@ -1077,6 +1079,127 @@ prvm_uint_t ofs, addr; } DISPATCH_OPCODE(); + // FTEQW pointer instructions. + HANDLE_OPCODE(OP_GLOBALADDRESS): + OPC->_int = PRVM_GLOBALSBASE + st->operand[0] + 1 * OPB->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_ADD_PIW): + OPC->_int = OPA->_int + 1 * OPB->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADA_F): + HANDLE_OPCODE(OP_LOADA_ENT): + HANDLE_OPCODE(OP_LOADA_FLD): + HANDLE_OPCODE(OP_LOADA_FNC): + HANDLE_OPCODE(OP_LOADA_I): + ofs = st->operand[0] + OPB->_int; + if (ofs >= cached_vmglobals) + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)st->operand[0], OPB->_int); + goto cleanup; + } + src = (prvm_eval_t *)&globals[ofs]; + OPC->_int = src->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADA_S): + ofs = st->operand[0] + OPB->_int; + if (ofs >= cached_vmglobals) + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)st->operand[0], OPB->_int); + goto cleanup; + } + src = (prvm_eval_t *)&globals[ofs]; + // refresh the garbage collection on the string - this guards + // against a certain sort of repeated migration to earlier + // points in the scan that could otherwise result in the string + // being freed for being unused + if(prvm_garbagecollection_enable.integer) + PRVM_GetString(prog, src->_int); + OPC->_int = src->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADA_V): + ofs = st->operand[0] + OPB->_int; + if (ofs >= cached_vmglobals_2) + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)st->operand[0], OPB->_int); + goto cleanup; + } + src = (prvm_eval_t *)&globals[ofs]; + OPC->ivector[0] = src->ivector[0]; + OPC->ivector[1] = src->ivector[1]; + OPC->ivector[2] = src->ivector[2]; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADP_F): + HANDLE_OPCODE(OP_LOADP_ENT): + HANDLE_OPCODE(OP_LOADP_FLD): // integers + HANDLE_OPCODE(OP_LOADP_FNC): // pointers + HANDLE_OPCODE(OP_LOADP_I): + addr = (prvm_uint_t)OPA->_int + (prvm_uint_t)OPB->_int; + if ((ofs = addr - cached_vmentity0start) < cached_entityfieldsarea) + { + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); + } + else if ((ofs = addr - PRVM_GLOBALSBASE) < cached_vmglobals) + { + // OK global write. + ptr = (prvm_eval_t *)(globals + ofs); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)OPA->_int, OPB->_int); + goto cleanup; + } + OPC->_int = ptr->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADP_S): + addr = (prvm_uint_t)OPA->_int + (prvm_uint_t)OPB->_int; + if ((ofs = addr - cached_vmentity0start) < cached_entityfieldsarea) + { + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); + } + else if ((ofs = addr - PRVM_GLOBALSBASE) < cached_vmglobals) + { + // OK global write. + ptr = (prvm_eval_t *)(globals + ofs); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)OPA->_int, OPB->_int); + goto cleanup; + } + if(prvm_garbagecollection_enable.integer) + PRVM_GetString(prog, ptr->_int); + OPC->_int = ptr->_int; + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOADP_V): + addr = (prvm_uint_t)OPA->_int + (prvm_uint_t)OPB->_int; + if ((ofs = addr - cached_vmentity0start) < cached_entityfieldsarea_2) + { + // OK entity write. + ptr = (prvm_eval_t *)(cached_edictsfields + ofs); + } + else if ((ofs = addr - PRVM_GLOBALSBASE) < cached_vmglobals_2) + { + // OK global write. + ptr = (prvm_eval_t *)(globals + ofs); + } + else + { + PRE_ERROR(); + prog->error_cmd("%s attempted to read from an out of bounds address %u+%i", prog->name, (unsigned int)OPA->_int, OPB->_int); + goto cleanup; + } + OPC->ivector[0] = ptr->ivector[0]; + OPC->ivector[1] = ptr->ivector[1]; + OPC->ivector[2] = ptr->ivector[2]; + DISPATCH_OPCODE(); + #if !USE_COMPUTED_GOTOS default: PRE_ERROR(); -- 2.39.2