#include "quakedef.h"
#include "progsvm.h"
-const char *prvm_opnames[] =
+static const char *prvm_opnames[] =
{
"^5DONE",
"^2OR",
"BITAND",
-"BITOR"
+"BITOR",
+
+
+
+
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+
+"STORE_I",
+
+NULL,
+NULL,
+
+"ADD_I",
+"ADD_FI",
+"ADD_IF",
+
+"SUB_I",
+"SUB_FI",
+"SUB_IF",
+"CONV_IF",
+"CONV_FI",
+
+NULL,
+NULL,
+
+"LOAD_I",
+"STOREP_I",
+
+NULL,
+NULL,
+
+"BITAND_I",
+"BITOR_I",
+
+"MUL_I",
+"DIV_I",
+"EQ_I",
+"NE_I",
+
+NULL,
+NULL,
+
+"NOT_I",
+
+"DIV_VF",
+
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+
+"STORE_P",
+
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+NULL,
+
+"LE_I",
+"GE_I",
+"LT_I",
+"GT_I",
+
+"LE_IF",
+"GE_IF",
+"LT_IF",
+"GT_IF",
+
+"LE_FI",
+"GE_FI",
+"LT_FI",
+"GT_FI",
+
+"EQ_IF",
+"EQ_FI",
+
+NULL,
+NULL,
+NULL,
+NULL,
+
+"MUL_IF",
+"MUL_FI",
+"MUL_VI",
+
+NULL,
+
+"DIV_IF",
+"DIV_FI",
+"BITAND_IF",
+"BITOR_IF",
+"BITAND_FI",
+"BITOR_FI",
+"AND_I",
+"OR_I",
+"AND_IF",
+"OR_IF",
+"AND_FI",
+"OR_FI",
+"NE_IF",
+"NE_FI",
+
+"GSTOREP_I",
+"GSTOREP_F",
+"GSTOREP_ENT",
+"GSTOREP_FLD",
+"GSTOREP_S",
+"GSTOREP_FNC",
+"GSTOREP_V",
+"GADDRESS",
+"GLOAD_I",
+"GLOAD_F",
+"GLOAD_FLD",
+"GLOAD_ENT",
+"GLOAD_S",
+"GLOAD_FNC",
+"BOUNDCHECK",
+NULL,
+NULL,
+NULL,
+NULL,
+"GLOAD_V",
};
PRVM_PrintStatement
=================
*/
+extern cvar_t prvm_coverage;
extern cvar_t prvm_statementprofiling;
extern cvar_t prvm_timeprofiling;
static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s)
size_t i;
int opnum = (int)(s - prog->statements);
char valuebuf[MAX_INPUTLINE];
+ const char *opname;
Con_Printf("s%i: ", opnum);
if( prog->statement_linenums )
- Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] );
+ {
+ if ( prog->statement_columnnums )
+ Con_Printf( "%s:%i:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ], prog->statement_columnnums[ opnum ] );
+ else
+ Con_Printf( "%s:%i: ", PRVM_GetString( prog, 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]);
- 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_Print(" ");
- }
+ if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]) && prvm_opnames[s->op])
+ opname = prvm_opnames[s->op];
+ else
+ opname = valuebuf, dpsnprintf(valuebuf, sizeof(valuebuf), "OPCODE_%u", (unsigned)s->op);
+ Con_Printf("%s ", opname);
+ i = strlen(opname);
+ // don't count a preceding color tag when padding the name
+ if (opname[0] == STRING_COLOR_TAG)
+ i -= 2;
+ for ( ; i<10 ; i++)
+ Con_Print(" ");
+
if (s->operand[0] >= 0) Con_Printf( "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf)));
if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf)));
if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf)));
for (i = firststatement;i < endstatement;i++)
{
PRVM_PrintStatement(prog, prog->statements + i);
- prog->statement_profile[i] = 0;
+ if (!(prvm_coverage.integer & 4))
+ prog->statement_profile[i] = 0;
}
+ if (prvm_coverage.integer & 4)
+ Con_Printf("Collecting statement coverage, not flushing statement profile.\n");
}
/*
============
*/
-void PRVM_PrintFunction_f (void)
+void PRVM_PrintFunction_f(cmd_state_t *cmd)
{
prvm_prog_t *prog;
- if (Cmd_Argc() != 3)
+ if (Cmd_Argc(cmd) != 3)
{
Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
return;
}
- if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
+ if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
return;
- PRVM_PrintFunctionStatements(prog, Cmd_Argv(2));
+ PRVM_PrintFunctionStatements(prog, Cmd_Argv(cmd, 2));
}
/*
if (!f)
Con_Print("<NULL FUNCTION>\n");
else
- Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement);
+ {
+ if (prog->statement_linenums)
+ {
+ if (prog->statement_columnnums)
+ Con_Printf("%12s:%i:%i : %s : statement %i\n", PRVM_GetString(prog, f->s_file), prog->statement_linenums[prog->stack[i].s], prog->statement_columnnums[prog->stack[i].s], PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement);
+ else
+ Con_Printf("%12s:%i : %s : statement %i\n", PRVM_GetString(prog, f->s_file), prog->statement_linenums[prog->stack[i].s], PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement);
+ }
+ else
+ Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement);
+ }
}
}
============
*/
-void PRVM_CallProfile_f (void)
+void PRVM_CallProfile_f(cmd_state_t *cmd)
{
prvm_prog_t *prog;
- if (Cmd_Argc() != 2)
+ if (Cmd_Argc(cmd) != 2)
{
Con_Print("prvm_callprofile <program name>\n");
return;
}
- if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
+ if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
return;
PRVM_CallProfile(prog);
============
*/
-void PRVM_Profile_f (void)
+void PRVM_Profile_f(cmd_state_t *cmd)
{
prvm_prog_t *prog;
int howmany;
+ if (prvm_coverage.integer & 1)
+ {
+ Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
+ return;
+ }
+
howmany = 1<<30;
- if (Cmd_Argc() == 3)
- howmany = atoi(Cmd_Argv(2));
- else if (Cmd_Argc() != 2)
+ if (Cmd_Argc(cmd) == 3)
+ howmany = atoi(Cmd_Argv(cmd, 2));
+ else if (Cmd_Argc(cmd) != 2)
{
Con_Print("prvm_profile <program name>\n");
return;
}
- if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
+ if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
return;
PRVM_Profile(prog, howmany, 0, 0);
}
-void PRVM_ChildProfile_f (void)
+void PRVM_ChildProfile_f(cmd_state_t *cmd)
{
prvm_prog_t *prog;
int howmany;
+ if (prvm_coverage.integer & 1)
+ {
+ Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
+ return;
+ }
+
howmany = 1<<30;
- if (Cmd_Argc() == 3)
- howmany = atoi(Cmd_Argv(2));
- else if (Cmd_Argc() != 2)
+ if (Cmd_Argc(cmd) == 3)
+ howmany = atoi(Cmd_Argv(cmd, 2));
+ else if (Cmd_Argc(cmd) != 2)
{
Con_Print("prvm_childprofile <program name>\n");
return;
}
- if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
+ if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
return;
PRVM_Profile(prog, howmany, 0, 1);
}
-void PRVM_PrintState(prvm_prog_t *prog)
+void PRVM_PrintState(prvm_prog_t *prog, int stack_index)
{
int i;
+ mfunction_t *func = prog->xfunction;
+ int st = prog->xstatement;
+ if (stack_index > 0 && stack_index <= prog->depth)
+ {
+ func = prog->stack[prog->depth - stack_index].f;
+ st = prog->stack[prog->depth - stack_index].s;
+ }
if (prog->statestring)
{
Con_Printf("Caller-provided information: %s\n", prog->statestring);
}
- if (prog->xfunction)
+ if (func)
{
for (i = -7; i <= 0;i++)
- if (prog->xstatement + i >= prog->xfunction->first_statement)
- PRVM_PrintStatement(prog, prog->statements + prog->xstatement + i);
+ if (st + i >= func->first_statement)
+ PRVM_PrintStatement(prog, prog->statements + st + i);
}
- else
- Con_Print("null function executing??\n");
PRVM_StackTrace(prog);
}
void PRVM_Crash(prvm_prog_t *prog)
{
char vabuf[1024];
+
+ cl.csqc_loaded = false;
+
if (prog == NULL)
return;
if (!prog->loaded)
if( prog->depth > 0 )
{
Con_Printf("QuakeC crash report for %s:\n", prog->name);
- PRVM_PrintState(prog);
+ PRVM_PrintState(prog, 0);
}
if(prvm_errordump.integer)
{
// make a savegame
- Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
+ SV_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
}
// dump the stack so host_error can shutdown functions
prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
for (i=0 ; i < c ; i++)
- prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
+ prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i];
prog->localstack_used += c;
// copy parameters
{
for (j=0 ; j<f->parm_size[i] ; j++)
{
- ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j];
+ prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j];
o++;
}
}
prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
for (i=0 ; i < c ; i++)
- ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
+ prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
// up stack
prog->depth--;
// nothing here yet
}
-#define OPA ((prvm_eval_t *)&prog->globals.generic[st->operand[0]])
-#define OPB ((prvm_eval_t *)&prog->globals.generic[st->operand[1]])
-#define OPC ((prvm_eval_t *)&prog->globals.generic[st->operand[2]])
+/*
+==================
+Coverage
+==================
+*/
+// Note: in these two calls, prog->xfunction is assumed to be sane.
+static const char *PRVM_WhereAmI(char *buf, size_t bufsize, prvm_prog_t *prog, mfunction_t *func, int statement)
+{
+ if (prog->statement_linenums)
+ {
+ if (prog->statement_columnnums)
+ return va(buf, bufsize, "%s:%i:%i(%s, %i)", PRVM_GetString(prog, func->s_file), prog->statement_linenums[statement], prog->statement_columnnums[statement], PRVM_GetString(prog, func->s_name), statement - func->first_statement);
+ else
+ return va(buf, bufsize, "%s:%i(%s, %i)", PRVM_GetString(prog, func->s_file), prog->statement_linenums[statement], PRVM_GetString(prog, func->s_name), statement - func->first_statement);
+ }
+ else
+ return va(buf, bufsize, "%s(%s, %i)", PRVM_GetString(prog, func->s_file), PRVM_GetString(prog, func->s_name), statement - func->first_statement);
+}
+static void PRVM_FunctionCoverageEvent(prvm_prog_t *prog, mfunction_t *func)
+{
+ ++prog->functions_covered;
+ Con_Printf("prvm_coverage: %s just called %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_GetString(prog, func->s_name), prog->functions_covered * 100.0 / prog->numfunctions);
+}
+void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
+{
+ char vabuf[128];
+ ++prog->explicit_covered;
+ Con_Printf("prvm_coverage: %s just executed a coverage() statement at %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_WhereAmI(vabuf, sizeof(vabuf), prog, func, statement), prog->explicit_covered * 100.0 / prog->numexplicitcoveragestatements);
+}
+static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
+{
+ char vabuf[128];
+ ++prog->statements_covered;
+ Con_Printf("prvm_coverage: %s just executed a statement at %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_WhereAmI(vabuf, sizeof(vabuf), prog, func, statement), prog->statements_covered * 100.0 / prog->numstatements);
+}
+
+#if defined (__GNUC__) || (__clang__) || (__TINYC__)
+# ifndef CONFIG_PEDANTIC
+# define HAVE_COMPUTED_GOTOS 1
+# endif
+#endif
+
+#define OPA ((prvm_eval_t *)&globals[st->operand[0]])
+#define OPB ((prvm_eval_t *)&globals[st->operand[1]])
+#define OPC ((prvm_eval_t *)&globals[st->operand[2]])
extern cvar_t prvm_traceqc;
extern cvar_t prvm_statementprofiling;
-extern qboolean prvm_runawaycheck;
+extern qbool prvm_runawaycheck;
#ifdef PROFILING
+#ifdef CONFIG_MENU
/*
====================
MVM_ExecuteProgram
void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
{
mstatement_t *st, *startst;
- mfunction_t *f, *newf;
+ mfunction_t *func, *enterfunc;
prvm_edict_t *ed;
prvm_eval_t *ptr;
int jumpcount, cachedpr_trace, exitdepth;
int restorevm_tempstringsbuf_cursize;
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;
calltime = Sys_DirtyTime();
prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
}
- f = &prog->functions[fnum];
+ func = &prog->functions[fnum];
// after executing this function, delete all tempstrings it created
restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
exitdepth = prog->depth;
// make a stack frame
- st = &prog->statements[PRVM_EnterFunction(prog, f)];
+ st = &prog->statements[PRVM_EnterFunction(prog, func)];
// 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)
// 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++;
+ if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
+ PRVM_FunctionCoverageEvent(prog, prog->xfunction);
chooseexecprogram:
cachedpr_trace = prog->trace;
- if (prvm_statementprofiling.integer || prog->trace)
+ if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
{
#define PRVMSLOWINTERPRETER 1
if (prvm_timeprofiling.integer)
prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
- f->totaltime += tm;
+ func->totaltime += tm;
if (prog == SVVM_prog)
SV_FlushBroadcastMessages();
}
+#endif
/*
====================
void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
{
mstatement_t *st, *startst;
- mfunction_t *f, *newf;
+ mfunction_t *func, *enterfunc;
prvm_edict_t *ed;
prvm_eval_t *ptr;
int jumpcount, cachedpr_trace, exitdepth;
int restorevm_tempstringsbuf_cursize;
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;
calltime = Sys_DirtyTime();
prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
}
- f = &prog->functions[fnum];
+ func = &prog->functions[fnum];
// after executing this function, delete all tempstrings it created
restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
exitdepth = prog->depth;
// make a stack frame
- st = &prog->statements[PRVM_EnterFunction(prog, f)];
+ st = &prog->statements[PRVM_EnterFunction(prog, func)];
// 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)
// 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++;
+ if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
+ PRVM_FunctionCoverageEvent(prog, prog->xfunction);
chooseexecprogram:
cachedpr_trace = prog->trace;
- if (prvm_statementprofiling.integer || prog->trace)
+ if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
{
#define PRVMSLOWINTERPRETER 1
if (prvm_timeprofiling.integer)
prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
- f->totaltime += tm;
+ func->totaltime += tm;
if (prog == SVVM_prog)
SV_FlushBroadcastMessages();
#endif
{
mstatement_t *st, *startst;
- mfunction_t *f, *newf;
+ mfunction_t *func, *enterfunc;
prvm_edict_t *ed;
prvm_eval_t *ptr;
int jumpcount, cachedpr_trace, exitdepth;
int restorevm_tempstringsbuf_cursize;
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;
calltime = Sys_DirtyTime();
prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
}
- f = &prog->functions[fnum];
+ func = &prog->functions[fnum];
// after executing this function, delete all tempstrings it created
restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
exitdepth = prog->depth;
// make a stack frame
- st = &prog->statements[PRVM_EnterFunction(prog, f)];
+ st = &prog->statements[PRVM_EnterFunction(prog, func)];
// 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)
// 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++;
+ if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
+ PRVM_FunctionCoverageEvent(prog, prog->xfunction);
chooseexecprogram:
cachedpr_trace = prog->trace;
- if (prvm_statementprofiling.integer || prog->trace)
+ if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
{
#define PRVMSLOWINTERPRETER 1
if (prvm_timeprofiling.integer)
prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
- f->totaltime += tm;
+ func->totaltime += tm;
if (prog == SVVM_prog)
SV_FlushBroadcastMessages();