]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_exec.c
com_list.h: Fix copy/paste oversight where List_For_Each_Entry went backwards like...
[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 static 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 NULL,
116 NULL,
117 NULL,
118 NULL,
119 NULL,
120 NULL,
121 NULL,
122 NULL,
123 NULL,
124 NULL,
125 NULL,
126 NULL,
127 NULL,
128 NULL,
129 NULL,
130 NULL,
131 NULL,
132 NULL,
133 NULL,
134 NULL,
135 NULL,
136 NULL,
137 NULL,
138 NULL,
139 NULL,
140 NULL,
141 NULL,
142 NULL,
143 NULL,
144 NULL,
145 NULL,
146 NULL,
147 NULL,
148 NULL,
149 NULL,
150 NULL,
151 NULL,
152 NULL,
153 NULL,
154 NULL,
155 NULL,
156 NULL,
157 NULL,
158 NULL,
159 NULL,
160 NULL,
161 NULL,
162
163 "STORE_I",
164
165 NULL,
166 NULL,
167
168 "ADD_I",
169 "ADD_FI",
170 "ADD_IF",
171
172 "SUB_I",
173 "SUB_FI",
174 "SUB_IF",
175 "CONV_IF",
176 "CONV_FI",
177
178 NULL,
179 NULL,
180
181 "LOAD_I",
182 "STOREP_I",
183
184 NULL,
185 NULL,
186
187 "BITAND_I",
188 "BITOR_I",
189
190 "MUL_I",
191 "DIV_I",
192 "EQ_I",
193 "NE_I",
194
195 NULL,
196 NULL,
197
198 "NOT_I",
199
200 "DIV_VF",
201
202 NULL,
203 NULL,
204 NULL,
205 NULL,
206 NULL,
207 NULL,
208 NULL,
209 NULL,
210 NULL,
211 NULL,
212 NULL,
213 NULL,
214
215 "STORE_P",
216
217 NULL,
218 NULL,
219 NULL,
220 NULL,
221 NULL,
222 NULL,
223 NULL,
224 NULL,
225
226 "LE_I",
227 "GE_I",
228 "LT_I",
229 "GT_I",
230
231 "LE_IF",
232 "GE_IF",
233 "LT_IF",
234 "GT_IF",
235
236 "LE_FI",
237 "GE_FI",
238 "LT_FI",
239 "GT_FI",
240
241 "EQ_IF",
242 "EQ_FI",
243
244 NULL,
245 NULL,
246 NULL,
247 NULL,
248
249 "MUL_IF",
250 "MUL_FI",
251 "MUL_VI",
252
253 NULL,
254
255 "DIV_IF",
256 "DIV_FI",
257 "BITAND_IF",
258 "BITOR_IF",
259 "BITAND_FI",
260 "BITOR_FI",
261 "AND_I",
262 "OR_I",
263 "AND_IF",
264 "OR_IF",
265 "AND_FI",
266 "OR_FI",
267 "NE_IF",
268 "NE_FI",
269
270 "GSTOREP_I",
271 "GSTOREP_F",
272 "GSTOREP_ENT",
273 "GSTOREP_FLD",
274 "GSTOREP_S",
275 "GSTOREP_FNC",
276 "GSTOREP_V",
277 "GADDRESS",
278 "GLOAD_I",
279 "GLOAD_F",
280 "GLOAD_FLD",
281 "GLOAD_ENT",
282 "GLOAD_S",
283 "GLOAD_FNC",
284 "BOUNDCHECK",
285 NULL,
286 NULL,
287 NULL,
288 NULL,
289 "GLOAD_V",
290 };
291
292
293
294 //=============================================================================
295
296 /*
297 =================
298 PRVM_PrintStatement
299 =================
300 */
301 extern cvar_t prvm_coverage;
302 extern cvar_t prvm_statementprofiling;
303 extern cvar_t prvm_timeprofiling;
304 static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s)
305 {
306         size_t i;
307         int opnum = (int)(s - prog->statements);
308         char valuebuf[MAX_INPUTLINE];
309         const char *opname;
310
311         Con_Printf("s%i: ", opnum);
312         if( prog->statement_linenums )
313         {
314                 if ( prog->statement_columnnums )
315                         Con_Printf( "%s:%i:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ], prog->statement_columnnums[ opnum ] );
316                 else
317                         Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] );
318         }
319
320         if (prvm_statementprofiling.integer)
321                 Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]);
322
323         if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]) && prvm_opnames[s->op])
324                 opname = prvm_opnames[s->op];
325         else
326                 opname = valuebuf, dpsnprintf(valuebuf, sizeof(valuebuf), "OPCODE_%u", (unsigned)s->op);
327         Con_Printf("%s ",  opname);
328         i = strlen(opname);
329         // don't count a preceding color tag when padding the name
330         if (opname[0] == STRING_COLOR_TAG)
331                 i -= 2;
332         for ( ; i<10 ; i++)
333                 Con_Print(" ");
334
335         if (s->operand[0] >= 0) Con_Printf(  "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf)));
336         if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf)));
337         if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf)));
338         if (s->jumpabsolute >= 0) Con_Printf(", statement %i", s->jumpabsolute);
339         Con_Print("\n");
340 }
341
342 void PRVM_PrintFunctionStatements (prvm_prog_t *prog, const char *name)
343 {
344         int i, firststatement, endstatement;
345         mfunction_t *func;
346         func = PRVM_ED_FindFunction (prog, name);
347         if (!func)
348         {
349                 Con_Printf("%s progs: no function named %s\n", prog->name, name);
350                 return;
351         }
352         firststatement = func->first_statement;
353         if (firststatement < 0)
354         {
355                 Con_Printf("%s progs: function %s is builtin #%i\n", prog->name, name, -firststatement);
356                 return;
357         }
358
359         // find the end statement
360         endstatement = prog->numstatements;
361         for (i = 0;i < prog->numfunctions;i++)
362                 if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement)
363                         endstatement = prog->functions[i].first_statement;
364
365         // now print the range of statements
366         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);
367         prog->xfunction = func;
368         for (i = firststatement;i < endstatement;i++)
369         {
370                 PRVM_PrintStatement(prog, prog->statements + i);
371                 if (!(prvm_coverage.integer & 4))
372                         prog->statement_profile[i] = 0;
373         }
374         if (prvm_coverage.integer & 4)
375                 Con_Printf("Collecting statement coverage, not flushing statement profile.\n");
376 }
377
378 /*
379 ============
380 PRVM_PrintFunction_f
381
382 ============
383 */
384 void PRVM_PrintFunction_f(cmd_state_t *cmd)
385 {
386         prvm_prog_t *prog;
387         if (Cmd_Argc(cmd) != 3)
388         {
389                 Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
390                 return;
391         }
392
393         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
394                 return;
395
396         PRVM_PrintFunctionStatements(prog, Cmd_Argv(cmd, 2));
397 }
398
399 /*
400 ============
401 PRVM_StackTrace
402 ============
403 */
404 void PRVM_StackTrace (prvm_prog_t *prog)
405 {
406         mfunction_t     *f;
407         int                     i;
408
409         prog->stack[prog->depth].s = prog->xstatement;
410         prog->stack[prog->depth].f = prog->xfunction;
411         for (i = prog->depth;i > 0;i--)
412         {
413                 f = prog->stack[i].f;
414
415                 if (!f)
416                         Con_Print("<NULL FUNCTION>\n");
417                 else
418                 {
419                         if (prog->statement_linenums)
420                         {
421                                 if (prog->statement_columnnums)
422                                         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);
423                                 else
424                                         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);
425                         }
426                         else
427                                 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);
428                 }
429         }
430 }
431
432 void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize)
433 {
434         mfunction_t     *f;
435         int                     i;
436         char vabuf[1024];
437
438         if(prog)
439         {
440                 dpsnprintf(buf, bufsize, "(%s) ", prog->name);
441         }
442         else
443         {
444                 strlcpy(buf, "<NO PROG>", bufsize);
445                 return;
446         }
447
448         prog->stack[prog->depth].s = prog->xstatement;
449         prog->stack[prog->depth].f = prog->xfunction;
450         for (i = prog->depth;i > 0;i--)
451         {
452                 f = prog->stack[i].f;
453
454                 if(strlcat(buf,
455                         f
456                                 ? 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)
457                                 : "<NULL> ",
458                         bufsize
459                 ) >= bufsize)
460                         break;
461         }
462 }
463
464
465 static void PRVM_CallProfile (prvm_prog_t *prog)
466 {
467         mfunction_t *f, *best;
468         int i;
469         double max;
470         double sum;
471         double newprofiletime;
472
473         Con_Printf( "%s Call Profile:\n", prog->name );
474
475         sum = 0;
476         do
477         {
478                 max = 0;
479                 best = NULL;
480                 for (i=0 ; i<prog->numfunctions ; i++)
481                 {
482                         f = &prog->functions[i];
483                         if (max < f->totaltime)
484                         {
485                                 max = f->totaltime;
486                                 best = f;
487                         }
488                 }
489                 if (best)
490                 {
491                         sum += best->totaltime;
492                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name));
493                         best->totaltime = 0;
494                 }
495         } while (best);
496
497         newprofiletime = Sys_DirtyTime();
498         Con_Printf("Total time since last profile reset: %9.4f\n", newprofiletime - prog->profiletime);
499         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
500
501         prog->profiletime = newprofiletime;
502 }
503
504 void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby)
505 {
506         mfunction_t *f, *best;
507         int i, num;
508         double max;
509
510         if(!prvm_timeprofiling.integer)
511                 mintime *= 10000000; // count each statement as about 0.1µs
512
513         if(prvm_timeprofiling.integer)
514                 Con_Printf( "%s Profile:\n[CallCount]      [Time] [BuiltinTm] [Statement] [BuiltinCt] [TimeTotal] [StmtTotal] [BltnTotal] [self]\n", prog->name );
515                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
516         else
517                 Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name );
518                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
519
520         num = 0;
521         do
522         {
523                 max = 0;
524                 best = NULL;
525                 for (i=0 ; i<prog->numfunctions ; i++)
526                 {
527                         f = &prog->functions[i];
528                         if(prvm_timeprofiling.integer)
529                         {
530                                 if(sortby)
531                                 {
532                                         if(f->first_statement < 0)
533                                         {
534                                                 if (max < f->tprofile)
535                                                 {
536                                                         max = f->tprofile;
537                                                         best = f;
538                                                 }
539                                         }
540                                         else
541                                         {
542                                                 if (max < f->tprofile_total)
543                                                 {
544                                                         max = f->tprofile_total;
545                                                         best = f;
546                                                 }
547                                         }
548                                 }
549                                 else
550                                 {
551                                         if (max < f->tprofile + f->tbprofile)
552                                         {
553                                                 max = f->tprofile + f->tbprofile;
554                                                 best = f;
555                                         }
556                                 }
557                         }
558                         else
559                         {
560                                 if(sortby)
561                                 {
562                                         if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
563                                         {
564                                                 max = f->profile_total + f->builtinsprofile_total + f->callcount;
565                                                 best = f;
566                                         }
567                                 }
568                                 else
569                                 {
570                                         if (max < f->profile + f->builtinsprofile + f->callcount)
571                                         {
572                                                 max = f->profile + f->builtinsprofile + f->callcount;
573                                                 best = f;
574                                         }
575                                 }
576                         }
577                 }
578                 if (best)
579                 {
580                         if (num < maxfunctions && max > mintime)
581                         {
582                                 if(prvm_timeprofiling.integer)
583                                 {
584                                         if (best->first_statement < 0)
585                                                 Con_Printf("%11.0f %11.6f ------------- builtin ------------- %11.6f ----------- builtin ----------- %s\n", best->callcount, best->tprofile, best->tprofile, PRVM_GetString(prog, best->s_name));
586                                         //                 %11.6f 12345678901 12345678901 12345678901 %11.6f 12345678901 12345678901 123.45%
587                                         else
588                                                 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));
589                                 }
590                                 else
591                                 {
592                                         if (best->first_statement < 0)
593                                                 Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(prog, best->s_name));
594                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
595                                         else
596                                                 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));
597                                 }
598                         }
599                         num++;
600                         best->profile = 0;
601                         best->tprofile = 0;
602                         best->tbprofile = 0;
603                         best->builtinsprofile = 0;
604                         best->profile_total = 0;
605                         best->tprofile_total = 0;
606                         best->builtinsprofile_total = 0;
607                         best->callcount = 0;
608                 }
609         } while (best);
610 }
611
612 /*
613 ============
614 PRVM_CallProfile_f
615
616 ============
617 */
618 void PRVM_CallProfile_f(cmd_state_t *cmd)
619 {
620         prvm_prog_t *prog;
621         if (Cmd_Argc(cmd) != 2)
622         {
623                 Con_Print("prvm_callprofile <program name>\n");
624                 return;
625         }
626
627         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
628                 return;
629
630         PRVM_CallProfile(prog);
631 }
632
633 /*
634 ============
635 PRVM_Profile_f
636
637 ============
638 */
639 void PRVM_Profile_f(cmd_state_t *cmd)
640 {
641         prvm_prog_t *prog;
642         int howmany;
643
644         if (prvm_coverage.integer & 1)
645         {
646                 Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
647                 return;
648         }
649
650         howmany = 1<<30;
651         if (Cmd_Argc(cmd) == 3)
652                 howmany = atoi(Cmd_Argv(cmd, 2));
653         else if (Cmd_Argc(cmd) != 2)
654         {
655                 Con_Print("prvm_profile <program name>\n");
656                 return;
657         }
658
659         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
660                 return;
661
662         PRVM_Profile(prog, howmany, 0, 0);
663 }
664
665 void PRVM_ChildProfile_f(cmd_state_t *cmd)
666 {
667         prvm_prog_t *prog;
668         int howmany;
669
670         if (prvm_coverage.integer & 1)
671         {
672                 Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
673                 return;
674         }
675
676         howmany = 1<<30;
677         if (Cmd_Argc(cmd) == 3)
678                 howmany = atoi(Cmd_Argv(cmd, 2));
679         else if (Cmd_Argc(cmd) != 2)
680         {
681                 Con_Print("prvm_childprofile <program name>\n");
682                 return;
683         }
684
685         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
686                 return;
687
688         PRVM_Profile(prog, howmany, 0, 1);
689 }
690
691 void PRVM_PrintState(prvm_prog_t *prog, int stack_index)
692 {
693         int i;
694         mfunction_t *func = prog->xfunction;
695         int st = prog->xstatement;
696         if (stack_index > 0 && stack_index <= prog->depth)
697         {
698                 func = prog->stack[prog->depth - stack_index].f;
699                 st = prog->stack[prog->depth - stack_index].s;
700         }
701         if (prog->statestring)
702         {
703                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
704         }
705         if (func)
706         {
707                 for (i = -7; i <= 0;i++)
708                         if (st + i >= func->first_statement)
709                                 PRVM_PrintStatement(prog, prog->statements + st + i);
710         }
711         PRVM_StackTrace(prog);
712 }
713
714 extern cvar_t prvm_errordump;
715 void PRVM_Crash(prvm_prog_t *prog)
716 {
717         char vabuf[1024];
718
719         cl.csqc_loaded = false;
720
721         if (prog == NULL)
722                 return;
723         if (!prog->loaded)
724                 return;
725
726         PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
727
728         if( prog->depth > 0 )
729         {
730                 Con_Printf("QuakeC crash report for %s:\n", prog->name);
731                 PRVM_PrintState(prog, 0);
732         }
733
734         if(prvm_errordump.integer)
735         {
736                 // make a savegame
737                 SV_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
738         }
739
740         // dump the stack so host_error can shutdown functions
741         prog->depth = 0;
742         prog->localstack_used = 0;
743
744         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
745         prog->tempstringsbuf.cursize = 0;
746
747         // reset the prog pointer
748         prog = NULL;
749 }
750
751 /*
752 ============================================================================
753 PRVM_ExecuteProgram
754
755 The interpretation main loop
756 ============================================================================
757 */
758
759 /*
760 ====================
761 PRVM_EnterFunction
762
763 Returns the new program statement counter
764 ====================
765 */
766 static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
767 {
768         int             i, j, c, o;
769
770         if (!f)
771                 prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name);
772
773         prog->stack[prog->depth].s = prog->xstatement;
774         prog->stack[prog->depth].f = prog->xfunction;
775         prog->stack[prog->depth].profile_acc = -f->profile;
776         prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile;
777         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
778         prog->depth++;
779         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
780                 prog->error_cmd("stack overflow");
781
782 // save off any locals that the new function steps on
783         c = f->locals;
784         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
785                 prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
786
787         for (i=0 ; i < c ; i++)
788                 prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i];
789         prog->localstack_used += c;
790
791 // copy parameters
792         o = f->parm_start;
793         for (i=0 ; i<f->numparms ; i++)
794         {
795                 for (j=0 ; j<f->parm_size[i] ; j++)
796                 {
797                         prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j];
798                         o++;
799                 }
800         }
801
802         ++f->recursion;
803         prog->xfunction = f;
804         return f->first_statement - 1;  // offset the s++
805 }
806
807 /*
808 ====================
809 PRVM_LeaveFunction
810 ====================
811 */
812 static int PRVM_LeaveFunction (prvm_prog_t *prog)
813 {
814         int             i, c;
815         mfunction_t *f;
816
817         if (prog->depth <= 0)
818                 prog->error_cmd("prog stack underflow in %s", prog->name);
819
820         if (!prog->xfunction)
821                 prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name);
822 // restore locals from the stack
823         c = prog->xfunction->locals;
824         prog->localstack_used -= c;
825         if (prog->localstack_used < 0)
826                 prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
827
828         for (i=0 ; i < c ; i++)
829                 prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
830
831 // up stack
832         prog->depth--;
833         f = prog->xfunction;
834         --f->recursion;
835         prog->xfunction = prog->stack[prog->depth].f;
836         prog->stack[prog->depth].profile_acc += f->profile;
837         prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile;
838         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
839         if(prog->depth > 0)
840         {
841                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
842                 prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc;
843                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
844         }
845         if(!f->recursion)
846         {
847                 // if f is already on the call stack...
848                 // we cannot add this profile data to it now
849                 // or we would add it more than once
850                 // so, let's only add to the function's profile if it is the outermost call
851                 f->profile_total += prog->stack[prog->depth].profile_acc;
852                 f->tprofile_total += prog->stack[prog->depth].tprofile_acc;
853                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
854         }
855         
856         return prog->stack[prog->depth].s;
857 }
858
859 void PRVM_Init_Exec(prvm_prog_t *prog)
860 {
861         // dump the stack
862         prog->depth = 0;
863         prog->localstack_used = 0;
864         // reset the string table
865         // nothing here yet
866 }
867
868 /*
869 ==================
870 Coverage
871 ==================
872 */
873 // Note: in these two calls, prog->xfunction is assumed to be sane.
874 static const char *PRVM_WhereAmI(char *buf, size_t bufsize, prvm_prog_t *prog, mfunction_t *func, int statement)
875 {
876         if (prog->statement_linenums)
877         {
878                 if (prog->statement_columnnums)
879                         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);
880                 else
881                         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);
882         }
883         else
884                 return va(buf, bufsize, "%s(%s, %i)", PRVM_GetString(prog, func->s_file), PRVM_GetString(prog, func->s_name), statement - func->first_statement);
885 }
886 static void PRVM_FunctionCoverageEvent(prvm_prog_t *prog, mfunction_t *func)
887 {
888         ++prog->functions_covered;
889         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);
890 }
891 void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
892 {
893         char vabuf[128];
894         ++prog->explicit_covered;
895         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);
896 }
897 static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
898 {
899         char vabuf[128];
900         ++prog->statements_covered;
901         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);
902 }
903
904 #if defined (__GNUC__) || (__clang__) || (__TINYC__)
905 #  ifndef CONFIG_PEDANTIC
906 #  define HAVE_COMPUTED_GOTOS 1
907 #  endif
908 #endif
909
910 #define OPA ((prvm_eval_t *)&globals[st->operand[0]])
911 #define OPB ((prvm_eval_t *)&globals[st->operand[1]])
912 #define OPC ((prvm_eval_t *)&globals[st->operand[2]])
913 extern cvar_t prvm_traceqc;
914 extern cvar_t prvm_statementprofiling;
915 extern qbool prvm_runawaycheck;
916
917 #ifdef PROFILING
918 #ifdef CONFIG_MENU
919 /*
920 ====================
921 MVM_ExecuteProgram
922 ====================
923 */
924 void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
925 {
926         mstatement_t    *st, *startst;
927         mfunction_t             *func, *enterfunc;
928         prvm_edict_t    *ed;
929         prvm_eval_t     *ptr;
930         int             jumpcount, cachedpr_trace, exitdepth;
931         int             restorevm_tempstringsbuf_cursize;
932         double  calltime;
933         double tm, starttm;
934         prvm_vec_t tempfloat;
935         // these may become out of date when a builtin is called, and are updated accordingly
936         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
937         unsigned int cached_entityfields = prog->entityfields;
938         unsigned int cached_entityfields_3 = prog->entityfields - 3;
939         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
940         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
941         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
942         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
943         unsigned int cached_max_edicts = prog->max_edicts;
944         // these do not change
945         mstatement_t *cached_statements = prog->statements;
946         qbool cached_allowworldwrites = prog->allowworldwrites;
947         unsigned int cached_flag = prog->flag;
948
949         prvm_vec_t *globals = prog->globals.fp;
950
951         calltime = Sys_DirtyTime();
952
953         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
954         {
955                 if (PRVM_allglobaledict(self))
956                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
957                 prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
958         }
959
960         func = &prog->functions[fnum];
961
962         // after executing this function, delete all tempstrings it created
963         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
964
965         prog->trace = prvm_traceqc.integer;
966
967         // we know we're done when pr_depth drops to this
968         exitdepth = prog->depth;
969
970 // make a stack frame
971         st = &prog->statements[PRVM_EnterFunction(prog, func)];
972         // save the starting statement pointer for profiling
973         // (when the function exits or jumps, the (st - startst) integer value is
974         // added to the function's profile counter)
975         startst = st;
976         starttm = calltime;
977         // instead of counting instructions, we count jumps
978         jumpcount = 0;
979         // add one to the callcount of this function because otherwise engine-called functions aren't counted
980         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
981                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
982
983 chooseexecprogram:
984         cachedpr_trace = prog->trace;
985         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
986         {
987 #define PRVMSLOWINTERPRETER 1
988                 if (prvm_timeprofiling.integer)
989                 {
990 #define PRVMTIMEPROFILING 1
991 #include "prvm_execprogram.h"
992 #undef PRVMTIMEPROFILING
993                 }
994                 else
995                 {
996 #include "prvm_execprogram.h"
997                 }
998 #undef PRVMSLOWINTERPRETER
999         }
1000         else
1001         {
1002                 if (prvm_timeprofiling.integer)
1003                 {
1004 #define PRVMTIMEPROFILING 1
1005 #include "prvm_execprogram.h"
1006 #undef PRVMTIMEPROFILING
1007                 }
1008                 else
1009                 {
1010 #include "prvm_execprogram.h"
1011                 }
1012         }
1013
1014 cleanup:
1015         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1016                 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);
1017         // delete tempstrings created by this function
1018         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1019
1020         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1021         func->totaltime += tm;
1022
1023         if (prog == SVVM_prog)
1024                 SV_FlushBroadcastMessages();
1025 }
1026 #endif
1027
1028 /*
1029 ====================
1030 CLVM_ExecuteProgram
1031 ====================
1032 */
1033 void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1034 {
1035         mstatement_t    *st, *startst;
1036         mfunction_t             *func, *enterfunc;
1037         prvm_edict_t    *ed;
1038         prvm_eval_t     *ptr;
1039         int             jumpcount, cachedpr_trace, exitdepth;
1040         int             restorevm_tempstringsbuf_cursize;
1041         double  calltime;
1042         double tm, starttm;
1043         prvm_vec_t tempfloat;
1044         // these may become out of date when a builtin is called, and are updated accordingly
1045         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1046         unsigned int cached_entityfields = prog->entityfields;
1047         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1048         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1049         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1050         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1051         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1052         unsigned int cached_max_edicts = prog->max_edicts;
1053         // these do not change
1054         mstatement_t *cached_statements = prog->statements;
1055         qbool cached_allowworldwrites = prog->allowworldwrites;
1056         unsigned int cached_flag = prog->flag;
1057
1058         prvm_vec_t *globals = prog->globals.fp;
1059
1060         calltime = Sys_DirtyTime();
1061
1062         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1063         {
1064                 if (PRVM_allglobaledict(self))
1065                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1066                 prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
1067         }
1068
1069         func = &prog->functions[fnum];
1070
1071         // after executing this function, delete all tempstrings it created
1072         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1073
1074         prog->trace = prvm_traceqc.integer;
1075
1076         // we know we're done when pr_depth drops to this
1077         exitdepth = prog->depth;
1078
1079 // make a stack frame
1080         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1081         // save the starting statement pointer for profiling
1082         // (when the function exits or jumps, the (st - startst) integer value is
1083         // added to the function's profile counter)
1084         startst = st;
1085         starttm = calltime;
1086         // instead of counting instructions, we count jumps
1087         jumpcount = 0;
1088         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1089         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1090                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1091
1092 chooseexecprogram:
1093         cachedpr_trace = prog->trace;
1094         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1095         {
1096 #define PRVMSLOWINTERPRETER 1
1097                 if (prvm_timeprofiling.integer)
1098                 {
1099 #define PRVMTIMEPROFILING 1
1100 #include "prvm_execprogram.h"
1101 #undef PRVMTIMEPROFILING
1102                 }
1103                 else
1104                 {
1105 #include "prvm_execprogram.h"
1106                 }
1107 #undef PRVMSLOWINTERPRETER
1108         }
1109         else
1110         {
1111                 if (prvm_timeprofiling.integer)
1112                 {
1113 #define PRVMTIMEPROFILING 1
1114 #include "prvm_execprogram.h"
1115 #undef PRVMTIMEPROFILING
1116                 }
1117                 else
1118                 {
1119 #include "prvm_execprogram.h"
1120                 }
1121         }
1122
1123 cleanup:
1124         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1125                 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);
1126         // delete tempstrings created by this function
1127         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1128
1129         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1130         func->totaltime += tm;
1131
1132         if (prog == SVVM_prog)
1133                 SV_FlushBroadcastMessages();
1134 }
1135 #endif
1136
1137 /*
1138 ====================
1139 SVVM_ExecuteProgram
1140 ====================
1141 */
1142 #ifdef PROFILING
1143 void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1144 #else
1145 void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1146 #endif
1147 {
1148         mstatement_t    *st, *startst;
1149         mfunction_t             *func, *enterfunc;
1150         prvm_edict_t    *ed;
1151         prvm_eval_t     *ptr;
1152         int             jumpcount, cachedpr_trace, exitdepth;
1153         int             restorevm_tempstringsbuf_cursize;
1154         double  calltime;
1155         double tm, starttm;
1156         prvm_vec_t tempfloat;
1157         // these may become out of date when a builtin is called, and are updated accordingly
1158         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1159         unsigned int cached_entityfields = prog->entityfields;
1160         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1161         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1162         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1163         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1164         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1165         unsigned int cached_max_edicts = prog->max_edicts;
1166         // these do not change
1167         mstatement_t *cached_statements = prog->statements;
1168         qbool cached_allowworldwrites = prog->allowworldwrites;
1169         unsigned int cached_flag = prog->flag;
1170
1171         prvm_vec_t *globals = prog->globals.fp;
1172
1173         calltime = Sys_DirtyTime();
1174
1175         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1176         {
1177                 if (PRVM_allglobaledict(self))
1178                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1179                 prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
1180         }
1181
1182         func = &prog->functions[fnum];
1183
1184         // after executing this function, delete all tempstrings it created
1185         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1186
1187         prog->trace = prvm_traceqc.integer;
1188
1189         // we know we're done when pr_depth drops to this
1190         exitdepth = prog->depth;
1191
1192 // make a stack frame
1193         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1194         // save the starting statement pointer for profiling
1195         // (when the function exits or jumps, the (st - startst) integer value is
1196         // added to the function's profile counter)
1197         startst = st;
1198         starttm = calltime;
1199         // instead of counting instructions, we count jumps
1200         jumpcount = 0;
1201         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1202         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1203                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1204
1205 chooseexecprogram:
1206         cachedpr_trace = prog->trace;
1207         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1208         {
1209 #define PRVMSLOWINTERPRETER 1
1210                 if (prvm_timeprofiling.integer)
1211                 {
1212 #define PRVMTIMEPROFILING 1
1213 #include "prvm_execprogram.h"
1214 #undef PRVMTIMEPROFILING
1215                 }
1216                 else
1217                 {
1218 #include "prvm_execprogram.h"
1219                 }
1220 #undef PRVMSLOWINTERPRETER
1221         }
1222         else
1223         {
1224                 if (prvm_timeprofiling.integer)
1225                 {
1226 #define PRVMTIMEPROFILING 1
1227 #include "prvm_execprogram.h"
1228 #undef PRVMTIMEPROFILING
1229                 }
1230                 else
1231                 {
1232 #include "prvm_execprogram.h"
1233                 }
1234         }
1235
1236 cleanup:
1237         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1238                 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);
1239         // delete tempstrings created by this function
1240         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1241
1242         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1243         func->totaltime += tm;
1244
1245         if (prog == SVVM_prog)
1246                 SV_FlushBroadcastMessages();
1247 }