]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
Change engine VM memory layout as follows:
authorRudolf Polzer <divVerent@gmail.com>
Tue, 29 Oct 2024 20:51:51 +0000 (16:51 -0400)
committerRudolf Polzer <divVerent@gmail.com>
Fri, 1 Nov 2024 19:28:46 +0000 (15:28 -0400)
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
prvm_execprogram.h

index e7f5468092aa23d6f4c4ca4e29cba7514ad57992..02f03398c7fb70c2541b425e6ff76caa985ef039 100644 (file)
@@ -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();
 
index 34dd8d29d67dac02a10d03d9ecbc24dc5f8920d4..68d0a673a1988781786e6eec4b4c5d6245adfa1f 100644 (file)
@@ -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;