49142b727a32db211c9737a7fdab7c118e1c065c
[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                         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);
228         }
229 }
230
231 void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize)
232 {
233         mfunction_t     *f;
234         int                     i;
235         char vabuf[1024];
236
237         if(prog)
238         {
239                 dpsnprintf(buf, bufsize, "(%s) ", prog->name);
240         }
241         else
242         {
243                 strlcpy(buf, "<NO PROG>", bufsize);
244                 return;
245         }
246
247         prog->stack[prog->depth].s = prog->xstatement;
248         prog->stack[prog->depth].f = prog->xfunction;
249         for (i = prog->depth;i > 0;i--)
250         {
251                 f = prog->stack[i].f;
252
253                 if(strlcat(buf,
254                         f
255                                 ? 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)
256                                 : "<NULL> ",
257                         bufsize
258                 ) >= bufsize)
259                         break;
260         }
261 }
262
263
264 static void PRVM_CallProfile (prvm_prog_t *prog)
265 {
266         mfunction_t *f, *best;
267         int i;
268         double max;
269         double sum;
270         double newprofiletime;
271
272         Con_Printf( "%s Call Profile:\n", prog->name );
273
274         sum = 0;
275         do
276         {
277                 max = 0;
278                 best = NULL;
279                 for (i=0 ; i<prog->numfunctions ; i++)
280                 {
281                         f = &prog->functions[i];
282                         if (max < f->totaltime)
283                         {
284                                 max = f->totaltime;
285                                 best = f;
286                         }
287                 }
288                 if (best)
289                 {
290                         sum += best->totaltime;
291                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name));
292                         best->totaltime = 0;
293                 }
294         } while (best);
295
296         newprofiletime = Sys_DirtyTime();
297         Con_Printf("Total time since last profile reset: %9.4f\n", newprofiletime - prog->profiletime);
298         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
299
300         prog->profiletime = newprofiletime;
301 }
302
303 void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby)
304 {
305         mfunction_t *f, *best;
306         int i, num;
307         double max;
308
309         if(!prvm_timeprofiling.integer)
310                 mintime *= 10000000; // count each statement as about 0.1┬Ás
311
312         if(prvm_timeprofiling.integer)
313                 Con_Printf( "%s Profile:\n[CallCount]      [Time] [BuiltinTm] [Statement] [BuiltinCt] [TimeTotal] [StmtTotal] [BltnTotal] [self]\n", prog->name );
314                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
315         else
316                 Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name );
317                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
318
319         num = 0;
320         do
321         {
322                 max = 0;
323                 best = NULL;
324                 for (i=0 ; i<prog->numfunctions ; i++)
325                 {
326                         f = &prog->functions[i];
327                         if(prvm_timeprofiling.integer)
328                         {
329                                 if(sortby)
330                                 {
331                                         if(f->first_statement < 0)
332                                         {
333                                                 if (max < f->tprofile)
334                                                 {
335                                                         max = f->tprofile;
336                                                         best = f;
337                                                 }
338                                         }
339                                         else
340                                         {
341                                                 if (max < f->tprofile_total)
342                                                 {
343                                                         max = f->tprofile_total;
344                                                         best = f;
345                                                 }
346                                         }
347                                 }
348                                 else
349                                 {
350                                         if (max < f->tprofile + f->tbprofile)
351                                         {
352                                                 max = f->tprofile + f->tbprofile;
353                                                 best = f;
354                                         }
355                                 }
356                         }
357                         else
358                         {
359                                 if(sortby)
360                                 {
361                                         if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
362                                         {
363                                                 max = f->profile_total + f->builtinsprofile_total + f->callcount;
364                                                 best = f;
365                                         }
366                                 }
367                                 else
368                                 {
369                                         if (max < f->profile + f->builtinsprofile + f->callcount)
370                                         {
371                                                 max = f->profile + f->builtinsprofile + f->callcount;
372                                                 best = f;
373                                         }
374                                 }
375                         }
376                 }
377                 if (best)
378                 {
379                         if (num < maxfunctions && max > mintime)
380                         {
381                                 if(prvm_timeprofiling.integer)
382                                 {
383                                         if (best->first_statement < 0)
384                                                 Con_Printf("%11.0f %11.6f ------------- builtin ------------- %11.6f ----------- builtin ----------- %s\n", best->callcount, best->tprofile, best->tprofile, PRVM_GetString(prog, best->s_name));
385                                         //                 %11.6f 12345678901 12345678901 12345678901 %11.6f 12345678901 12345678901 123.45%
386                                         else
387                                                 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));
388                                 }
389                                 else
390                                 {
391                                         if (best->first_statement < 0)
392                                                 Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(prog, best->s_name));
393                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
394                                         else
395                                                 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));
396                                 }
397                         }
398                         num++;
399                         best->profile = 0;
400                         best->tprofile = 0;
401                         best->tbprofile = 0;
402                         best->builtinsprofile = 0;
403                         best->profile_total = 0;
404                         best->tprofile_total = 0;
405                         best->builtinsprofile_total = 0;
406                         best->callcount = 0;
407                 }
408         } while (best);
409 }
410
411 /*
412 ============
413 PRVM_CallProfile_f
414
415 ============
416 */
417 void PRVM_CallProfile_f (void)
418 {
419         prvm_prog_t *prog;
420         if (Cmd_Argc() != 2)
421         {
422                 Con_Print("prvm_callprofile <program name>\n");
423                 return;
424         }
425
426         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
427                 return;
428
429         PRVM_CallProfile(prog);
430 }
431
432 /*
433 ============
434 PRVM_Profile_f
435
436 ============
437 */
438 void PRVM_Profile_f (void)
439 {
440         prvm_prog_t *prog;
441         int howmany;
442
443         howmany = 1<<30;
444         if (Cmd_Argc() == 3)
445                 howmany = atoi(Cmd_Argv(2));
446         else if (Cmd_Argc() != 2)
447         {
448                 Con_Print("prvm_profile <program name>\n");
449                 return;
450         }
451
452         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
453                 return;
454
455         PRVM_Profile(prog, howmany, 0, 0);
456 }
457
458 void PRVM_ChildProfile_f (void)
459 {
460         prvm_prog_t *prog;
461         int howmany;
462
463         howmany = 1<<30;
464         if (Cmd_Argc() == 3)
465                 howmany = atoi(Cmd_Argv(2));
466         else if (Cmd_Argc() != 2)
467         {
468                 Con_Print("prvm_childprofile <program name>\n");
469                 return;
470         }
471
472         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
473                 return;
474
475         PRVM_Profile(prog, howmany, 0, 1);
476 }
477
478 void PRVM_PrintState(prvm_prog_t *prog)
479 {
480         int i;
481         if (prog->statestring)
482         {
483                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
484         }
485         if (prog->xfunction)
486         {
487                 for (i = -7; i <= 0;i++)
488                         if (prog->xstatement + i >= prog->xfunction->first_statement)
489                                 PRVM_PrintStatement(prog, prog->statements + prog->xstatement + i);
490         }
491         else
492                 Con_Print("null function executing??\n");
493         PRVM_StackTrace(prog);
494 }
495
496 extern cvar_t prvm_errordump;
497 void PRVM_Crash(prvm_prog_t *prog)
498 {
499         char vabuf[1024];
500         if (prog == NULL)
501                 return;
502         if (!prog->loaded)
503                 return;
504
505         PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
506
507         if( prog->depth > 0 )
508         {
509                 Con_Printf("QuakeC crash report for %s:\n", prog->name);
510                 PRVM_PrintState(prog);
511         }
512
513         if(prvm_errordump.integer)
514         {
515                 // make a savegame
516                 Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
517         }
518
519         // dump the stack so host_error can shutdown functions
520         prog->depth = 0;
521         prog->localstack_used = 0;
522
523         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
524         prog->tempstringsbuf.cursize = 0;
525
526         // reset the prog pointer
527         prog = NULL;
528 }
529
530 /*
531 ============================================================================
532 PRVM_ExecuteProgram
533
534 The interpretation main loop
535 ============================================================================
536 */
537
538 /*
539 ====================
540 PRVM_EnterFunction
541
542 Returns the new program statement counter
543 ====================
544 */
545 static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
546 {
547         int             i, j, c, o;
548
549         if (!f)
550                 prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name);
551
552         prog->stack[prog->depth].s = prog->xstatement;
553         prog->stack[prog->depth].f = prog->xfunction;
554         prog->stack[prog->depth].profile_acc = -f->profile;
555         prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile;
556         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
557         prog->depth++;
558         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
559                 prog->error_cmd("stack overflow");
560
561 // save off any locals that the new function steps on
562         c = f->locals;
563         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
564                 prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
565
566         for (i=0 ; i < c ; i++)
567                 prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
568         prog->localstack_used += c;
569
570 // copy parameters
571         o = f->parm_start;
572         for (i=0 ; i<f->numparms ; i++)
573         {
574                 for (j=0 ; j<f->parm_size[i] ; j++)
575                 {
576                         ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j];
577                         o++;
578                 }
579         }
580
581         ++f->recursion;
582         prog->xfunction = f;
583         return f->first_statement - 1;  // offset the s++
584 }
585
586 /*
587 ====================
588 PRVM_LeaveFunction
589 ====================
590 */
591 static int PRVM_LeaveFunction (prvm_prog_t *prog)
592 {
593         int             i, c;
594         mfunction_t *f;
595
596         if (prog->depth <= 0)
597                 prog->error_cmd("prog stack underflow in %s", prog->name);
598
599         if (!prog->xfunction)
600                 prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name);
601 // restore locals from the stack
602         c = prog->xfunction->locals;
603         prog->localstack_used -= c;
604         if (prog->localstack_used < 0)
605                 prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
606
607         for (i=0 ; i < c ; i++)
608                 ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
609
610 // up stack
611         prog->depth--;
612         f = prog->xfunction;
613         --f->recursion;
614         prog->xfunction = prog->stack[prog->depth].f;
615         prog->stack[prog->depth].profile_acc += f->profile;
616         prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile;
617         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
618         if(prog->depth > 0)
619         {
620                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
621                 prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc;
622                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
623         }
624         if(!f->recursion)
625         {
626                 // if f is already on the call stack...
627                 // we cannot add this profile data to it now
628                 // or we would add it more than once
629                 // so, let's only add to the function's profile if it is the outermost call
630                 f->profile_total += prog->stack[prog->depth].profile_acc;
631                 f->tprofile_total += prog->stack[prog->depth].tprofile_acc;
632                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
633         }
634         
635         return prog->stack[prog->depth].s;
636 }
637
638 void PRVM_Init_Exec(prvm_prog_t *prog)
639 {
640         // dump the stack
641         prog->depth = 0;
642         prog->localstack_used = 0;
643         // reset the string table
644         // nothing here yet
645 }
646
647 #define OPA ((prvm_eval_t *)&prog->globals.generic[st->operand[0]])
648 #define OPB ((prvm_eval_t *)&prog->globals.generic[st->operand[1]])
649 #define OPC ((prvm_eval_t *)&prog->globals.generic[st->operand[2]])
650 extern cvar_t prvm_traceqc;
651 extern cvar_t prvm_statementprofiling;
652 extern qboolean prvm_runawaycheck;
653
654 #ifdef PROFILING
655 /*
656 ====================
657 MVM_ExecuteProgram
658 ====================
659 */
660 void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
661 {
662         mstatement_t    *st, *startst;
663         mfunction_t     *f, *newf;
664         prvm_edict_t    *ed;
665         prvm_eval_t     *ptr;
666         int             jumpcount, cachedpr_trace, exitdepth;
667         int             restorevm_tempstringsbuf_cursize;
668         double  calltime;
669         double tm, starttm;
670
671         calltime = Sys_DirtyTime();
672
673         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
674         {
675                 if (PRVM_allglobaledict(self))
676                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
677                 prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
678         }
679
680         f = &prog->functions[fnum];
681
682         // after executing this function, delete all tempstrings it created
683         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
684
685         prog->trace = prvm_traceqc.integer;
686
687         // we know we're done when pr_depth drops to this
688         exitdepth = prog->depth;
689
690 // make a stack frame
691         st = &prog->statements[PRVM_EnterFunction(prog, f)];
692         // save the starting statement pointer for profiling
693         // (when the function exits or jumps, the (st - startst) integer value is
694         // added to the function's profile counter)
695         startst = st;
696         starttm = calltime;
697         // instead of counting instructions, we count jumps
698         jumpcount = 0;
699         // add one to the callcount of this function because otherwise engine-called functions aren't counted
700         prog->xfunction->callcount++;
701
702 chooseexecprogram:
703         cachedpr_trace = prog->trace;
704         if (prvm_statementprofiling.integer || prog->trace)
705         {
706 #define PRVMSLOWINTERPRETER 1
707                 if (prvm_timeprofiling.integer)
708                 {
709 #define PRVMTIMEPROFILING 1
710 #include "prvm_execprogram.h"
711 #undef PRVMTIMEPROFILING
712                 }
713                 else
714                 {
715 #include "prvm_execprogram.h"
716                 }
717 #undef PRVMSLOWINTERPRETER
718         }
719         else
720         {
721                 if (prvm_timeprofiling.integer)
722                 {
723 #define PRVMTIMEPROFILING 1
724 #include "prvm_execprogram.h"
725 #undef PRVMTIMEPROFILING
726                 }
727                 else
728                 {
729 #include "prvm_execprogram.h"
730                 }
731         }
732
733 cleanup:
734         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
735                 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);
736         // delete tempstrings created by this function
737         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
738
739         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
740         f->totaltime += tm;
741
742         if (prog == SVVM_prog)
743                 SV_FlushBroadcastMessages();
744 }
745
746 /*
747 ====================
748 CLVM_ExecuteProgram
749 ====================
750 */
751 void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
752 {
753         mstatement_t    *st, *startst;
754         mfunction_t     *f, *newf;
755         prvm_edict_t    *ed;
756         prvm_eval_t     *ptr;
757         int             jumpcount, cachedpr_trace, exitdepth;
758         int             restorevm_tempstringsbuf_cursize;
759         double  calltime;
760         double tm, starttm;
761
762         calltime = Sys_DirtyTime();
763
764         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
765         {
766                 if (PRVM_allglobaledict(self))
767                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
768                 prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
769         }
770
771         f = &prog->functions[fnum];
772
773         // after executing this function, delete all tempstrings it created
774         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
775
776         prog->trace = prvm_traceqc.integer;
777
778         // we know we're done when pr_depth drops to this
779         exitdepth = prog->depth;
780
781 // make a stack frame
782         st = &prog->statements[PRVM_EnterFunction(prog, f)];
783         // save the starting statement pointer for profiling
784         // (when the function exits or jumps, the (st - startst) integer value is
785         // added to the function's profile counter)
786         startst = st;
787         starttm = calltime;
788         // instead of counting instructions, we count jumps
789         jumpcount = 0;
790         // add one to the callcount of this function because otherwise engine-called functions aren't counted
791         prog->xfunction->callcount++;
792
793 chooseexecprogram:
794         cachedpr_trace = prog->trace;
795         if (prvm_statementprofiling.integer || prog->trace)
796         {
797 #define PRVMSLOWINTERPRETER 1
798                 if (prvm_timeprofiling.integer)
799                 {
800 #define PRVMTIMEPROFILING 1
801 #include "prvm_execprogram.h"
802 #undef PRVMTIMEPROFILING
803                 }
804                 else
805                 {
806 #include "prvm_execprogram.h"
807                 }
808 #undef PRVMSLOWINTERPRETER
809         }
810         else
811         {
812                 if (prvm_timeprofiling.integer)
813                 {
814 #define PRVMTIMEPROFILING 1
815 #include "prvm_execprogram.h"
816 #undef PRVMTIMEPROFILING
817                 }
818                 else
819                 {
820 #include "prvm_execprogram.h"
821                 }
822         }
823
824 cleanup:
825         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
826                 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);
827         // delete tempstrings created by this function
828         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
829
830         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
831         f->totaltime += tm;
832
833         if (prog == SVVM_prog)
834                 SV_FlushBroadcastMessages();
835 }
836 #endif
837
838 /*
839 ====================
840 SVVM_ExecuteProgram
841 ====================
842 */
843 #ifdef PROFILING
844 void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
845 #else
846 void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
847 #endif
848 {
849         mstatement_t    *st, *startst;
850         mfunction_t     *f, *newf;
851         prvm_edict_t    *ed;
852         prvm_eval_t     *ptr;
853         int             jumpcount, cachedpr_trace, exitdepth;
854         int             restorevm_tempstringsbuf_cursize;
855         double  calltime;
856         double tm, starttm;
857
858         calltime = Sys_DirtyTime();
859
860         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
861         {
862                 if (PRVM_allglobaledict(self))
863                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
864                 prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
865         }
866
867         f = &prog->functions[fnum];
868
869         // after executing this function, delete all tempstrings it created
870         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
871
872         prog->trace = prvm_traceqc.integer;
873
874         // we know we're done when pr_depth drops to this
875         exitdepth = prog->depth;
876
877 // make a stack frame
878         st = &prog->statements[PRVM_EnterFunction(prog, f)];
879         // save the starting statement pointer for profiling
880         // (when the function exits or jumps, the (st - startst) integer value is
881         // added to the function's profile counter)
882         startst = st;
883         starttm = calltime;
884         // instead of counting instructions, we count jumps
885         jumpcount = 0;
886         // add one to the callcount of this function because otherwise engine-called functions aren't counted
887         prog->xfunction->callcount++;
888
889 chooseexecprogram:
890         cachedpr_trace = prog->trace;
891         if (prvm_statementprofiling.integer || prog->trace)
892         {
893 #define PRVMSLOWINTERPRETER 1
894                 if (prvm_timeprofiling.integer)
895                 {
896 #define PRVMTIMEPROFILING 1
897 #include "prvm_execprogram.h"
898 #undef PRVMTIMEPROFILING
899                 }
900                 else
901                 {
902 #include "prvm_execprogram.h"
903                 }
904 #undef PRVMSLOWINTERPRETER
905         }
906         else
907         {
908                 if (prvm_timeprofiling.integer)
909                 {
910 #define PRVMTIMEPROFILING 1
911 #include "prvm_execprogram.h"
912 #undef PRVMTIMEPROFILING
913                 }
914                 else
915                 {
916 #include "prvm_execprogram.h"
917                 }
918         }
919
920 cleanup:
921         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
922                 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);
923         // delete tempstrings created by this function
924         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
925
926         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
927         f->totaltime += tm;
928
929         if (prog == SVVM_prog)
930                 SV_FlushBroadcastMessages();
931 }