X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=prvm_exec.c;h=6dfdc150d2e1179956c3fe8a9a181475ac0fbae8;hp=9816450c5dedb4281a664cb6fb3f9a66b8759595;hb=fda81eb8eb6440b8bef219f615ea25a6073c0ba2;hpb=e11263d3ea167699c332c40802df925881d8a58d diff --git a/prvm_exec.c b/prvm_exec.c index 9816450c..6dfdc150 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -19,10 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "progsvm.h" char *prvm_opnames[] = { -"DONE", +"^5DONE", "MUL_F", "MUL_V", @@ -37,31 +38,31 @@ char *prvm_opnames[] = "SUB_F", "SUB_V", -"EQ_F", -"EQ_V", -"EQ_S", -"EQ_E", -"EQ_FNC", +"^2EQ_F", +"^2EQ_V", +"^2EQ_S", +"^2EQ_E", +"^2EQ_FNC", -"NE_F", -"NE_V", -"NE_S", -"NE_E", -"NE_FNC", +"^2NE_F", +"^2NE_V", +"^2NE_S", +"^2NE_E", +"^2NE_FNC", -"LE", -"GE", -"LT", -"GT", +"^2LE", +"^2GE", +"^2LT", +"^2GT", -"INDIRECT", -"INDIRECT", -"INDIRECT", -"INDIRECT", -"INDIRECT", -"INDIRECT", +"^6FIELD_F", +"^6FIELD_V", +"^6FIELD_S", +"^6FIELD_ENT", +"^6FIELD_FLD", +"^6FIELD_FNC", -"ADDRESS", +"^1ADDRESS", "STORE_F", "STORE_V", @@ -70,40 +71,40 @@ char *prvm_opnames[] = "STORE_FLD", "STORE_FNC", -"STOREP_F", -"STOREP_V", -"STOREP_S", -"STOREP_ENT", -"STOREP_FLD", -"STOREP_FNC", +"^1STOREP_F", +"^1STOREP_V", +"^1STOREP_S", +"^1STOREP_ENT", +"^1STOREP_FLD", +"^1STOREP_FNC", -"RETURN", +"^5RETURN", -"NOT_F", -"NOT_V", -"NOT_S", -"NOT_ENT", -"NOT_FNC", +"^2NOT_F", +"^2NOT_V", +"^2NOT_S", +"^2NOT_ENT", +"^2NOT_FNC", -"IF", -"IFNOT", +"^5IF", +"^5IFNOT", -"CALL0", -"CALL1", -"CALL2", -"CALL3", -"CALL4", -"CALL5", -"CALL6", -"CALL7", -"CALL8", +"^3CALL0", +"^3CALL1", +"^3CALL2", +"^3CALL3", +"^3CALL4", +"^3CALL5", +"^3CALL6", +"^3CALL7", +"^3CALL8", -"STATE", +"^1STATE", -"GOTO", +"^5GOTO", -"AND", -"OR", +"^2AND", +"^2OR", "BITAND", "BITOR" @@ -111,6 +112,7 @@ char *prvm_opnames[] = char *PRVM_GlobalString (int ofs); char *PRVM_GlobalStringNoContents (int ofs); +extern ddef_t *PRVM_ED_FieldAtOfs(int ofs); //============================================================================= @@ -120,39 +122,125 @@ char *PRVM_GlobalStringNoContents (int ofs); PRVM_PrintStatement ================= */ +extern cvar_t prvm_statementprofiling; void PRVM_PrintStatement (dstatement_t *s) { - int i; + size_t i; + int opnum = (int)(s - prog->statements); + + Con_Printf("s%i: ", opnum); + if( prog->statement_linenums ) + Con_Printf( "%s:%i: ", PRVM_GetString( prog->xfunction->s_file ), prog->statement_linenums[ opnum ] ); + + if (prvm_statementprofiling.integer) + Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]); if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0])) { - Con_Printf ("%s ", prvm_opnames[s->op]); + Con_Printf("%s ", prvm_opnames[s->op]); i = strlen(prvm_opnames[s->op]); + // don't count a preceding color tag when padding the name + if (prvm_opnames[s->op][0] == STRING_COLOR_TAG) + i -= 2; for ( ; i<10 ; i++) - Con_Printf (" "); + Con_Print(" "); } - if (s->op == OP_IF || s->op == OP_IFNOT) - Con_Printf ("%sbranch %i",PRVM_GlobalString((unsigned short) s->a),s->b); + Con_Printf("%s, s%i",PRVM_GlobalString((unsigned short) s->a),(signed short)s->b + opnum); else if (s->op == OP_GOTO) + Con_Printf("s%i",(signed short)s->a + opnum); + else if ( (unsigned)(s->op - OP_STORE_F) < 6) { - Con_Printf ("branch %i",s->a); + Con_Print(PRVM_GlobalString((unsigned short) s->a)); + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b)); } - else if ( (unsigned)(s->op - OP_STORE_F) < 6) + else if (s->op == OP_ADDRESS || (unsigned)(s->op - OP_LOAD_F) < 6) { - Con_Printf ("%s", PRVM_GlobalString((unsigned short) s->a)); - Con_Printf ("%s", PRVM_GlobalStringNoContents((unsigned short) s->b)); + if (s->a) + Con_Print(PRVM_GlobalString((unsigned short) s->a)); + if (s->b) + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b)); + } + if (s->c) + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c)); + } } else { if (s->a) - Con_Printf ("%s", PRVM_GlobalString((unsigned short) s->a)); + Con_Print(PRVM_GlobalString((unsigned short) s->a)); if (s->b) - Con_Printf ("%s", PRVM_GlobalString((unsigned short) s->b)); + { + Con_Print(", "); + Con_Print(PRVM_GlobalString((unsigned short) s->b)); + } if (s->c) - Con_Printf ("%s", PRVM_GlobalStringNoContents((unsigned short) s->c)); + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c)); + } + } + Con_Print("\n"); +} + +void PRVM_PrintFunctionStatements (const char *name) +{ + int i, firststatement, endstatement; + mfunction_t *func; + func = PRVM_ED_FindFunction (name); + if (!func) + { + Con_Printf("%s progs: no function named %s\n", PRVM_NAME, name); + return; + } + firststatement = func->first_statement; + if (firststatement < 0) + { + Con_Printf("%s progs: function %s is builtin #%i\n", PRVM_NAME, name, -firststatement); + return; + } + + // find the end statement + endstatement = prog->progs->numstatements; + for (i = 0;i < prog->progs->numfunctions;i++) + if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement) + endstatement = prog->functions[i].first_statement; + + // now print the range of statements + Con_Printf("%s progs: disassembly of function %s (statements %i-%i, locals %i-%i):\n", PRVM_NAME, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1); + for (i = firststatement;i < endstatement;i++) + { + PRVM_PrintStatement(prog->statements + i); + prog->statement_profile[i] = 0; + } +} + +/* +============ +PRVM_PrintFunction_f + +============ +*/ +void PRVM_PrintFunction_f (void) +{ + if (Cmd_Argc() != 3) + { + Con_Printf("usage: prvm_printfunction \n"); + return; } - Con_Printf ("\n"); + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_PrintFunctionStatements(Cmd_Argv(2)); + + PRVM_End; } /* @@ -172,36 +260,89 @@ void PRVM_StackTrace (void) f = prog->stack[i].f; if (!f) - Con_Printf ("\n"); + Con_Print("\n"); else - Con_Printf ("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement); + Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement); } } +void PRVM_ShortStackTrace(char *buf, size_t bufsize) +{ + mfunction_t *f; + int i; -/* -============ -PRVM_Profile_f + if(prog) + { + dpsnprintf(buf, bufsize, "(%s) ", prog->name); + } + else + { + strlcpy(buf, "", bufsize); + return; + } -============ -*/ -void PRVM_Profile_f (void) + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + for (i = prog->depth;i > 0;i--) + { + f = prog->stack[i].f; + + if(strlcat(buf, + f + ? va("%s:%s(%i) ", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement) + : " ", + bufsize + ) >= bufsize) + break; + } +} + + +void PRVM_CallProfile (void) { mfunction_t *f, *best; - int i, num, max/*, howmany*/; + int i; + double max; + double sum; - //howmany = 10; - //if (Cmd_Argc() == 2) - // howmany = atoi(Cmd_Argv(1)); - if(Cmd_Argc() != 2) + Con_Printf( "%s Call Profile:\n", PRVM_NAME ); + + sum = 0; + do { - Con_Printf("prvm_profile \n"); - return; - } + max = 0; + best = NULL; + for (i=0 ; iprogs->numfunctions ; i++) + { + f = &prog->functions[i]; + if (max < f->totaltime) + { + max = f->totaltime; + best = f; + } + } + if (best) + { + sum += best->totaltime; + Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(best->s_name)); + best->totaltime = 0; + } + } while (best); - PRVM_Begin; - if(!PRVM_SetProgFromString(Cmd_Argv(1))) - return; + Con_Printf("Total time since last profile reset: %9.4f\n", Sys_DoubleTime() - prog->starttime); + Con_Printf(" - used by QC code of this VM: %9.4f\n", sum); + + prog->starttime = Sys_DoubleTime(); +} + +void PRVM_Profile (int maxfunctions, int mininstructions, int sortby) +{ + mfunction_t *f, *best; + int i, num; + double max; + + Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", PRVM_NAME ); + // 12345678901 12345678901 12345678901 12345678901 12345678901 123.45% num = 0; do @@ -211,26 +352,117 @@ void PRVM_Profile_f (void) for (i=0 ; iprogs->numfunctions ; i++) { f = &prog->functions[i]; - if (f->profile > max) + if(sortby) { - max = f->profile; - best = f; + if (max < f->profile_total + f->builtinsprofile_total + f->callcount) + { + max = f->profile_total + f->builtinsprofile_total + f->callcount; + best = f; + } + } + else + { + if (max < f->profile + f->builtinsprofile + f->callcount) + { + max = f->profile + f->builtinsprofile + f->callcount; + best = f; + } } } if (best) { - //if (num < howmany) - Con_Printf ("%s: %7i %7i %s\n", PRVM_NAME, best->profile, best->builtinsprofile, PRVM_GetString(best->s_name)); + if (num < maxfunctions && max >= mininstructions) + { + if (best->first_statement < 0) + Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(best->s_name)); + // 12345678901 12345678901 12345678901 12345678901 123.45% + else + Con_Printf("%11.0f %11.0f %11.0f %11.0f %11.0f %6.2f%% %s\n", best->callcount, best->profile, best->builtinsprofile, best->profile_total, best->builtinsprofile_total, (best->profile + best->builtinsprofile) * 100.0 / (best->profile_total + best->builtinsprofile_total), PRVM_GetString(best->s_name)); + } num++; best->profile = 0; best->builtinsprofile = 0; + best->profile_total = 0; + best->builtinsprofile_total = 0; + best->callcount = 0; } } while (best); +} + +/* +============ +PRVM_CallProfile_f + +============ +*/ +void PRVM_CallProfile_f (void) +{ + if (Cmd_Argc() != 2) + { + Con_Print("prvm_callprofile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_CallProfile(); + + PRVM_End; +} + +/* +============ +PRVM_Profile_f + +============ +*/ +void PRVM_Profile_f (void) +{ + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_profile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_Profile(howmany, 1, 0); PRVM_End; } -void PRVM_CrashAll() +void PRVM_ChildProfile_f (void) +{ + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_childprofile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_Profile(howmany, 1, 1); + + PRVM_End; +} + +void PRVM_CrashAll(void) { int i; prvm_prog_t *oldprog = prog; @@ -242,41 +474,59 @@ void PRVM_CrashAll() PRVM_SetProg(i); PRVM_Crash(); } - + prog = oldprog; } void PRVM_PrintState(void) { int i; + if(prog->statestring) + { + Con_Printf("Caller-provided information: %s\n", prog->statestring); + } if (prog->xfunction) { - for (i = -4;i <= 0;i++) + for (i = -7; i <= 0;i++) if (prog->xstatement + i >= prog->xfunction->first_statement) PRVM_PrintStatement (prog->statements + prog->xstatement + i); } else - Con_Printf("null function executing??\n"); + Con_Print("null function executing??\n"); PRVM_StackTrace (); } -void PRVM_Crash() +extern sizebuf_t vm_tempstringsbuf; +extern cvar_t prvm_errordump; +void Host_Savegame_to (const char *name); +void PRVM_Crash(void) { - if (prog->depth < 1) - { - // kill the stack just to be sure - prog->depth = 0; - prog->localstack_used = 0; + if (prog == NULL) return; + + prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash + + if( prog->depth > 0 ) + { + Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME); + PRVM_PrintState(); } - Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME); - PRVM_PrintState(); + if(prvm_errordump.integer) + { + // make a savegame + Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME)); + } // dump the stack so host_error can shutdown functions prog->depth = 0; prog->localstack_used = 0; + // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?) + vm_tempstringsbuf.cursize = 0; + + // reset the prog pointer + prog = NULL; } /* @@ -299,10 +549,12 @@ int PRVM_EnterFunction (mfunction_t *f) int i, j, c, o; if (!f) - PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s\n", PRVM_NAME); + PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME); prog->stack[prog->depth].s = prog->xstatement; prog->stack[prog->depth].f = prog->xfunction; + prog->stack[prog->depth].profile_acc = -f->profile; + prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile; prog->depth++; if (prog->depth >=PRVM_MAX_STACK_DEPTH) PRVM_ERROR ("stack overflow"); @@ -310,10 +562,10 @@ int PRVM_EnterFunction (mfunction_t *f) // save off any locals that the new function steps on c = f->locals; if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE) - PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s\n", PRVM_NAME); + PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME); for (i=0 ; i < c ; i++) - prog->localstack[prog->localstack_used+i] = ((int *)prog->globals)[f->parm_start + i]; + prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i]; prog->localstack_used += c; // copy parameters @@ -322,11 +574,12 @@ int PRVM_EnterFunction (mfunction_t *f) { for (j=0 ; jparm_size[i] ; j++) { - ((int *)prog->globals)[o] = ((int *)prog->globals)[OFS_PARM0+i*3+j]; + ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j]; o++; } } + ++f->recursion; prog->xfunction = f; return f->first_statement - 1; // offset the s++ } @@ -339,24 +592,44 @@ PRVM_LeaveFunction int PRVM_LeaveFunction (void) { int i, c; + mfunction_t *f; if (prog->depth <= 0) PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME); if (!prog->xfunction) - PRVM_ERROR ("PR_LeaveFunction: NULL function in %s\n", PRVM_NAME); + PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME); // restore locals from the stack c = prog->xfunction->locals; prog->localstack_used -= c; if (prog->localstack_used < 0) - PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s\n", PRVM_NAME); + PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME); for (i=0 ; i < c ; i++) - ((int *)prog->globals)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; + ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; // up stack prog->depth--; + f = prog->xfunction; + --f->recursion; prog->xfunction = prog->stack[prog->depth].f; + prog->stack[prog->depth].profile_acc += f->profile; + prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile; + if(prog->depth > 0) + { + prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc; + prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc; + } + if(!f->recursion) + { + // if f is already on the call stack... + // we cannot add this profile data to it now + // or we would add it more than once + // so, let's only add to the function's profile if it is the outermost call + f->profile_total += prog->stack[prog->depth].profile_acc; + f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc; + } + return prog->stack[prog->depth].s; } @@ -369,36 +642,44 @@ void PRVM_Init_Exec(void) // nothing here yet } +#define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a]) +#define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b]) +#define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c]) +extern cvar_t prvm_traceqc; +extern cvar_t prvm_statementprofiling; +extern sizebuf_t vm_tempstringsbuf; +extern qboolean prvm_runawaycheck; + +#ifdef PROFILING /* ==================== -PRVM_ExecuteProgram +MVM_ExecuteProgram ==================== */ -// LordHavoc: optimized -#define OPA ((prvm_eval_t *)&prog->globals[(unsigned short) st->a]) -#define OPB ((prvm_eval_t *)&prog->globals[(unsigned short) st->b]) -#define OPC ((prvm_eval_t *)&prog->globals[(unsigned short) st->c]) -extern cvar_t prvm_boundscheck; -extern cvar_t prvm_traceqc; -extern int PRVM_ED_FindFieldOffset (const char *field); -extern ddef_t* PRVM_ED_FindGlobal(const char *name); -void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) +void MVM_ExecuteProgram (func_t fnum, const char *errormessage) { - dstatement_t *st; + dstatement_t *st, *startst; mfunction_t *f, *newf; prvm_edict_t *ed; prvm_eval_t *ptr; - int profile, startprofile, cachedpr_trace, exitdepth; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); - if (!fnum || fnum >= prog->progs->numfunctions) + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) { - if (prog->self && PRVM_G_INT(prog->self->ofs)) - PRVM_ED_Print (PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs))); - PRVM_ERROR ("PR_ExecuteProgram: %s", errormessage); + if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); + PRVM_ERROR ("MVM_ExecuteProgram: %s", errormessage); } f = &prog->functions[fnum]; + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + prog->trace = prvm_traceqc.integer; // we know we're done when pr_depth drops to this @@ -406,36 +687,174 @@ void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) // make a stack frame st = &prog->statements[PRVM_EnterFunction (f)]; - startprofile = profile = 0; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; chooseexecprogram: cachedpr_trace = prog->trace; - if (prvm_boundscheck.integer) + if (prvm_statementprofiling.integer || prog->trace) { -#define PRVMBOUNDSCHECK 1 - if (prog->trace) - { -#define PRVMTRACE 1 +#define PRVMSLOWINTERPRETER 1 #include "prvm_execprogram.h" - } - else - { -#undef PRVMTRACE +#undef PRVMSLOWINTERPRETER + } + else + { #include "prvm_execprogram.h" - } + } + +cleanup: + if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + f->totaltime += (Sys_DoubleTime() - calltime); + + SV_FlushBroadcastMessages(); +} + +/* +==================== +CLVM_ExecuteProgram +==================== +*/ +void CLVM_ExecuteProgram (func_t fnum, const char *errormessage) +{ + dstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); + + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) + { + if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); + PRVM_ERROR ("CLVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction (f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_statementprofiling.integer || prog->trace) + { +#define PRVMSLOWINTERPRETER 1 +#include "prvm_execprogram.h" +#undef PRVMSLOWINTERPRETER } else { -#undef PRVMBOUNDSCHECK - if (prog->trace) - { -#define PRVMTRACE 1 #include "prvm_execprogram.h" - } - else - { -#undef PRVMTRACE + } + +cleanup: + if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + f->totaltime += (Sys_DoubleTime() - calltime); + + SV_FlushBroadcastMessages(); +} +#endif + +/* +==================== +SVVM_ExecuteProgram +==================== +*/ +void SVVM_ExecuteProgram (func_t fnum, const char *errormessage) +{ + dstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + + calltime = Sys_DoubleTime(); + + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) + { + if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL); + PRVM_ERROR ("SVVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction (f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_statementprofiling.integer || prog->trace) + { +#define PRVMSLOWINTERPRETER 1 +#include "prvm_execprogram.h" +#undef PRVMSLOWINTERPRETER + } + else + { #include "prvm_execprogram.h" - } } + +cleanup: + if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + f->totaltime += (Sys_DoubleTime() - calltime); + + SV_FlushBroadcastMessages(); }