]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_exec.c
Merge commit 'origin/master' into dp1
[divverent/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 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 "OP_MULSTORE_F",
112 "OP_MULSTORE_V",
113 "OP_MULSTOREP_F",
114 "OP_MULSTOREP_V",
115
116 "OP_DIVSTORE_F",        //70
117 "OP_DIVSTOREP_F",
118
119 "OP_ADDSTORE_F",
120 "OP_ADDSTORE_V",
121 "OP_ADDSTOREP_F",
122 "OP_ADDSTOREP_V",
123
124 "OP_SUBSTORE_F",
125 "OP_SUBSTORE_V",
126 "OP_SUBSTOREP_F",
127 "OP_SUBSTOREP_V",
128
129 "OP_FETCH_GBL_F",       //80
130 "OP_FETCH_GBL_V",
131 "OP_FETCH_GBL_S",
132 "OP_FETCH_GBL_E",
133 "OP_FETCH_GBL_FNC",
134
135 "OP_CSTATE",
136 "OP_CWSTATE",
137
138 "OP_THINKTIME",
139
140 "OP_BITSET",
141 "OP_BITSETP",
142 "OP_BITCLR",            //90
143 "OP_BITCLRP",
144
145 "OP_RAND0",
146 "OP_RAND1",
147 "OP_RAND2",
148 "OP_RANDV0",
149 "OP_RANDV1",
150 "OP_RANDV2",
151
152 "OP_SWITCH_F",
153 "OP_SWITCH_V",
154 "OP_SWITCH_S",  //100
155 "OP_SWITCH_E",
156 "OP_SWITCH_FNC",
157
158 "OP_CASE",
159 "OP_CASERANGE",
160
161
162
163
164
165         //the rest are added
166         //mostly they are various different ways of adding two vars with conversions.
167
168 "OP_CALL1H",
169 "OP_CALL2H",
170 "OP_CALL3H",
171 "OP_CALL4H",
172 "OP_CALL5H",
173 "OP_CALL6H",            //110
174 "OP_CALL7H",
175 "OP_CALL8H",
176
177
178 "OP_STORE_I",
179 "OP_STORE_IF",
180 "OP_STORE_FI",
181
182 "OP_ADD_I",
183 "OP_ADD_FI",
184 "OP_ADD_IF",            //110
185
186 "OP_SUB_I",
187 "OP_SUB_FI",
188 "OP_SUB_IF",
189
190 "OP_CONV_ITOF",
191 "OP_CONV_FTOI",
192 "OP_CP_ITOF",
193 "OP_CP_FTOI",
194 "OP_LOAD_I",
195 "OP_STOREP_I",
196 "OP_STOREP_IF", //120
197 "OP_STOREP_FI",
198
199 "OP_BITAND_I",
200 "OP_BITOR_I",
201
202 "OP_MUL_I",
203 "OP_DIV_I",
204 "OP_EQ_I",
205 "OP_NE_I",
206
207 "OP_IFNOTS",
208 "OP_IFS",
209
210 "OP_NOT_I",             //130
211
212 "OP_DIV_VF",
213
214 "OP_XOR_I",
215 "OP_RSHIFT_I",
216 "OP_LSHIFT_I",
217
218 "OP_GLOBALADDRESS",
219 "OP_POINTER_ADD",       //32 bit pointers
220
221 "OP_LOADA_F",
222 "OP_LOADA_V",
223 "OP_LOADA_S",
224 "OP_LOADA_ENT", //140
225 "OP_LOADA_FLD",
226 "OP_LOADA_FNC",
227 "OP_LOADA_I",
228
229 "OP_STORE_P",
230 "OP_LOAD_P",
231
232 "OP_LOADP_F",
233 "OP_LOADP_V",
234 "OP_LOADP_S",
235 "OP_LOADP_ENT",
236 "OP_LOADP_FLD", //150
237 "OP_LOADP_FNC",
238 "OP_LOADP_I",
239
240 "OP_LE_I",
241 "OP_GE_I",
242 "OP_LT_I",
243 "OP_GT_I",
244
245 "OP_LE_IF",
246 "OP_GE_IF",
247 "OP_LT_IF",
248 "OP_GT_IF",             //160
249
250 "OP_LE_FI",
251 "OP_GE_FI",
252 "OP_LT_FI",
253 "OP_GT_FI",
254
255 "OP_EQ_IF",
256 "OP_EQ_FI",
257
258         //-------------------------------------
259         //string manipulation.
260 "OP_ADD_SF",    //(char*)c = (char*)a + (float)b
261 "OP_SUB_S",     //(float)c = (char*)a - (char*)b
262 "OP_STOREP_C",//(float)c = *(char*)b = (float)a
263 "OP_LOADP_C",   //(float)c = *(char*)                                   //170
264         //-------------------------------------
265
266
267 "OP_MUL_IF",
268 "OP_MUL_FI",
269 "OP_MUL_VI",
270 "OP_MUL_IV",
271 "OP_DIV_IF",
272 "OP_DIV_FI",
273 "OP_BITAND_IF",
274 "OP_BITOR_IF",
275 "OP_BITAND_FI",
276 "OP_BITOR_FI",          //180
277 "OP_AND_I",
278 "OP_OR_I",
279 "OP_AND_IF",
280 "OP_OR_IF",
281 "OP_AND_FI",
282 "OP_OR_FI",
283 "OP_NE_IF",
284 "OP_NE_FI",
285
286 //erm... FTEQCC doesn't make use of these... These are for DP.
287 "OP_GSTOREP_I",
288 "OP_GSTOREP_F",         //190
289 "OP_GSTOREP_ENT",
290 "OP_GSTOREP_FLD",               // integers
291 "OP_GSTOREP_S",
292 "OP_GSTOREP_FNC",               // pointers
293 "OP_GSTOREP_V",
294 "OP_GADDRESS",
295 "OP_GLOAD_I",
296 "OP_GLOAD_F",
297 "OP_GLOAD_FLD",
298 "OP_GLOAD_ENT",         //200
299 "OP_GLOAD_S",
300 "OP_GLOAD_FNC",
301 "OP_BOUNDCHECK",
302
303 //back to ones that we do use.
304 "OP_STOREP_P",
305 "OP_PUSH",      //push 4octets onto the local-stack (which is ALWAYS poped on function return). Returns a pointer.
306 "OP_POP",               //pop those ones that were pushed (don't over do it). Needs assembler.
307
308 "^5OP_IF_I",
309 "^5OP_IFNOT_I",
310
311 "OP_NUMOPS"
312 };
313
314 char *PRVM_GlobalString (int ofs);
315 char *PRVM_GlobalStringNoContents (int ofs);
316
317
318 //=============================================================================
319
320 /*
321 =================
322 PRVM_PrintStatement
323 =================
324 */
325 extern cvar_t prvm_statementprofiling;
326 void PRVM_PrintStatement (dstatement_t *s)
327 {
328         size_t i;
329         int opnum = (int)(s - prog->statements);
330
331         Con_Printf("s%i: ", opnum);
332         if( prog->statement_linenums )
333                 Con_Printf( "%s:%i: ", PRVM_GetString( prog->xfunction->s_file ), prog->statement_linenums[ opnum ] );
334
335         if (prvm_statementprofiling.integer)
336                 Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]);
337
338         if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]))
339         {
340                 Con_Printf("%s ",  prvm_opnames[s->op]);
341                 i = strlen(prvm_opnames[s->op]);
342                 // don't count a preceding color tag when padding the name
343                 if (prvm_opnames[s->op][0] == STRING_COLOR_TAG)
344                         i -= 2;
345                 for ( ; i<10 ; i++)
346                         Con_Print(" ");
347         }
348         if (s->op == OP_IF || s->op == OP_IFNOT)
349                 Con_Printf("%s, s%i",PRVM_GlobalString((unsigned short) s->a),(signed short)s->b + opnum);
350         else if (s->op == OP_GOTO)
351                 Con_Printf("s%i",(signed short)s->a + opnum);
352         else if ( (unsigned)(s->op - OP_STORE_F) < 6)
353         {
354                 Con_Print(PRVM_GlobalString((unsigned short) s->a));
355                 Con_Print(", ");
356                 Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
357         }
358         else if (s->op == OP_ADDRESS || (unsigned)(s->op - OP_LOAD_F) < 6)
359         {
360                 if (s->a)
361                         Con_Print(PRVM_GlobalString((unsigned short) s->a));
362                 if (s->b)
363                 {
364                         Con_Print(", ");
365                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
366                 }
367                 if (s->c)
368                 {
369                         Con_Print(", ");
370                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
371                 }
372         }
373         else
374         {
375                 if (s->a)
376                         Con_Print(PRVM_GlobalString((unsigned short) s->a));
377                 if (s->b)
378                 {
379                         Con_Print(", ");
380                         Con_Print(PRVM_GlobalString((unsigned short) s->b));
381                 }
382                 if (s->c)
383                 {
384                         if(!s->b) // added for debugging --blub
385                                 Con_Print(", (nil)");
386                         Con_Print(", ");
387                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
388                 }
389         }
390         Con_Print("\n");
391 }
392
393 void PRVM_PrintFunctionStatements (const char *name)
394 {
395         int i, firststatement, endstatement;
396         mfunction_t *func;
397         func = PRVM_ED_FindFunction (name);
398         if (!func)
399         {
400                 Con_Printf("%s progs: no function named %s\n", PRVM_NAME, name);
401                 return;
402         }
403         firststatement = func->first_statement;
404         if (firststatement < 0)
405         {
406                 Con_Printf("%s progs: function %s is builtin #%i\n", PRVM_NAME, name, -firststatement);
407                 return;
408         }
409
410         // find the end statement
411         endstatement = prog->progs->numstatements;
412         for (i = 0;i < prog->progs->numfunctions;i++)
413                 if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement)
414                         endstatement = prog->functions[i].first_statement;
415
416         // now print the range of statements
417         Con_Printf("%s progs: disassembly of function %s (statements %i-%i):\n", PRVM_NAME, name, firststatement, endstatement);
418         for (i = firststatement;i < endstatement;i++)
419         {
420                 PRVM_PrintStatement(prog->statements + i);
421                 prog->statement_profile[i] = 0;
422         }
423 }
424
425 /*
426 ============
427 PRVM_PrintFunction_f
428
429 ============
430 */
431 void PRVM_PrintFunction_f (void)
432 {
433         if (Cmd_Argc() != 3)
434         {
435                 Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
436                 return;
437         }
438
439         PRVM_Begin;
440         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
441                 return;
442
443         PRVM_PrintFunctionStatements(Cmd_Argv(2));
444
445         PRVM_End;
446 }
447
448 /*
449 ============
450 PRVM_StackTrace
451 ============
452 */
453 void PRVM_StackTrace (void)
454 {
455         mfunction_t     *f;
456         int                     i;
457
458         prog->stack[prog->depth].s = prog->xstatement;
459         prog->stack[prog->depth].f = prog->xfunction;
460         for (i = prog->depth;i > 0;i--)
461         {
462                 f = prog->stack[i].f;
463
464                 if (!f)
465                         Con_Print("<NULL FUNCTION>\n");
466                 else
467                         Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement);
468         }
469 }
470
471 void PRVM_ShortStackTrace(char *buf, size_t bufsize)
472 {
473         mfunction_t     *f;
474         int                     i;
475
476         if(prog)
477         {
478                 dpsnprintf(buf, bufsize, "(%s) ", prog->name);
479         }
480         else
481         {
482                 strlcpy(buf, "<NO PROG>", bufsize);
483                 return;
484         }
485
486         prog->stack[prog->depth].s = prog->xstatement;
487         prog->stack[prog->depth].f = prog->xfunction;
488         for (i = prog->depth;i > 0;i--)
489         {
490                 f = prog->stack[i].f;
491
492                 if(strlcat(buf,
493                         f
494                                 ? va("%s:%s(%i) ", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement)
495                                 : "<NULL> ",
496                         bufsize
497                 ) >= bufsize)
498                         break;
499         }
500 }
501
502
503 void PRVM_CallProfile (void)
504 {
505         mfunction_t *f, *best;
506         int i;
507         double max;
508         double sum;
509
510         Con_Printf( "%s Call Profile:\n", PRVM_NAME );
511
512         sum = 0;
513         do
514         {
515                 max = 0;
516                 best = NULL;
517                 for (i=0 ; i<prog->progs->numfunctions ; i++)
518                 {
519                         f = &prog->functions[i];
520                         if (max < f->totaltime)
521                         {
522                                 max = f->totaltime;
523                                 best = f;
524                         }
525                 }
526                 if (best)
527                 {
528                         sum += best->totaltime;
529                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(best->s_name));
530                         best->totaltime = 0;
531                 }
532         } while (best);
533
534         Con_Printf("Total time since last profile reset: %9.4f\n", Sys_DoubleTime() - prog->starttime);
535         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
536
537         prog->starttime = Sys_DoubleTime();
538 }
539
540 void PRVM_Profile (int maxfunctions, int mininstructions)
541 {
542         mfunction_t *f, *best;
543         int i, num;
544         double max;
545
546         Con_Printf( "%s Profile:\n[CallCount] [Statements] [BuiltinCost]\n", PRVM_NAME );
547
548         num = 0;
549         do
550         {
551                 max = 0;
552                 best = NULL;
553                 for (i=0 ; i<prog->progs->numfunctions ; i++)
554                 {
555                         f = &prog->functions[i];
556                         if (max < f->profile + f->builtinsprofile + f->callcount)
557                         {
558                                 max = f->profile + f->builtinsprofile + f->callcount;
559                                 best = f;
560                         }
561                 }
562                 if (best)
563                 {
564                         if (num < maxfunctions && max >= mininstructions)
565                         {
566                                 if (best->first_statement < 0)
567                                         Con_Printf("%9.0f ----- builtin ----- %s\n", best->callcount, PRVM_GetString(best->s_name));
568                                 else
569                                         Con_Printf("%9.0f %9.0f %9.0f %s\n", best->callcount, best->profile, best->builtinsprofile, PRVM_GetString(best->s_name));
570                         }
571                         num++;
572                         best->profile = 0;
573                         best->builtinsprofile = 0;
574                         best->callcount = 0;
575                 }
576         } while (best);
577 }
578
579 /*
580 ============
581 PRVM_CallProfile_f
582
583 ============
584 */
585 void PRVM_CallProfile_f (void)
586 {
587         if (Cmd_Argc() != 2)
588         {
589                 Con_Print("prvm_callprofile <program name>\n");
590                 return;
591         }
592
593         PRVM_Begin;
594         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
595                 return;
596
597         PRVM_CallProfile();
598
599         PRVM_End;
600 }
601
602 /*
603 ============
604 PRVM_Profile_f
605
606 ============
607 */
608 void PRVM_Profile_f (void)
609 {
610         int howmany;
611
612         howmany = 1<<30;
613         if (Cmd_Argc() == 3)
614                 howmany = atoi(Cmd_Argv(2));
615         else if (Cmd_Argc() != 2)
616         {
617                 Con_Print("prvm_profile <program name>\n");
618                 return;
619         }
620
621         PRVM_Begin;
622         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
623                 return;
624
625         PRVM_Profile(howmany, 1);
626
627         PRVM_End;
628 }
629
630 void PRVM_CrashAll(void)
631 {
632         int i;
633         prvm_prog_t *oldprog = prog;
634
635         for(i = 0; i < PRVM_MAXPROGS; i++)
636         {
637                 if(!PRVM_ProgLoaded(i))
638                         continue;
639                 PRVM_SetProg(i);
640                 PRVM_Crash();
641         }
642
643         prog = oldprog;
644 }
645
646 void PRVM_PrintState(void)
647 {
648         int i;
649         if(prog->statestring)
650         {
651                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
652         }
653         if (prog->xfunction)
654         {
655                 for (i = -7; i <= 0;i++)
656                         if (prog->xstatement + i >= prog->xfunction->first_statement)
657                                 PRVM_PrintStatement (prog->statements + prog->xstatement + i);
658         }
659         else
660                 Con_Print("null function executing??\n");
661         PRVM_StackTrace ();
662 }
663
664 extern sizebuf_t vm_tempstringsbuf;
665 extern cvar_t prvm_errordump;
666 void Host_Savegame_to (const char *name);
667 void PRVM_Crash(void)
668 {
669         if (prog == NULL)
670                 return;
671
672         prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash
673
674         if( prog->depth > 0 )
675         {
676                 Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME);
677                 PRVM_PrintState();
678         }
679
680         if(prvm_errordump.integer)
681         {
682                 // make a savegame
683                 Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME));
684         }
685
686         // dump the stack so host_error can shutdown functions
687         prog->depth = 0;
688         prog->localstack_used = 0;
689
690         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
691         vm_tempstringsbuf.cursize = 0;
692
693         // reset the prog pointer
694         prog = NULL;
695 }
696
697 /*
698 ============================================================================
699 PRVM_ExecuteProgram
700
701 The interpretation main loop
702 ============================================================================
703 */
704
705 /*
706 ====================
707 PRVM_EnterFunction
708
709 Returns the new program statement counter
710 ====================
711 */
712 int PRVM_EnterFunction (mfunction_t *f)
713 {
714         int             i, j, c, o;
715
716         if (!f)
717                 PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME);
718
719         prog->stack[prog->depth].s = prog->xstatement;
720         prog->stack[prog->depth].f = prog->xfunction;
721         prog->depth++;
722         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
723                 PRVM_ERROR ("stack overflow");
724
725 // save off any locals that the new function steps on
726         c = f->locals;
727         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
728                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME);
729
730         for (i=0 ; i < c ; i++)
731                 prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
732         prog->localstack_used += c;
733
734 // copy parameters
735         o = f->parm_start;
736         for (i=0 ; i<f->numparms ; i++)
737         {
738                 for (j=0 ; j<f->parm_size[i] ; j++)
739                 {
740                         ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j];
741                         o++;
742                 }
743         }
744
745         prog->xfunction = f;
746         return f->first_statement - 1;  // offset the s++
747 }
748
749 /*
750 ====================
751 PRVM_LeaveFunction
752 ====================
753 */
754 int PRVM_LeaveFunction (void)
755 {
756         int             i, c;
757
758         if (prog->depth <= 0)
759                 PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME);
760
761         if (!prog->xfunction)
762                 PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME);
763 // restore locals from the stack
764         c = prog->xfunction->locals;
765         prog->localstack_used -= c;
766         if (prog->localstack_used < 0)
767                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME);
768
769         for (i=0 ; i < c ; i++)
770                 ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
771
772 // up stack
773         prog->depth--;
774         prog->xfunction = prog->stack[prog->depth].f;
775         return prog->stack[prog->depth].s;
776 }
777
778 void PRVM_Init_Exec(void)
779 {
780         // dump the stack
781         prog->depth = 0;
782         prog->localstack_used = 0;
783         // reset the string table
784         // nothing here yet
785 }
786
787 void CStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
788 {
789         // This function should not be called...
790         PRVM_ERROR("CStateOp not implemented.\n");
791 }
792
793 void CWStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
794 {
795         // This function should not be called...
796         PRVM_ERROR("CWStateOp not implemented.\n");
797 }
798
799 void ThinkTimeOp(prvm_prog_t *prog, prvm_edict_t *ent, float varb)
800 {
801         ent->fields.server->nextthink = prog->globals.server->time + varb;
802 }
803
804 /*
805 ====================
806 PRVM_ExecuteProgram
807 ====================
808 */
809 // LordHavoc: optimized
810 #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
811 #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
812 #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
813 extern cvar_t prvm_traceqc;
814 extern cvar_t prvm_statementprofiling;
815 extern sizebuf_t vm_tempstringsbuf;
816 extern qboolean prvm_runawaycheck;
817 extern qboolean prvm_boundscheck;
818 void PRVM_ExecuteProgram (func_t fnum, const char *errormessage)
819 {
820         dstatement_t    *st, *startst;
821         mfunction_t     *f, *newf;
822         prvm_edict_t    *ed;
823         prvm_eval_t     *ptr;
824         int             jumpcount, cachedpr_trace, exitdepth;
825         int             restorevm_tempstringsbuf_cursize;
826         double  calltime;
827
828         calltime = Sys_DoubleTime();
829
830         if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
831         {
832                 if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
833                         PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
834                 PRVM_ERROR ("PRVM_ExecuteProgram: %s", errormessage);
835         }
836
837         f = &prog->functions[fnum];
838
839         // after executing this function, delete all tempstrings it created
840         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
841
842         prog->trace = prvm_traceqc.integer;
843
844         // we know we're done when pr_depth drops to this
845         exitdepth = prog->depth;
846
847 // make a stack frame
848         st = &prog->statements[PRVM_EnterFunction (f)];
849         // save the starting statement pointer for profiling
850         // (when the function exits or jumps, the (st - startst) integer value is
851         // added to the function's profile counter)
852         startst = st;
853         // instead of counting instructions, we count jumps
854         jumpcount = 0;
855         // add one to the callcount of this function because otherwise engine-called functions aren't counted
856         prog->xfunction->callcount++;
857
858 chooseexecprogram:
859         cachedpr_trace = prog->trace;
860         if (prvm_runawaycheck)
861         {
862 #define PRVMRUNAWAYCHECK 1
863                 if (prvm_statementprofiling.integer)
864                 {
865 #define PRVMSTATEMENTPROFILING 1
866                         if (prvm_boundscheck)
867                         {
868 #define PRVMBOUNDSCHECK 1
869                                 if (prog->trace)
870                                 {
871 #define PRVMTRACE 1
872 #include "prvm_execprogram.h"
873 #undef PRVMTRACE
874                                 }
875                                 else
876                                 {
877 #include "prvm_execprogram.h"
878                                 }
879 #undef PRVMBOUNDSCHECK
880                         }
881                         else
882                         {
883                                 if (prog->trace)
884                                 {
885 #define PRVMTRACE 1
886 #include "prvm_execprogram.h"
887 #undef PRVMTRACE
888                                 }
889                                 else
890                                 {
891 #include "prvm_execprogram.h"
892                                 }
893                         }
894 #undef PRVMSTATEMENTPROFILING
895                 }
896                 else
897                 {
898                         if (prvm_boundscheck)
899                         {
900 #define PRVMBOUNDSCHECK 1
901                                 if (prog->trace)
902                                 {
903 #define PRVMTRACE 1
904 #include "prvm_execprogram.h"
905 #undef PRVMTRACE
906                                 }
907                                 else
908                                 {
909 #include "prvm_execprogram.h"
910                                 }
911 #undef PRVMBOUNDSCHECK
912                         }
913                         else
914                         {
915                                 if (prog->trace)
916                                 {
917 #define PRVMTRACE 1
918 #include "prvm_execprogram.h"
919 #undef PRVMTRACE
920                                 }
921                                 else
922                                 {
923 #include "prvm_execprogram.h"
924                                 }
925                         }
926                 }
927 #undef PRVMRUNAWAYCHECK
928         }
929         else
930         {
931                 if (prvm_statementprofiling.integer)
932                 {
933 #define PRVMSTATEMENTPROFILING 1
934                         if (prvm_boundscheck)
935                         {
936 #define PRVMBOUNDSCHECK 1
937                                 if (prog->trace)
938                                 {
939 #define PRVMTRACE 1
940 #include "prvm_execprogram.h"
941 #undef PRVMTRACE
942                                 }
943                                 else
944                                 {
945 #include "prvm_execprogram.h"
946                                 }
947 #undef PRVMBOUNDSCHECK
948                         }
949                         else
950                         {
951                                 if (prog->trace)
952                                 {
953 #define PRVMTRACE 1
954 #include "prvm_execprogram.h"
955 #undef PRVMTRACE
956                                 }
957                                 else
958                                 {
959 #include "prvm_execprogram.h"
960                                 }
961                         }
962 #undef PRVMSTATEMENTPROFILING
963                 }
964                 else
965                 {
966                         if (prvm_boundscheck)
967                         {
968 #define PRVMBOUNDSCHECK 1
969                                 if (prog->trace)
970                                 {
971 #define PRVMTRACE 1
972 #include "prvm_execprogram.h"
973 #undef PRVMTRACE
974                                 }
975                                 else
976                                 {
977 #include "prvm_execprogram.h"
978                                 }
979 #undef PRVMBOUNDSCHECK
980                         }
981                         else
982                         {
983                                 if (prog->trace)
984                                 {
985 #define PRVMTRACE 1
986 #include "prvm_execprogram.h"
987 #undef PRVMTRACE
988                                 }
989                                 else
990                                 {
991 #include "prvm_execprogram.h"
992                                 }
993                         }
994                 }
995         }
996
997 cleanup:
998         if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
999                 Con_Printf("PRVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
1000         // delete tempstrings created by this function
1001         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1002
1003         prog->functions[fnum].totaltime += (Sys_DoubleTime() - calltime);
1004
1005         SV_FlushBroadcastMessages();
1006 }