]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_exec.c
Revert "Revert "Build in subdirs"", as the issues seem to be ironed out now.
[xonotic/darkplaces.git] / prvm_exec.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "progsvm.h"
23
24 const char *prvm_opnames[] =
25 {
26 "^5DONE",
27
28 "MUL_F",
29 "MUL_V",
30 "MUL_FV",
31 "MUL_VF",
32
33 "DIV",
34
35 "ADD_F",
36 "ADD_V",
37
38 "SUB_F",
39 "SUB_V",
40
41 "^2EQ_F",
42 "^2EQ_V",
43 "^2EQ_S",
44 "^2EQ_E",
45 "^2EQ_FNC",
46
47 "^2NE_F",
48 "^2NE_V",
49 "^2NE_S",
50 "^2NE_E",
51 "^2NE_FNC",
52
53 "^2LE",
54 "^2GE",
55 "^2LT",
56 "^2GT",
57
58 "^6FIELD_F",
59 "^6FIELD_V",
60 "^6FIELD_S",
61 "^6FIELD_ENT",
62 "^6FIELD_FLD",
63 "^6FIELD_FNC",
64
65 "^1ADDRESS",
66
67 "STORE_F",
68 "STORE_V",
69 "STORE_S",
70 "STORE_ENT",
71 "STORE_FLD",
72 "STORE_FNC",
73
74 "^1STOREP_F",
75 "^1STOREP_V",
76 "^1STOREP_S",
77 "^1STOREP_ENT",
78 "^1STOREP_FLD",
79 "^1STOREP_FNC",
80
81 "^5RETURN",
82
83 "^2NOT_F",
84 "^2NOT_V",
85 "^2NOT_S",
86 "^2NOT_ENT",
87 "^2NOT_FNC",
88
89 "^5IF",
90 "^5IFNOT",
91
92 "^3CALL0",
93 "^3CALL1",
94 "^3CALL2",
95 "^3CALL3",
96 "^3CALL4",
97 "^3CALL5",
98 "^3CALL6",
99 "^3CALL7",
100 "^3CALL8",
101
102 "^1STATE",
103
104 "^5GOTO",
105
106 "^2AND",
107 "^2OR",
108
109 "BITAND",
110 "BITOR"
111 };
112
113
114
115 //=============================================================================
116
117 /*
118 =================
119 PRVM_PrintStatement
120 =================
121 */
122 extern cvar_t prvm_statementprofiling;
123 extern cvar_t prvm_timeprofiling;
124 static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s)
125 {
126         size_t i;
127         int opnum = (int)(s - prog->statements);
128         char valuebuf[MAX_INPUTLINE];
129
130         Con_Printf("s%i: ", opnum);
131         if( prog->statement_linenums )
132                 Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] );
133
134         if (prvm_statementprofiling.integer)
135                 Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]);
136
137         if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]))
138         {
139                 Con_Printf("%s ",  prvm_opnames[s->op]);
140                 i = strlen(prvm_opnames[s->op]);
141                 // don't count a preceding color tag when padding the name
142                 if (prvm_opnames[s->op][0] == STRING_COLOR_TAG)
143                         i -= 2;
144                 for ( ; i<10 ; i++)
145                         Con_Print(" ");
146         }
147         if (s->operand[0] >= 0) Con_Printf(  "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf)));
148         if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf)));
149         if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf)));
150         if (s->jumpabsolute >= 0) Con_Printf(", statement %i", s->jumpabsolute);
151         Con_Print("\n");
152 }
153
154 void PRVM_PrintFunctionStatements (prvm_prog_t *prog, const char *name)
155 {
156         int i, firststatement, endstatement;
157         mfunction_t *func;
158         func = PRVM_ED_FindFunction (prog, name);
159         if (!func)
160         {
161                 Con_Printf("%s progs: no function named %s\n", prog->name, name);
162                 return;
163         }
164         firststatement = func->first_statement;
165         if (firststatement < 0)
166         {
167                 Con_Printf("%s progs: function %s is builtin #%i\n", prog->name, name, -firststatement);
168                 return;
169         }
170
171         // find the end statement
172         endstatement = prog->numstatements;
173         for (i = 0;i < prog->numfunctions;i++)
174                 if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement)
175                         endstatement = prog->functions[i].first_statement;
176
177         // now print the range of statements
178         Con_Printf("%s progs: disassembly of function %s (statements %i-%i, locals %i-%i):\n", prog->name, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1);
179         prog->xfunction = func;
180         for (i = firststatement;i < endstatement;i++)
181         {
182                 PRVM_PrintStatement(prog, prog->statements + i);
183                 prog->statement_profile[i] = 0;
184         }
185 }
186
187 /*
188 ============
189 PRVM_PrintFunction_f
190
191 ============
192 */
193 void PRVM_PrintFunction_f (void)
194 {
195         prvm_prog_t *prog;
196         if (Cmd_Argc() != 3)
197         {
198                 Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
199                 return;
200         }
201
202         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
203                 return;
204
205         PRVM_PrintFunctionStatements(prog, Cmd_Argv(2));
206 }
207
208 /*
209 ============
210 PRVM_StackTrace
211 ============
212 */
213 void PRVM_StackTrace (prvm_prog_t *prog)
214 {
215         mfunction_t     *f;
216         int                     i;
217
218         prog->stack[prog->depth].s = prog->xstatement;
219         prog->stack[prog->depth].f = prog->xfunction;
220         for (i = prog->depth;i > 0;i--)
221         {
222                 f = prog->stack[i].f;
223
224                 if (!f)
225                         Con_Print("<NULL FUNCTION>\n");
226                 else
227                 {
228                         if (prog->statement_linenums)
229                                 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);
230                         else
231                                 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);
232                 }
233         }
234 }
235
236 void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize)
237 {
238         mfunction_t     *f;
239         int                     i;
240         char vabuf[1024];
241
242         if(prog)
243         {
244                 dpsnprintf(buf, bufsize, "(%s) ", prog->name);
245         }
246         else
247         {
248                 strlcpy(buf, "<NO PROG>", bufsize);
249                 return;
250         }
251
252         prog->stack[prog->depth].s = prog->xstatement;
253         prog->stack[prog->depth].f = prog->xfunction;
254         for (i = prog->depth;i > 0;i--)
255         {
256                 f = prog->stack[i].f;
257
258                 if(strlcat(buf,
259                         f
260                                 ? va(vabuf, sizeof(vabuf), "%s:%s(%i) ", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement)
261                                 : "<NULL> ",
262                         bufsize
263                 ) >= bufsize)
264                         break;
265         }
266 }
267
268
269 static void PRVM_CallProfile (prvm_prog_t *prog)
270 {
271         mfunction_t *f, *best;
272         int i;
273         double max;
274         double sum;
275         double newprofiletime;
276
277         Con_Printf( "%s Call Profile:\n", prog->name );
278
279         sum = 0;
280         do
281         {
282                 max = 0;
283                 best = NULL;
284                 for (i=0 ; i<prog->numfunctions ; i++)
285                 {
286                         f = &prog->functions[i];
287                         if (max < f->totaltime)
288                         {
289                                 max = f->totaltime;
290                                 best = f;
291                         }
292                 }
293                 if (best)
294                 {
295                         sum += best->totaltime;
296                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name));
297                         best->totaltime = 0;
298                 }
299         } while (best);
300
301         newprofiletime = Sys_DirtyTime();
302         Con_Printf("Total time since last profile reset: %9.4f\n", newprofiletime - prog->profiletime);
303         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
304
305         prog->profiletime = newprofiletime;
306 }
307
308 void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby)
309 {
310         mfunction_t *f, *best;
311         int i, num;
312         double max;
313
314         if(!prvm_timeprofiling.integer)
315                 mintime *= 10000000; // count each statement as about 0.1µs
316
317         if(prvm_timeprofiling.integer)
318                 Con_Printf( "%s Profile:\n[CallCount]      [Time] [BuiltinTm] [Statement] [BuiltinCt] [TimeTotal] [StmtTotal] [BltnTotal] [self]\n", prog->name );
319                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
320         else
321                 Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name );
322                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
323
324         num = 0;
325         do
326         {
327                 max = 0;
328                 best = NULL;
329                 for (i=0 ; i<prog->numfunctions ; i++)
330                 {
331                         f = &prog->functions[i];
332                         if(prvm_timeprofiling.integer)
333                         {
334                                 if(sortby)
335                                 {
336                                         if(f->first_statement < 0)
337                                         {
338                                                 if (max < f->tprofile)
339                                                 {
340                                                         max = f->tprofile;
341                                                         best = f;
342                                                 }
343                                         }
344                                         else
345                                         {
346                                                 if (max < f->tprofile_total)
347                                                 {
348                                                         max = f->tprofile_total;
349                                                         best = f;
350                                                 }
351                                         }
352                                 }
353                                 else
354                                 {
355                                         if (max < f->tprofile + f->tbprofile)
356                                         {
357                                                 max = f->tprofile + f->tbprofile;
358                                                 best = f;
359                                         }
360                                 }
361                         }
362                         else
363                         {
364                                 if(sortby)
365                                 {
366                                         if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
367                                         {
368                                                 max = f->profile_total + f->builtinsprofile_total + f->callcount;
369                                                 best = f;
370                                         }
371                                 }
372                                 else
373                                 {
374                                         if (max < f->profile + f->builtinsprofile + f->callcount)
375                                         {
376                                                 max = f->profile + f->builtinsprofile + f->callcount;
377                                                 best = f;
378                                         }
379                                 }
380                         }
381                 }
382                 if (best)
383                 {
384                         if (num < maxfunctions && max > mintime)
385                         {
386                                 if(prvm_timeprofiling.integer)
387                                 {
388                                         if (best->first_statement < 0)
389                                                 Con_Printf("%11.0f %11.6f ------------- builtin ------------- %11.6f ----------- builtin ----------- %s\n", best->callcount, best->tprofile, best->tprofile, PRVM_GetString(prog, best->s_name));
390                                         //                 %11.6f 12345678901 12345678901 12345678901 %11.6f 12345678901 12345678901 123.45%
391                                         else
392                                                 Con_Printf("%11.0f %11.6f %11.6f %11.0f %11.0f %11.6f %11.0f %11.0f %6.2f%% %s\n", best->callcount, best->tprofile, best->tbprofile, best->profile, best->builtinsprofile, best->tprofile_total, best->profile_total, best->builtinsprofile_total, (best->tprofile_total > 0) ? ((best->tprofile) * 100.0 / (best->tprofile_total)) : -99.99, PRVM_GetString(prog, best->s_name));
393                                 }
394                                 else
395                                 {
396                                         if (best->first_statement < 0)
397                                                 Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(prog, best->s_name));
398                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
399                                         else
400                                                 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(prog, best->s_name));
401                                 }
402                         }
403                         num++;
404                         best->profile = 0;
405                         best->tprofile = 0;
406                         best->tbprofile = 0;
407                         best->builtinsprofile = 0;
408                         best->profile_total = 0;
409                         best->tprofile_total = 0;
410                         best->builtinsprofile_total = 0;
411                         best->callcount = 0;
412                 }
413         } while (best);
414 }
415
416 /*
417 ============
418 PRVM_CallProfile_f
419
420 ============
421 */
422 void PRVM_CallProfile_f (void)
423 {
424         prvm_prog_t *prog;
425         if (Cmd_Argc() != 2)
426         {
427                 Con_Print("prvm_callprofile <program name>\n");
428                 return;
429         }
430
431         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
432                 return;
433
434         PRVM_CallProfile(prog);
435 }
436
437 /*
438 ============
439 PRVM_Profile_f
440
441 ============
442 */
443 void PRVM_Profile_f (void)
444 {
445         prvm_prog_t *prog;
446         int howmany;
447
448         howmany = 1<<30;
449         if (Cmd_Argc() == 3)
450                 howmany = atoi(Cmd_Argv(2));
451         else if (Cmd_Argc() != 2)
452         {
453                 Con_Print("prvm_profile <program name>\n");
454                 return;
455         }
456
457         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
458                 return;
459
460         PRVM_Profile(prog, howmany, 0, 0);
461 }
462
463 void PRVM_ChildProfile_f (void)
464 {
465         prvm_prog_t *prog;
466         int howmany;
467
468         howmany = 1<<30;
469         if (Cmd_Argc() == 3)
470                 howmany = atoi(Cmd_Argv(2));
471         else if (Cmd_Argc() != 2)
472         {
473                 Con_Print("prvm_childprofile <program name>\n");
474                 return;
475         }
476
477         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
478                 return;
479
480         PRVM_Profile(prog, howmany, 0, 1);
481 }
482
483 void PRVM_PrintState(prvm_prog_t *prog, int stack_index)
484 {
485         int i;
486         mfunction_t *func = prog->xfunction;
487         int st = prog->xstatement;
488         if (stack_index > 0 && stack_index <= prog->depth)
489         {
490                 func = prog->stack[prog->depth - stack_index].f;
491                 st = prog->stack[prog->depth - stack_index].s;
492         }
493         if (prog->statestring)
494         {
495                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
496         }
497         if (func)
498         {
499                 for (i = -7; i <= 0;i++)
500                         if (st + i >= func->first_statement)
501                                 PRVM_PrintStatement(prog, prog->statements + st + i);
502         }
503         PRVM_StackTrace(prog);
504 }
505
506 extern cvar_t prvm_errordump;
507 void PRVM_Crash(prvm_prog_t *prog)
508 {
509         char vabuf[1024];
510         if (prog == NULL)
511                 return;
512         if (!prog->loaded)
513                 return;
514
515         PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
516
517         if( prog->depth > 0 )
518         {
519                 Con_Printf("QuakeC crash report for %s:\n", prog->name);
520                 PRVM_PrintState(prog, 0);
521         }
522
523         if(prvm_errordump.integer)
524         {
525                 // make a savegame
526                 Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
527         }
528
529         // dump the stack so host_error can shutdown functions
530         prog->depth = 0;
531         prog->localstack_used = 0;
532
533         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
534         prog->tempstringsbuf.cursize = 0;
535
536         // reset the prog pointer
537         prog = NULL;
538 }
539
540 /*
541 ============================================================================
542 PRVM_ExecuteProgram
543
544 The interpretation main loop
545 ============================================================================
546 */
547
548 /*
549 ====================
550 PRVM_EnterFunction
551
552 Returns the new program statement counter
553 ====================
554 */
555 static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
556 {
557         int             i, j, c, o;
558
559         if (!f)
560                 prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name);
561
562         prog->stack[prog->depth].s = prog->xstatement;
563         prog->stack[prog->depth].f = prog->xfunction;
564         prog->stack[prog->depth].profile_acc = -f->profile;
565         prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile;
566         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
567         prog->depth++;
568         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
569                 prog->error_cmd("stack overflow");
570
571 // save off any locals that the new function steps on
572         c = f->locals;
573         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
574                 prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
575
576         for (i=0 ; i < c ; i++)
577                 prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i];
578         prog->localstack_used += c;
579
580 // copy parameters
581         o = f->parm_start;
582         for (i=0 ; i<f->numparms ; i++)
583         {
584                 for (j=0 ; j<f->parm_size[i] ; j++)
585                 {
586                         prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j];
587                         o++;
588                 }
589         }
590
591         ++f->recursion;
592         prog->xfunction = f;
593         return f->first_statement - 1;  // offset the s++
594 }
595
596 /*
597 ====================
598 PRVM_LeaveFunction
599 ====================
600 */
601 static int PRVM_LeaveFunction (prvm_prog_t *prog)
602 {
603         int             i, c;
604         mfunction_t *f;
605
606         if (prog->depth <= 0)
607                 prog->error_cmd("prog stack underflow in %s", prog->name);
608
609         if (!prog->xfunction)
610                 prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name);
611 // restore locals from the stack
612         c = prog->xfunction->locals;
613         prog->localstack_used -= c;
614         if (prog->localstack_used < 0)
615                 prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
616
617         for (i=0 ; i < c ; i++)
618                 prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
619
620 // up stack
621         prog->depth--;
622         f = prog->xfunction;
623         --f->recursion;
624         prog->xfunction = prog->stack[prog->depth].f;
625         prog->stack[prog->depth].profile_acc += f->profile;
626         prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile;
627         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
628         if(prog->depth > 0)
629         {
630                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
631                 prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc;
632                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
633         }
634         if(!f->recursion)
635         {
636                 // if f is already on the call stack...
637                 // we cannot add this profile data to it now
638                 // or we would add it more than once
639                 // so, let's only add to the function's profile if it is the outermost call
640                 f->profile_total += prog->stack[prog->depth].profile_acc;
641                 f->tprofile_total += prog->stack[prog->depth].tprofile_acc;
642                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
643         }
644         
645         return prog->stack[prog->depth].s;
646 }
647
648 void PRVM_Init_Exec(prvm_prog_t *prog)
649 {
650         // dump the stack
651         prog->depth = 0;
652         prog->localstack_used = 0;
653         // reset the string table
654         // nothing here yet
655 }
656
657 #define OPA ((prvm_eval_t *)&prog->globals.fp[st->operand[0]])
658 #define OPB ((prvm_eval_t *)&prog->globals.fp[st->operand[1]])
659 #define OPC ((prvm_eval_t *)&prog->globals.fp[st->operand[2]])
660 extern cvar_t prvm_traceqc;
661 extern cvar_t prvm_statementprofiling;
662 extern qboolean prvm_runawaycheck;
663
664 #ifdef PROFILING
665 #ifdef CONFIG_MENU
666 /*
667 ====================
668 MVM_ExecuteProgram
669 ====================
670 */
671 void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
672 {
673         mstatement_t    *st, *startst;
674         mfunction_t     *f, *newf;
675         prvm_edict_t    *ed;
676         prvm_eval_t     *ptr;
677         int             jumpcount, cachedpr_trace, exitdepth;
678         int             restorevm_tempstringsbuf_cursize;
679         double  calltime;
680         double tm, starttm;
681         prvm_vec_t tempfloat;
682         // these may become out of date when a builtin is called, and are updated accordingly
683         prvm_vec_t *cached_edictsfields = prog->edictsfields;
684         unsigned int cached_entityfields = prog->entityfields;
685         unsigned int cached_entityfields_3 = prog->entityfields - 3;
686         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
687         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
688         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
689         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
690         unsigned int cached_max_edicts = prog->max_edicts;
691         // these do not change
692         mstatement_t *cached_statements = prog->statements;
693         qboolean cached_allowworldwrites = prog->allowworldwrites;
694         unsigned int cached_flag = prog->flag;
695
696         calltime = Sys_DirtyTime();
697
698         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
699         {
700                 if (PRVM_allglobaledict(self))
701                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
702                 prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
703         }
704
705         f = &prog->functions[fnum];
706
707         // after executing this function, delete all tempstrings it created
708         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
709
710         prog->trace = prvm_traceqc.integer;
711
712         // we know we're done when pr_depth drops to this
713         exitdepth = prog->depth;
714
715 // make a stack frame
716         st = &prog->statements[PRVM_EnterFunction(prog, f)];
717         // save the starting statement pointer for profiling
718         // (when the function exits or jumps, the (st - startst) integer value is
719         // added to the function's profile counter)
720         startst = st;
721         starttm = calltime;
722         // instead of counting instructions, we count jumps
723         jumpcount = 0;
724         // add one to the callcount of this function because otherwise engine-called functions aren't counted
725         prog->xfunction->callcount++;
726
727 chooseexecprogram:
728         cachedpr_trace = prog->trace;
729         if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0)
730         {
731 #define PRVMSLOWINTERPRETER 1
732                 if (prvm_timeprofiling.integer)
733                 {
734 #define PRVMTIMEPROFILING 1
735 #include "prvm_execprogram.h"
736 #undef PRVMTIMEPROFILING
737                 }
738                 else
739                 {
740 #include "prvm_execprogram.h"
741                 }
742 #undef PRVMSLOWINTERPRETER
743         }
744         else
745         {
746                 if (prvm_timeprofiling.integer)
747                 {
748 #define PRVMTIMEPROFILING 1
749 #include "prvm_execprogram.h"
750 #undef PRVMTIMEPROFILING
751                 }
752                 else
753                 {
754 #include "prvm_execprogram.h"
755                 }
756         }
757
758 cleanup:
759         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
760                 Con_DPrintf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
761         // delete tempstrings created by this function
762         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
763
764         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
765         f->totaltime += tm;
766
767         if (prog == SVVM_prog)
768                 SV_FlushBroadcastMessages();
769 }
770 #endif
771
772 /*
773 ====================
774 CLVM_ExecuteProgram
775 ====================
776 */
777 void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
778 {
779         mstatement_t    *st, *startst;
780         mfunction_t     *f, *newf;
781         prvm_edict_t    *ed;
782         prvm_eval_t     *ptr;
783         int             jumpcount, cachedpr_trace, exitdepth;
784         int             restorevm_tempstringsbuf_cursize;
785         double  calltime;
786         double tm, starttm;
787         prvm_vec_t tempfloat;
788         // these may become out of date when a builtin is called, and are updated accordingly
789         prvm_vec_t *cached_edictsfields = prog->edictsfields;
790         unsigned int cached_entityfields = prog->entityfields;
791         unsigned int cached_entityfields_3 = prog->entityfields - 3;
792         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
793         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
794         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
795         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
796         unsigned int cached_max_edicts = prog->max_edicts;
797         // these do not change
798         mstatement_t *cached_statements = prog->statements;
799         qboolean cached_allowworldwrites = prog->allowworldwrites;
800         unsigned int cached_flag = prog->flag;
801
802         calltime = Sys_DirtyTime();
803
804         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
805         {
806                 if (PRVM_allglobaledict(self))
807                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
808                 prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
809         }
810
811         f = &prog->functions[fnum];
812
813         // after executing this function, delete all tempstrings it created
814         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
815
816         prog->trace = prvm_traceqc.integer;
817
818         // we know we're done when pr_depth drops to this
819         exitdepth = prog->depth;
820
821 // make a stack frame
822         st = &prog->statements[PRVM_EnterFunction(prog, f)];
823         // save the starting statement pointer for profiling
824         // (when the function exits or jumps, the (st - startst) integer value is
825         // added to the function's profile counter)
826         startst = st;
827         starttm = calltime;
828         // instead of counting instructions, we count jumps
829         jumpcount = 0;
830         // add one to the callcount of this function because otherwise engine-called functions aren't counted
831         prog->xfunction->callcount++;
832
833 chooseexecprogram:
834         cachedpr_trace = prog->trace;
835         if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0)
836         {
837 #define PRVMSLOWINTERPRETER 1
838                 if (prvm_timeprofiling.integer)
839                 {
840 #define PRVMTIMEPROFILING 1
841 #include "prvm_execprogram.h"
842 #undef PRVMTIMEPROFILING
843                 }
844                 else
845                 {
846 #include "prvm_execprogram.h"
847                 }
848 #undef PRVMSLOWINTERPRETER
849         }
850         else
851         {
852                 if (prvm_timeprofiling.integer)
853                 {
854 #define PRVMTIMEPROFILING 1
855 #include "prvm_execprogram.h"
856 #undef PRVMTIMEPROFILING
857                 }
858                 else
859                 {
860 #include "prvm_execprogram.h"
861                 }
862         }
863
864 cleanup:
865         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
866                 Con_DPrintf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
867         // delete tempstrings created by this function
868         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
869
870         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
871         f->totaltime += tm;
872
873         if (prog == SVVM_prog)
874                 SV_FlushBroadcastMessages();
875 }
876 #endif
877
878 /*
879 ====================
880 SVVM_ExecuteProgram
881 ====================
882 */
883 #ifdef PROFILING
884 void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
885 #else
886 void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
887 #endif
888 {
889         mstatement_t    *st, *startst;
890         mfunction_t     *f, *newf;
891         prvm_edict_t    *ed;
892         prvm_eval_t     *ptr;
893         int             jumpcount, cachedpr_trace, exitdepth;
894         int             restorevm_tempstringsbuf_cursize;
895         double  calltime;
896         double tm, starttm;
897         prvm_vec_t tempfloat;
898         // these may become out of date when a builtin is called, and are updated accordingly
899         prvm_vec_t *cached_edictsfields = prog->edictsfields;
900         unsigned int cached_entityfields = prog->entityfields;
901         unsigned int cached_entityfields_3 = prog->entityfields - 3;
902         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
903         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
904         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
905         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
906         unsigned int cached_max_edicts = prog->max_edicts;
907         // these do not change
908         mstatement_t *cached_statements = prog->statements;
909         qboolean cached_allowworldwrites = prog->allowworldwrites;
910         unsigned int cached_flag = prog->flag;
911
912         calltime = Sys_DirtyTime();
913
914         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
915         {
916                 if (PRVM_allglobaledict(self))
917                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
918                 prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
919         }
920
921         f = &prog->functions[fnum];
922
923         // after executing this function, delete all tempstrings it created
924         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
925
926         prog->trace = prvm_traceqc.integer;
927
928         // we know we're done when pr_depth drops to this
929         exitdepth = prog->depth;
930
931 // make a stack frame
932         st = &prog->statements[PRVM_EnterFunction(prog, f)];
933         // save the starting statement pointer for profiling
934         // (when the function exits or jumps, the (st - startst) integer value is
935         // added to the function's profile counter)
936         startst = st;
937         starttm = calltime;
938         // instead of counting instructions, we count jumps
939         jumpcount = 0;
940         // add one to the callcount of this function because otherwise engine-called functions aren't counted
941         prog->xfunction->callcount++;
942
943 chooseexecprogram:
944         cachedpr_trace = prog->trace;
945         if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0)
946         {
947 #define PRVMSLOWINTERPRETER 1
948                 if (prvm_timeprofiling.integer)
949                 {
950 #define PRVMTIMEPROFILING 1
951 #include "prvm_execprogram.h"
952 #undef PRVMTIMEPROFILING
953                 }
954                 else
955                 {
956 #include "prvm_execprogram.h"
957                 }
958 #undef PRVMSLOWINTERPRETER
959         }
960         else
961         {
962                 if (prvm_timeprofiling.integer)
963                 {
964 #define PRVMTIMEPROFILING 1
965 #include "prvm_execprogram.h"
966 #undef PRVMTIMEPROFILING
967                 }
968                 else
969                 {
970 #include "prvm_execprogram.h"
971                 }
972         }
973
974 cleanup:
975         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
976                 Con_DPrintf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
977         // delete tempstrings created by this function
978         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
979
980         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
981         f->totaltime += tm;
982
983         if (prog == SVVM_prog)
984                 SV_FlushBroadcastMessages();
985 }