]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_exec.c
Rename qboolean to qbool
[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         if (prog == NULL)
719                 return;
720         if (!prog->loaded)
721                 return;
722
723         PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
724
725         if( prog->depth > 0 )
726         {
727                 Con_Printf("QuakeC crash report for %s:\n", prog->name);
728                 PRVM_PrintState(prog, 0);
729         }
730
731         if(prvm_errordump.integer)
732         {
733                 // make a savegame
734                 SV_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
735         }
736
737         // dump the stack so host_error can shutdown functions
738         prog->depth = 0;
739         prog->localstack_used = 0;
740
741         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
742         prog->tempstringsbuf.cursize = 0;
743
744         // reset the prog pointer
745         prog = NULL;
746 }
747
748 /*
749 ============================================================================
750 PRVM_ExecuteProgram
751
752 The interpretation main loop
753 ============================================================================
754 */
755
756 /*
757 ====================
758 PRVM_EnterFunction
759
760 Returns the new program statement counter
761 ====================
762 */
763 static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
764 {
765         int             i, j, c, o;
766
767         if (!f)
768                 prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name);
769
770         prog->stack[prog->depth].s = prog->xstatement;
771         prog->stack[prog->depth].f = prog->xfunction;
772         prog->stack[prog->depth].profile_acc = -f->profile;
773         prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile;
774         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
775         prog->depth++;
776         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
777                 prog->error_cmd("stack overflow");
778
779 // save off any locals that the new function steps on
780         c = f->locals;
781         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
782                 prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
783
784         for (i=0 ; i < c ; i++)
785                 prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i];
786         prog->localstack_used += c;
787
788 // copy parameters
789         o = f->parm_start;
790         for (i=0 ; i<f->numparms ; i++)
791         {
792                 for (j=0 ; j<f->parm_size[i] ; j++)
793                 {
794                         prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j];
795                         o++;
796                 }
797         }
798
799         ++f->recursion;
800         prog->xfunction = f;
801         return f->first_statement - 1;  // offset the s++
802 }
803
804 /*
805 ====================
806 PRVM_LeaveFunction
807 ====================
808 */
809 static int PRVM_LeaveFunction (prvm_prog_t *prog)
810 {
811         int             i, c;
812         mfunction_t *f;
813
814         if (prog->depth <= 0)
815                 prog->error_cmd("prog stack underflow in %s", prog->name);
816
817         if (!prog->xfunction)
818                 prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name);
819 // restore locals from the stack
820         c = prog->xfunction->locals;
821         prog->localstack_used -= c;
822         if (prog->localstack_used < 0)
823                 prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
824
825         for (i=0 ; i < c ; i++)
826                 prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
827
828 // up stack
829         prog->depth--;
830         f = prog->xfunction;
831         --f->recursion;
832         prog->xfunction = prog->stack[prog->depth].f;
833         prog->stack[prog->depth].profile_acc += f->profile;
834         prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile;
835         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
836         if(prog->depth > 0)
837         {
838                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
839                 prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc;
840                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
841         }
842         if(!f->recursion)
843         {
844                 // if f is already on the call stack...
845                 // we cannot add this profile data to it now
846                 // or we would add it more than once
847                 // so, let's only add to the function's profile if it is the outermost call
848                 f->profile_total += prog->stack[prog->depth].profile_acc;
849                 f->tprofile_total += prog->stack[prog->depth].tprofile_acc;
850                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
851         }
852         
853         return prog->stack[prog->depth].s;
854 }
855
856 void PRVM_Init_Exec(prvm_prog_t *prog)
857 {
858         // dump the stack
859         prog->depth = 0;
860         prog->localstack_used = 0;
861         // reset the string table
862         // nothing here yet
863 }
864
865 /*
866 ==================
867 Coverage
868 ==================
869 */
870 // Note: in these two calls, prog->xfunction is assumed to be sane.
871 static const char *PRVM_WhereAmI(char *buf, size_t bufsize, prvm_prog_t *prog, mfunction_t *func, int statement)
872 {
873         if (prog->statement_linenums)
874         {
875                 if (prog->statement_columnnums)
876                         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);
877                 else
878                         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);
879         }
880         else
881                 return va(buf, bufsize, "%s(%s, %i)", PRVM_GetString(prog, func->s_file), PRVM_GetString(prog, func->s_name), statement - func->first_statement);
882 }
883 static void PRVM_FunctionCoverageEvent(prvm_prog_t *prog, mfunction_t *func)
884 {
885         ++prog->functions_covered;
886         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);
887 }
888 void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
889 {
890         char vabuf[128];
891         ++prog->explicit_covered;
892         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);
893 }
894 static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
895 {
896         char vabuf[128];
897         ++prog->statements_covered;
898         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);
899 }
900
901 #if defined (__GNUC__) || (__clang__) || (__TINYC__)
902 #  ifndef CONFIG_PEDANTIC
903 #  define HAVE_COMPUTED_GOTOS 1
904 #  endif
905 #endif
906
907 #define OPA ((prvm_eval_t *)&globals[st->operand[0]])
908 #define OPB ((prvm_eval_t *)&globals[st->operand[1]])
909 #define OPC ((prvm_eval_t *)&globals[st->operand[2]])
910 extern cvar_t prvm_traceqc;
911 extern cvar_t prvm_statementprofiling;
912 extern qbool prvm_runawaycheck;
913
914 #ifdef PROFILING
915 #ifdef CONFIG_MENU
916 /*
917 ====================
918 MVM_ExecuteProgram
919 ====================
920 */
921 void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
922 {
923         mstatement_t    *st, *startst;
924         mfunction_t             *func, *enterfunc;
925         prvm_edict_t    *ed;
926         prvm_eval_t     *ptr;
927         int             jumpcount, cachedpr_trace, exitdepth;
928         int             restorevm_tempstringsbuf_cursize;
929         double  calltime;
930         double tm, starttm;
931         prvm_vec_t tempfloat;
932         // these may become out of date when a builtin is called, and are updated accordingly
933         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
934         unsigned int cached_entityfields = prog->entityfields;
935         unsigned int cached_entityfields_3 = prog->entityfields - 3;
936         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
937         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
938         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
939         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
940         unsigned int cached_max_edicts = prog->max_edicts;
941         // these do not change
942         mstatement_t *cached_statements = prog->statements;
943         qbool cached_allowworldwrites = prog->allowworldwrites;
944         unsigned int cached_flag = prog->flag;
945
946         prvm_vec_t *globals = prog->globals.fp;
947
948         calltime = Sys_DirtyTime();
949
950         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
951         {
952                 if (PRVM_allglobaledict(self))
953                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
954                 prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
955         }
956
957         func = &prog->functions[fnum];
958
959         // after executing this function, delete all tempstrings it created
960         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
961
962         prog->trace = prvm_traceqc.integer;
963
964         // we know we're done when pr_depth drops to this
965         exitdepth = prog->depth;
966
967 // make a stack frame
968         st = &prog->statements[PRVM_EnterFunction(prog, func)];
969         // save the starting statement pointer for profiling
970         // (when the function exits or jumps, the (st - startst) integer value is
971         // added to the function's profile counter)
972         startst = st;
973         starttm = calltime;
974         // instead of counting instructions, we count jumps
975         jumpcount = 0;
976         // add one to the callcount of this function because otherwise engine-called functions aren't counted
977         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
978                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
979
980 chooseexecprogram:
981         cachedpr_trace = prog->trace;
982         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
983         {
984 #define PRVMSLOWINTERPRETER 1
985                 if (prvm_timeprofiling.integer)
986                 {
987 #define PRVMTIMEPROFILING 1
988 #include "prvm_execprogram.h"
989 #undef PRVMTIMEPROFILING
990                 }
991                 else
992                 {
993 #include "prvm_execprogram.h"
994                 }
995 #undef PRVMSLOWINTERPRETER
996         }
997         else
998         {
999                 if (prvm_timeprofiling.integer)
1000                 {
1001 #define PRVMTIMEPROFILING 1
1002 #include "prvm_execprogram.h"
1003 #undef PRVMTIMEPROFILING
1004                 }
1005                 else
1006                 {
1007 #include "prvm_execprogram.h"
1008                 }
1009         }
1010
1011 cleanup:
1012         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1013                 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);
1014         // delete tempstrings created by this function
1015         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1016
1017         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1018         func->totaltime += tm;
1019
1020         if (prog == SVVM_prog)
1021                 SV_FlushBroadcastMessages();
1022 }
1023 #endif
1024
1025 /*
1026 ====================
1027 CLVM_ExecuteProgram
1028 ====================
1029 */
1030 void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1031 {
1032         mstatement_t    *st, *startst;
1033         mfunction_t             *func, *enterfunc;
1034         prvm_edict_t    *ed;
1035         prvm_eval_t     *ptr;
1036         int             jumpcount, cachedpr_trace, exitdepth;
1037         int             restorevm_tempstringsbuf_cursize;
1038         double  calltime;
1039         double tm, starttm;
1040         prvm_vec_t tempfloat;
1041         // these may become out of date when a builtin is called, and are updated accordingly
1042         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1043         unsigned int cached_entityfields = prog->entityfields;
1044         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1045         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1046         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1047         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1048         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1049         unsigned int cached_max_edicts = prog->max_edicts;
1050         // these do not change
1051         mstatement_t *cached_statements = prog->statements;
1052         qbool cached_allowworldwrites = prog->allowworldwrites;
1053         unsigned int cached_flag = prog->flag;
1054
1055         prvm_vec_t *globals = prog->globals.fp;
1056
1057         calltime = Sys_DirtyTime();
1058
1059         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1060         {
1061                 if (PRVM_allglobaledict(self))
1062                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1063                 prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
1064         }
1065
1066         func = &prog->functions[fnum];
1067
1068         // after executing this function, delete all tempstrings it created
1069         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1070
1071         prog->trace = prvm_traceqc.integer;
1072
1073         // we know we're done when pr_depth drops to this
1074         exitdepth = prog->depth;
1075
1076 // make a stack frame
1077         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1078         // save the starting statement pointer for profiling
1079         // (when the function exits or jumps, the (st - startst) integer value is
1080         // added to the function's profile counter)
1081         startst = st;
1082         starttm = calltime;
1083         // instead of counting instructions, we count jumps
1084         jumpcount = 0;
1085         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1086         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1087                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1088
1089 chooseexecprogram:
1090         cachedpr_trace = prog->trace;
1091         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1092         {
1093 #define PRVMSLOWINTERPRETER 1
1094                 if (prvm_timeprofiling.integer)
1095                 {
1096 #define PRVMTIMEPROFILING 1
1097 #include "prvm_execprogram.h"
1098 #undef PRVMTIMEPROFILING
1099                 }
1100                 else
1101                 {
1102 #include "prvm_execprogram.h"
1103                 }
1104 #undef PRVMSLOWINTERPRETER
1105         }
1106         else
1107         {
1108                 if (prvm_timeprofiling.integer)
1109                 {
1110 #define PRVMTIMEPROFILING 1
1111 #include "prvm_execprogram.h"
1112 #undef PRVMTIMEPROFILING
1113                 }
1114                 else
1115                 {
1116 #include "prvm_execprogram.h"
1117                 }
1118         }
1119
1120 cleanup:
1121         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1122                 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);
1123         // delete tempstrings created by this function
1124         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1125
1126         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1127         func->totaltime += tm;
1128
1129         if (prog == SVVM_prog)
1130                 SV_FlushBroadcastMessages();
1131 }
1132 #endif
1133
1134 /*
1135 ====================
1136 SVVM_ExecuteProgram
1137 ====================
1138 */
1139 #ifdef PROFILING
1140 void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1141 #else
1142 void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1143 #endif
1144 {
1145         mstatement_t    *st, *startst;
1146         mfunction_t             *func, *enterfunc;
1147         prvm_edict_t    *ed;
1148         prvm_eval_t     *ptr;
1149         int             jumpcount, cachedpr_trace, exitdepth;
1150         int             restorevm_tempstringsbuf_cursize;
1151         double  calltime;
1152         double tm, starttm;
1153         prvm_vec_t tempfloat;
1154         // these may become out of date when a builtin is called, and are updated accordingly
1155         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1156         unsigned int cached_entityfields = prog->entityfields;
1157         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1158         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1159         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1160         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1161         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1162         unsigned int cached_max_edicts = prog->max_edicts;
1163         // these do not change
1164         mstatement_t *cached_statements = prog->statements;
1165         qbool cached_allowworldwrites = prog->allowworldwrites;
1166         unsigned int cached_flag = prog->flag;
1167
1168         prvm_vec_t *globals = prog->globals.fp;
1169
1170         calltime = Sys_DirtyTime();
1171
1172         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1173         {
1174                 if (PRVM_allglobaledict(self))
1175                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1176                 prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
1177         }
1178
1179         func = &prog->functions[fnum];
1180
1181         // after executing this function, delete all tempstrings it created
1182         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1183
1184         prog->trace = prvm_traceqc.integer;
1185
1186         // we know we're done when pr_depth drops to this
1187         exitdepth = prog->depth;
1188
1189 // make a stack frame
1190         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1191         // save the starting statement pointer for profiling
1192         // (when the function exits or jumps, the (st - startst) integer value is
1193         // added to the function's profile counter)
1194         startst = st;
1195         starttm = calltime;
1196         // instead of counting instructions, we count jumps
1197         jumpcount = 0;
1198         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1199         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1200                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1201
1202 chooseexecprogram:
1203         cachedpr_trace = prog->trace;
1204         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1205         {
1206 #define PRVMSLOWINTERPRETER 1
1207                 if (prvm_timeprofiling.integer)
1208                 {
1209 #define PRVMTIMEPROFILING 1
1210 #include "prvm_execprogram.h"
1211 #undef PRVMTIMEPROFILING
1212                 }
1213                 else
1214                 {
1215 #include "prvm_execprogram.h"
1216                 }
1217 #undef PRVMSLOWINTERPRETER
1218         }
1219         else
1220         {
1221                 if (prvm_timeprofiling.integer)
1222                 {
1223 #define PRVMTIMEPROFILING 1
1224 #include "prvm_execprogram.h"
1225 #undef PRVMTIMEPROFILING
1226                 }
1227                 else
1228                 {
1229 #include "prvm_execprogram.h"
1230                 }
1231         }
1232
1233 cleanup:
1234         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1235                 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);
1236         // delete tempstrings created by this function
1237         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1238
1239         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1240         func->totaltime += tm;
1241
1242         if (prog == SVVM_prog)
1243                 SV_FlushBroadcastMessages();
1244 }