]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_exec.c
com: replace BSD strlcpy and strlcat
[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         char *p;
438
439         if(prog)
440         {
441                 p = buf + max(0, dpsnprintf(buf, bufsize, "(%s) ", prog->name));
442         }
443         else
444         {
445                 dp_strlcpy(buf, "<NO PROG>", bufsize);
446                 return;
447         }
448
449         prog->stack[prog->depth].s = prog->xstatement;
450         prog->stack[prog->depth].f = prog->xfunction;
451         for (i = prog->depth;i > 0;i--)
452         {
453                 f = prog->stack[i].f;
454                 p = dp_stpecpy(
455                         p,
456                         buf + bufsize,
457                         f
458                                 ? 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)
459                                 : "<NULL> "
460                         );
461                 if (p == buf + bufsize)
462                         break;
463         }
464 }
465
466
467 static void PRVM_CallProfile (prvm_prog_t *prog)
468 {
469         mfunction_t *f, *best;
470         int i;
471         double max;
472         double sum;
473         double newprofiletime;
474
475         Con_Printf( "%s Call Profile:\n", prog->name );
476
477         sum = 0;
478         do
479         {
480                 max = 0;
481                 best = NULL;
482                 for (i=0 ; i<prog->numfunctions ; i++)
483                 {
484                         f = &prog->functions[i];
485                         if (max < f->totaltime)
486                         {
487                                 max = f->totaltime;
488                                 best = f;
489                         }
490                 }
491                 if (best)
492                 {
493                         sum += best->totaltime;
494                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name));
495                         best->totaltime = 0;
496                 }
497         } while (best);
498
499         newprofiletime = Sys_DirtyTime();
500         Con_Printf("Total time since last profile reset: %9.4f\n", newprofiletime - prog->profiletime);
501         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
502
503         prog->profiletime = newprofiletime;
504 }
505
506 void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby)
507 {
508         mfunction_t *f, *best;
509         int i, num;
510         double max;
511
512         if(!prvm_timeprofiling.integer)
513                 mintime *= 10000000; // count each statement as about 0.1µs
514
515         if(prvm_timeprofiling.integer)
516                 Con_Printf( "%s Profile:\n[CallCount]      [Time] [BuiltinTm] [Statement] [BuiltinCt] [TimeTotal] [StmtTotal] [BltnTotal] [self]\n", prog->name );
517                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
518         else
519                 Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name );
520                 //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
521
522         num = 0;
523         do
524         {
525                 max = 0;
526                 best = NULL;
527                 for (i=0 ; i<prog->numfunctions ; i++)
528                 {
529                         f = &prog->functions[i];
530                         if(prvm_timeprofiling.integer)
531                         {
532                                 if(sortby)
533                                 {
534                                         if(f->first_statement < 0)
535                                         {
536                                                 if (max < f->tprofile)
537                                                 {
538                                                         max = f->tprofile;
539                                                         best = f;
540                                                 }
541                                         }
542                                         else
543                                         {
544                                                 if (max < f->tprofile_total)
545                                                 {
546                                                         max = f->tprofile_total;
547                                                         best = f;
548                                                 }
549                                         }
550                                 }
551                                 else
552                                 {
553                                         if (max < f->tprofile + f->tbprofile)
554                                         {
555                                                 max = f->tprofile + f->tbprofile;
556                                                 best = f;
557                                         }
558                                 }
559                         }
560                         else
561                         {
562                                 if(sortby)
563                                 {
564                                         if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
565                                         {
566                                                 max = f->profile_total + f->builtinsprofile_total + f->callcount;
567                                                 best = f;
568                                         }
569                                 }
570                                 else
571                                 {
572                                         if (max < f->profile + f->builtinsprofile + f->callcount)
573                                         {
574                                                 max = f->profile + f->builtinsprofile + f->callcount;
575                                                 best = f;
576                                         }
577                                 }
578                         }
579                 }
580                 if (best)
581                 {
582                         if (num < maxfunctions && max > mintime)
583                         {
584                                 if(prvm_timeprofiling.integer)
585                                 {
586                                         if (best->first_statement < 0)
587                                                 Con_Printf("%11.0f %11.6f ------------- builtin ------------- %11.6f ----------- builtin ----------- %s\n", best->callcount, best->tprofile, best->tprofile, PRVM_GetString(prog, best->s_name));
588                                         //                 %11.6f 12345678901 12345678901 12345678901 %11.6f 12345678901 12345678901 123.45%
589                                         else
590                                                 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));
591                                 }
592                                 else
593                                 {
594                                         if (best->first_statement < 0)
595                                                 Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(prog, best->s_name));
596                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
597                                         else
598                                                 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));
599                                 }
600                         }
601                         num++;
602                         best->profile = 0;
603                         best->tprofile = 0;
604                         best->tbprofile = 0;
605                         best->builtinsprofile = 0;
606                         best->profile_total = 0;
607                         best->tprofile_total = 0;
608                         best->builtinsprofile_total = 0;
609                         best->callcount = 0;
610                 }
611         } while (best);
612 }
613
614 /*
615 ============
616 PRVM_CallProfile_f
617
618 ============
619 */
620 void PRVM_CallProfile_f(cmd_state_t *cmd)
621 {
622         prvm_prog_t *prog;
623         if (Cmd_Argc(cmd) != 2)
624         {
625                 Con_Print("prvm_callprofile <program name>\n");
626                 return;
627         }
628
629         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
630                 return;
631
632         PRVM_CallProfile(prog);
633 }
634
635 /*
636 ============
637 PRVM_Profile_f
638
639 ============
640 */
641 void PRVM_Profile_f(cmd_state_t *cmd)
642 {
643         prvm_prog_t *prog;
644         int howmany;
645
646         if (prvm_coverage.integer & 1)
647         {
648                 Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
649                 return;
650         }
651
652         howmany = 1<<30;
653         if (Cmd_Argc(cmd) == 3)
654                 howmany = atoi(Cmd_Argv(cmd, 2));
655         else if (Cmd_Argc(cmd) != 2)
656         {
657                 Con_Print("prvm_profile <program name>\n");
658                 return;
659         }
660
661         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
662                 return;
663
664         PRVM_Profile(prog, howmany, 0, 0);
665 }
666
667 void PRVM_ChildProfile_f(cmd_state_t *cmd)
668 {
669         prvm_prog_t *prog;
670         int howmany;
671
672         if (prvm_coverage.integer & 1)
673         {
674                 Con_Printf("Collecting function coverage, cannot profile - sorry!\n");
675                 return;
676         }
677
678         howmany = 1<<30;
679         if (Cmd_Argc(cmd) == 3)
680                 howmany = atoi(Cmd_Argv(cmd, 2));
681         else if (Cmd_Argc(cmd) != 2)
682         {
683                 Con_Print("prvm_childprofile <program name>\n");
684                 return;
685         }
686
687         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
688                 return;
689
690         PRVM_Profile(prog, howmany, 0, 1);
691 }
692
693 void PRVM_PrintState(prvm_prog_t *prog, int stack_index)
694 {
695         int i;
696         mfunction_t *func = prog->xfunction;
697         int st = prog->xstatement;
698         if (stack_index > 0 && stack_index <= prog->depth)
699         {
700                 func = prog->stack[prog->depth - stack_index].f;
701                 st = prog->stack[prog->depth - stack_index].s;
702         }
703         if (prog->statestring)
704         {
705                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
706         }
707         if (func)
708         {
709                 for (i = -7; i <= 0;i++)
710                         if (st + i >= func->first_statement)
711                                 PRVM_PrintStatement(prog, prog->statements + st + i);
712         }
713         PRVM_StackTrace(prog);
714 }
715
716 extern cvar_t prvm_errordump;
717 void PRVM_Crash(prvm_prog_t *prog)
718 {
719         char vabuf[1024];
720         int outfd = sys.outfd;
721
722         cl.csqc_loaded = false;
723
724         if (prog == NULL)
725                 return;
726         if (!prog->loaded)
727                 return;
728
729         // set output to stderr
730         sys.outfd = fileno(stderr);
731
732         PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
733
734         if( prog->depth > 0 )
735         {
736                 Con_Printf("QuakeC crash report for %s:\n", prog->name);
737                 PRVM_PrintState(prog, 0);
738         }
739
740         if(prvm_errordump.integer)
741         {
742                 // make a savegame
743                 SV_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
744         }
745
746         // dump the stack so host_error can shutdown functions
747         prog->depth = 0;
748         prog->localstack_used = 0;
749
750         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
751         prog->tempstringsbuf.cursize = 0;
752
753         // reset the prog pointer
754         prog = NULL;
755
756         // restore configured outfd
757         sys.outfd = outfd;
758 }
759
760 /*
761 ============================================================================
762 PRVM_ExecuteProgram
763
764 The interpretation main loop
765 ============================================================================
766 */
767
768 /*
769 ====================
770 PRVM_EnterFunction
771
772 Returns the new program statement counter
773 ====================
774 */
775 static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
776 {
777         int             i, j, c, o;
778
779         if (!f)
780                 prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name);
781
782         prog->stack[prog->depth].s = prog->xstatement;
783         prog->stack[prog->depth].f = prog->xfunction;
784         prog->stack[prog->depth].profile_acc = -f->profile;
785         prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile;
786         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
787         prog->depth++;
788         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
789                 prog->error_cmd("stack overflow");
790
791 // save off any locals that the new function steps on
792         c = f->locals;
793         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
794                 prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
795
796         for (i=0 ; i < c ; i++)
797                 prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i];
798         prog->localstack_used += c;
799
800 // copy parameters
801         o = f->parm_start;
802         for (i=0 ; i<f->numparms ; i++)
803         {
804                 for (j=0 ; j<f->parm_size[i] ; j++)
805                 {
806                         prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j];
807                         o++;
808                 }
809         }
810
811         ++f->recursion;
812         prog->xfunction = f;
813         return f->first_statement - 1;  // offset the s++
814 }
815
816 /*
817 ====================
818 PRVM_LeaveFunction
819 ====================
820 */
821 static int PRVM_LeaveFunction (prvm_prog_t *prog)
822 {
823         int             i, c;
824         mfunction_t *f;
825
826         if (prog->depth <= 0)
827                 prog->error_cmd("prog stack underflow in %s", prog->name);
828
829         if (!prog->xfunction)
830                 prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name);
831 // restore locals from the stack
832         c = prog->xfunction->locals;
833         prog->localstack_used -= c;
834         if (prog->localstack_used < 0)
835                 prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
836
837         for (i=0 ; i < c ; i++)
838                 prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
839
840 // up stack
841         prog->depth--;
842         f = prog->xfunction;
843         --f->recursion;
844         prog->xfunction = prog->stack[prog->depth].f;
845         prog->stack[prog->depth].profile_acc += f->profile;
846         prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile;
847         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
848         if(prog->depth > 0)
849         {
850                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
851                 prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc;
852                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
853         }
854         if(!f->recursion)
855         {
856                 // if f is already on the call stack...
857                 // we cannot add this profile data to it now
858                 // or we would add it more than once
859                 // so, let's only add to the function's profile if it is the outermost call
860                 f->profile_total += prog->stack[prog->depth].profile_acc;
861                 f->tprofile_total += prog->stack[prog->depth].tprofile_acc;
862                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
863         }
864         
865         return prog->stack[prog->depth].s;
866 }
867
868 void PRVM_Init_Exec(prvm_prog_t *prog)
869 {
870         // dump the stack
871         prog->depth = 0;
872         prog->localstack_used = 0;
873         // reset the string table
874         // nothing here yet
875 }
876
877 /*
878 ==================
879 Coverage
880 ==================
881 */
882 // Note: in these two calls, prog->xfunction is assumed to be sane.
883 static const char *PRVM_WhereAmI(char *buf, size_t bufsize, prvm_prog_t *prog, mfunction_t *func, int statement)
884 {
885         if (prog->statement_linenums)
886         {
887                 if (prog->statement_columnnums)
888                         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);
889                 else
890                         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);
891         }
892         else
893                 return va(buf, bufsize, "%s(%s, %i)", PRVM_GetString(prog, func->s_file), PRVM_GetString(prog, func->s_name), statement - func->first_statement);
894 }
895 static void PRVM_FunctionCoverageEvent(prvm_prog_t *prog, mfunction_t *func)
896 {
897         ++prog->functions_covered;
898         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);
899 }
900 void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
901 {
902         char vabuf[128];
903         ++prog->explicit_covered;
904         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);
905 }
906 static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
907 {
908         char vabuf[128];
909         ++prog->statements_covered;
910         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);
911 }
912
913 #if defined (__GNUC__) || (__clang__) || (__TINYC__)
914 #  ifndef CONFIG_PEDANTIC
915 #  define HAVE_COMPUTED_GOTOS 1
916 #  endif
917 #endif
918
919 #define OPA ((prvm_eval_t *)&globals[st->operand[0]])
920 #define OPB ((prvm_eval_t *)&globals[st->operand[1]])
921 #define OPC ((prvm_eval_t *)&globals[st->operand[2]])
922 extern cvar_t prvm_traceqc;
923 extern cvar_t prvm_statementprofiling;
924 extern qbool prvm_runawaycheck;
925
926 #ifdef PROFILING
927 #ifdef CONFIG_MENU
928 /*
929 ====================
930 MVM_ExecuteProgram
931 ====================
932 */
933 void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
934 {
935         mstatement_t    *st, *startst;
936         mfunction_t             *func, *enterfunc;
937         prvm_edict_t    *ed;
938         prvm_eval_t     *ptr;
939         int             jumpcount, cachedpr_trace, exitdepth;
940         int             restorevm_tempstringsbuf_cursize;
941         double  calltime;
942         double tm, starttm;
943         prvm_vec_t tempfloat;
944         // these may become out of date when a builtin is called, and are updated accordingly
945         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
946         unsigned int cached_entityfields = prog->entityfields;
947         unsigned int cached_entityfields_3 = prog->entityfields - 3;
948         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
949         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
950         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
951         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
952         unsigned int cached_max_edicts = prog->max_edicts;
953         // these do not change
954         mstatement_t *cached_statements = prog->statements;
955         qbool cached_allowworldwrites = prog->allowworldwrites;
956         unsigned int cached_flag = prog->flag;
957
958         prvm_vec_t *globals = prog->globals.fp;
959
960         calltime = Sys_DirtyTime();
961
962         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
963         {
964                 if (PRVM_allglobaledict(self))
965                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
966                 prog->error_cmd("MVM_ExecuteProgram: %s", errormessage);
967         }
968
969         func = &prog->functions[fnum];
970
971         // after executing this function, delete all tempstrings it created
972         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
973
974         prog->trace = prvm_traceqc.integer;
975
976         // we know we're done when pr_depth drops to this
977         exitdepth = prog->depth;
978
979 // make a stack frame
980         st = &prog->statements[PRVM_EnterFunction(prog, func)];
981         // save the starting statement pointer for profiling
982         // (when the function exits or jumps, the (st - startst) integer value is
983         // added to the function's profile counter)
984         startst = st;
985         starttm = calltime;
986         // instead of counting instructions, we count jumps
987         jumpcount = 0;
988         // add one to the callcount of this function because otherwise engine-called functions aren't counted
989         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
990                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
991
992 chooseexecprogram:
993         cachedpr_trace = prog->trace;
994         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
995         {
996 #define PRVMSLOWINTERPRETER 1
997                 if (prvm_timeprofiling.integer)
998                 {
999 #define PRVMTIMEPROFILING 1
1000 #include "prvm_execprogram.h"
1001 #undef PRVMTIMEPROFILING
1002                 }
1003                 else
1004                 {
1005 #include "prvm_execprogram.h"
1006                 }
1007 #undef PRVMSLOWINTERPRETER
1008         }
1009         else
1010         {
1011                 if (prvm_timeprofiling.integer)
1012                 {
1013 #define PRVMTIMEPROFILING 1
1014 #include "prvm_execprogram.h"
1015 #undef PRVMTIMEPROFILING
1016                 }
1017                 else
1018                 {
1019 #include "prvm_execprogram.h"
1020                 }
1021         }
1022
1023 cleanup:
1024         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1025                 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);
1026         // delete tempstrings created by this function
1027         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1028
1029         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1030         func->totaltime += tm;
1031
1032         if (prog == SVVM_prog)
1033                 SV_FlushBroadcastMessages();
1034 }
1035 #endif
1036
1037 /*
1038 ====================
1039 CLVM_ExecuteProgram
1040 ====================
1041 */
1042 void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1043 {
1044         mstatement_t    *st, *startst;
1045         mfunction_t             *func, *enterfunc;
1046         prvm_edict_t    *ed;
1047         prvm_eval_t     *ptr;
1048         int             jumpcount, cachedpr_trace, exitdepth;
1049         int             restorevm_tempstringsbuf_cursize;
1050         double  calltime;
1051         double tm, starttm;
1052         prvm_vec_t tempfloat;
1053         // these may become out of date when a builtin is called, and are updated accordingly
1054         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1055         unsigned int cached_entityfields = prog->entityfields;
1056         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1057         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1058         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1059         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1060         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1061         unsigned int cached_max_edicts = prog->max_edicts;
1062         // these do not change
1063         mstatement_t *cached_statements = prog->statements;
1064         qbool cached_allowworldwrites = prog->allowworldwrites;
1065         unsigned int cached_flag = prog->flag;
1066
1067         prvm_vec_t *globals = prog->globals.fp;
1068
1069         calltime = Sys_DirtyTime();
1070
1071         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1072         {
1073                 if (PRVM_allglobaledict(self))
1074                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1075                 prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage);
1076         }
1077
1078         func = &prog->functions[fnum];
1079
1080         // after executing this function, delete all tempstrings it created
1081         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1082
1083         prog->trace = prvm_traceqc.integer;
1084
1085         // we know we're done when pr_depth drops to this
1086         exitdepth = prog->depth;
1087
1088 // make a stack frame
1089         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1090         // save the starting statement pointer for profiling
1091         // (when the function exits or jumps, the (st - startst) integer value is
1092         // added to the function's profile counter)
1093         startst = st;
1094         starttm = calltime;
1095         // instead of counting instructions, we count jumps
1096         jumpcount = 0;
1097         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1098         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1099                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1100
1101 chooseexecprogram:
1102         cachedpr_trace = prog->trace;
1103         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1104         {
1105 #define PRVMSLOWINTERPRETER 1
1106                 if (prvm_timeprofiling.integer)
1107                 {
1108 #define PRVMTIMEPROFILING 1
1109 #include "prvm_execprogram.h"
1110 #undef PRVMTIMEPROFILING
1111                 }
1112                 else
1113                 {
1114 #include "prvm_execprogram.h"
1115                 }
1116 #undef PRVMSLOWINTERPRETER
1117         }
1118         else
1119         {
1120                 if (prvm_timeprofiling.integer)
1121                 {
1122 #define PRVMTIMEPROFILING 1
1123 #include "prvm_execprogram.h"
1124 #undef PRVMTIMEPROFILING
1125                 }
1126                 else
1127                 {
1128 #include "prvm_execprogram.h"
1129                 }
1130         }
1131
1132 cleanup:
1133         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1134                 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);
1135         // delete tempstrings created by this function
1136         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1137
1138         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1139         func->totaltime += tm;
1140
1141         if (prog == SVVM_prog)
1142                 SV_FlushBroadcastMessages();
1143 }
1144 #endif
1145
1146 /*
1147 ====================
1148 SVVM_ExecuteProgram
1149 ====================
1150 */
1151 #ifdef PROFILING
1152 void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1153 #else
1154 void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
1155 #endif
1156 {
1157         mstatement_t    *st, *startst;
1158         mfunction_t             *func, *enterfunc;
1159         prvm_edict_t    *ed;
1160         prvm_eval_t     *ptr;
1161         int             jumpcount, cachedpr_trace, exitdepth;
1162         int             restorevm_tempstringsbuf_cursize;
1163         double  calltime;
1164         double tm, starttm;
1165         prvm_vec_t tempfloat;
1166         // these may become out of date when a builtin is called, and are updated accordingly
1167         prvm_vec_t *cached_edictsfields = prog->edictsfields.fp;
1168         unsigned int cached_entityfields = prog->entityfields;
1169         unsigned int cached_entityfields_3 = prog->entityfields - 3;
1170         unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
1171         unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
1172         unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
1173         unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
1174         unsigned int cached_max_edicts = prog->max_edicts;
1175         // these do not change
1176         mstatement_t *cached_statements = prog->statements;
1177         qbool cached_allowworldwrites = prog->allowworldwrites;
1178         unsigned int cached_flag = prog->flag;
1179
1180         prvm_vec_t *globals = prog->globals.fp;
1181
1182         calltime = Sys_DirtyTime();
1183
1184         if (!fnum || fnum >= (unsigned int)prog->numfunctions)
1185         {
1186                 if (PRVM_allglobaledict(self))
1187                         PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
1188                 prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage);
1189         }
1190
1191         func = &prog->functions[fnum];
1192
1193         // after executing this function, delete all tempstrings it created
1194         restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1195
1196         prog->trace = prvm_traceqc.integer;
1197
1198         // we know we're done when pr_depth drops to this
1199         exitdepth = prog->depth;
1200
1201 // make a stack frame
1202         st = &prog->statements[PRVM_EnterFunction(prog, func)];
1203         // save the starting statement pointer for profiling
1204         // (when the function exits or jumps, the (st - startst) integer value is
1205         // added to the function's profile counter)
1206         startst = st;
1207         starttm = calltime;
1208         // instead of counting instructions, we count jumps
1209         jumpcount = 0;
1210         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1211         if (prog->xfunction->callcount++ == 0 && (prvm_coverage.integer & 1))
1212                 PRVM_FunctionCoverageEvent(prog, prog->xfunction);
1213
1214 chooseexecprogram:
1215         cachedpr_trace = prog->trace;
1216         if (prog->trace || prog->watch_global_type != ev_void || prog->watch_field_type != ev_void || prog->break_statement >= 0)
1217         {
1218 #define PRVMSLOWINTERPRETER 1
1219                 if (prvm_timeprofiling.integer)
1220                 {
1221 #define PRVMTIMEPROFILING 1
1222 #include "prvm_execprogram.h"
1223 #undef PRVMTIMEPROFILING
1224                 }
1225                 else
1226                 {
1227 #include "prvm_execprogram.h"
1228                 }
1229 #undef PRVMSLOWINTERPRETER
1230         }
1231         else
1232         {
1233                 if (prvm_timeprofiling.integer)
1234                 {
1235 #define PRVMTIMEPROFILING 1
1236 #include "prvm_execprogram.h"
1237 #undef PRVMTIMEPROFILING
1238                 }
1239                 else
1240                 {
1241 #include "prvm_execprogram.h"
1242                 }
1243         }
1244
1245 cleanup:
1246         if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1247                 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);
1248         // delete tempstrings created by this function
1249         prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1250
1251         tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
1252         func->totaltime += tm;
1253
1254         if (prog == SVVM_prog)
1255                 SV_FlushBroadcastMessages();
1256 }