]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_exec.c
Merge branch '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, int sortby)
541 {
542         mfunction_t *f, *best;
543         int i, num;
544         double max;
545
546         Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", PRVM_NAME );
547         //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
548
549         num = 0;
550         do
551         {
552                 max = 0;
553                 best = NULL;
554                 for (i=0 ; i<prog->progs->numfunctions ; i++)
555                 {
556                         f = &prog->functions[i];
557                         if(sortby)
558                         {
559                                 if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
560                                 {
561                                         max = f->profile_total + f->builtinsprofile_total + f->callcount;
562                                         best = f;
563                                 }
564                         }
565                         else
566                         {
567                                 if (max < f->profile + f->builtinsprofile + f->callcount)
568                                 {
569                                         max = f->profile + f->builtinsprofile + f->callcount;
570                                         best = f;
571                                 }
572                         }
573                 }
574                 if (best)
575                 {
576                         if (num < maxfunctions && max >= mininstructions)
577                         {
578                                 if (best->first_statement < 0)
579                                         Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(best->s_name));
580                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
581                                 else
582                                         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(best->s_name));
583                         }
584                         num++;
585                         best->profile = 0;
586                         best->builtinsprofile = 0;
587                         best->profile_total = 0;
588                         best->builtinsprofile_total = 0;
589                         best->callcount = 0;
590                 }
591         } while (best);
592 }
593
594 /*
595 ============
596 PRVM_CallProfile_f
597
598 ============
599 */
600 void PRVM_CallProfile_f (void)
601 {
602         if (Cmd_Argc() != 2)
603         {
604                 Con_Print("prvm_callprofile <program name>\n");
605                 return;
606         }
607
608         PRVM_Begin;
609         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
610                 return;
611
612         PRVM_CallProfile();
613
614         PRVM_End;
615 }
616
617 /*
618 ============
619 PRVM_Profile_f
620
621 ============
622 */
623 void PRVM_Profile_f (void)
624 {
625         int howmany;
626
627         howmany = 1<<30;
628         if (Cmd_Argc() == 3)
629                 howmany = atoi(Cmd_Argv(2));
630         else if (Cmd_Argc() != 2)
631         {
632                 Con_Print("prvm_profile <program name>\n");
633                 return;
634         }
635
636         PRVM_Begin;
637         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
638                 return;
639
640         PRVM_Profile(howmany, 1, 0);
641
642         PRVM_End;
643 }
644
645 void PRVM_ChildProfile_f (void)
646 {
647         int howmany;
648
649         howmany = 1<<30;
650         if (Cmd_Argc() == 3)
651                 howmany = atoi(Cmd_Argv(2));
652         else if (Cmd_Argc() != 2)
653         {
654                 Con_Print("prvm_childprofile <program name>\n");
655                 return;
656         }
657
658         PRVM_Begin;
659         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
660                 return;
661
662         PRVM_Profile(howmany, 1, 1);
663
664         PRVM_End;
665 }
666
667 void PRVM_CrashAll(void)
668 {
669         int i;
670         prvm_prog_t *oldprog = prog;
671
672         for(i = 0; i < PRVM_MAXPROGS; i++)
673         {
674                 if(!PRVM_ProgLoaded(i))
675                         continue;
676                 PRVM_SetProg(i);
677                 PRVM_Crash();
678         }
679
680         prog = oldprog;
681 }
682
683 void PRVM_PrintState(void)
684 {
685         int i;
686         if(prog->statestring)
687         {
688                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
689         }
690         if (prog->xfunction)
691         {
692                 for (i = -7; i <= 0;i++)
693                         if (prog->xstatement + i >= prog->xfunction->first_statement)
694                                 PRVM_PrintStatement (prog->statements + prog->xstatement + i);
695         }
696         else
697                 Con_Print("null function executing??\n");
698         PRVM_StackTrace ();
699 }
700
701 extern sizebuf_t vm_tempstringsbuf;
702 extern cvar_t prvm_errordump;
703 void Host_Savegame_to (const char *name);
704 void PRVM_Crash(void)
705 {
706         if (prog == NULL)
707                 return;
708
709         prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash
710
711         if( prog->depth > 0 )
712         {
713                 Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME);
714                 PRVM_PrintState();
715         }
716
717         if(prvm_errordump.integer)
718         {
719                 // make a savegame
720                 Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME));
721         }
722
723         // dump the stack so host_error can shutdown functions
724         prog->depth = 0;
725         prog->localstack_used = 0;
726
727         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
728         vm_tempstringsbuf.cursize = 0;
729
730         // reset the prog pointer
731         prog = NULL;
732 }
733
734 /*
735 ============================================================================
736 PRVM_ExecuteProgram
737
738 The interpretation main loop
739 ============================================================================
740 */
741
742 /*
743 ====================
744 PRVM_EnterFunction
745
746 Returns the new program statement counter
747 ====================
748 */
749 int PRVM_EnterFunction (mfunction_t *f)
750 {
751         int             i, j, c, o;
752
753         if (!f)
754                 PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME);
755
756         prog->stack[prog->depth].s = prog->xstatement;
757         prog->stack[prog->depth].f = prog->xfunction;
758         prog->stack[prog->depth].profile_acc = -f->profile;
759         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
760         prog->depth++;
761         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
762                 PRVM_ERROR ("stack overflow");
763
764 // save off any locals that the new function steps on
765         c = f->locals;
766         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
767                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME);
768
769         for (i=0 ; i < c ; i++)
770                 prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
771         prog->localstack_used += c;
772
773 // copy parameters
774         o = f->parm_start;
775         for (i=0 ; i<f->numparms ; i++)
776         {
777                 for (j=0 ; j<f->parm_size[i] ; j++)
778                 {
779                         ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j];
780                         o++;
781                 }
782         }
783
784         ++f->recursion;
785         prog->xfunction = f;
786         return f->first_statement - 1;  // offset the s++
787 }
788
789 /*
790 ====================
791 PRVM_LeaveFunction
792 ====================
793 */
794 int PRVM_LeaveFunction (void)
795 {
796         int             i, c;
797         mfunction_t *f;
798
799         if (prog->depth <= 0)
800                 PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME);
801
802         if (!prog->xfunction)
803                 PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME);
804 // restore locals from the stack
805         c = prog->xfunction->locals;
806         prog->localstack_used -= c;
807         if (prog->localstack_used < 0)
808                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME);
809
810         for (i=0 ; i < c ; i++)
811                 ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
812
813 // up stack
814         prog->depth--;
815         f = prog->xfunction;
816         --f->recursion;
817         prog->xfunction = prog->stack[prog->depth].f;
818         prog->stack[prog->depth].profile_acc += f->profile;
819         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
820         if(prog->depth > 0)
821         {
822                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
823                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
824         }
825         if(!f->recursion)
826         {
827                 // if f is already on the call stack...
828                 // we cannot add this profile data to it now
829                 // or we would add it more than once
830                 // so, let's only add to the function's profile if it is the outermost call
831                 f->profile_total += prog->stack[prog->depth].profile_acc;
832                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
833         }
834         
835         return prog->stack[prog->depth].s;
836 }
837
838 void PRVM_Init_Exec(void)
839 {
840         // dump the stack
841         prog->depth = 0;
842         prog->localstack_used = 0;
843         // reset the string table
844         // nothing here yet
845 }
846
847 void CStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
848 {
849         // This function should not be called...
850         PRVM_ERROR("CStateOp not implemented.\n");
851 }
852
853 void CWStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
854 {
855         // This function should not be called...
856         PRVM_ERROR("CWStateOp not implemented.\n");
857 }
858
859 void ThinkTimeOp(prvm_prog_t *prog, prvm_edict_t *ent, float varb)
860 {
861         ent->fields.server->nextthink = prog->globals.server->time + varb;
862 }
863
864 /*
865 ====================
866 PRVM_ExecuteProgram
867 ====================
868 */
869 // LordHavoc: optimized
870 #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
871 #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
872 #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
873 extern cvar_t prvm_traceqc;
874 extern cvar_t prvm_statementprofiling;
875 extern sizebuf_t vm_tempstringsbuf;
876 extern qboolean prvm_runawaycheck;
877 extern qboolean prvm_boundscheck;
878 void PRVM_ExecuteProgram (func_t fnum, const char *errormessage)
879 {
880         dstatement_t    *st, *startst;
881         mfunction_t     *f, *newf;
882         prvm_edict_t    *ed;
883         prvm_eval_t     *ptr;
884         int             jumpcount, cachedpr_trace, exitdepth;
885         int             restorevm_tempstringsbuf_cursize;
886         double  calltime;
887
888         calltime = Sys_DoubleTime();
889
890         if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
891         {
892                 if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
893                         PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
894                 PRVM_ERROR ("PRVM_ExecuteProgram: %s", errormessage);
895         }
896
897         f = &prog->functions[fnum];
898
899         // after executing this function, delete all tempstrings it created
900         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
901
902         prog->trace = prvm_traceqc.integer;
903
904         // we know we're done when pr_depth drops to this
905         exitdepth = prog->depth;
906
907 // make a stack frame
908         st = &prog->statements[PRVM_EnterFunction (f)];
909         // save the starting statement pointer for profiling
910         // (when the function exits or jumps, the (st - startst) integer value is
911         // added to the function's profile counter)
912         startst = st;
913         // instead of counting instructions, we count jumps
914         jumpcount = 0;
915         // add one to the callcount of this function because otherwise engine-called functions aren't counted
916         prog->xfunction->callcount++;
917
918 chooseexecprogram:
919         cachedpr_trace = prog->trace;
920         if (prvm_runawaycheck)
921         {
922 #define PRVMRUNAWAYCHECK 1
923                 if (prvm_statementprofiling.integer)
924                 {
925 #define PRVMSTATEMENTPROFILING 1
926                         if (prvm_boundscheck)
927                         {
928 #define PRVMBOUNDSCHECK 1
929                                 if (prog->trace)
930                                 {
931 #define PRVMTRACE 1
932 #include "prvm_execprogram.h"
933 #undef PRVMTRACE
934                                 }
935                                 else
936                                 {
937 #include "prvm_execprogram.h"
938                                 }
939 #undef PRVMBOUNDSCHECK
940                         }
941                         else
942                         {
943                                 if (prog->trace)
944                                 {
945 #define PRVMTRACE 1
946 #include "prvm_execprogram.h"
947 #undef PRVMTRACE
948                                 }
949                                 else
950                                 {
951 #include "prvm_execprogram.h"
952                                 }
953                         }
954 #undef PRVMSTATEMENTPROFILING
955                 }
956                 else
957                 {
958                         if (prvm_boundscheck)
959                         {
960 #define PRVMBOUNDSCHECK 1
961                                 if (prog->trace)
962                                 {
963 #define PRVMTRACE 1
964 #include "prvm_execprogram.h"
965 #undef PRVMTRACE
966                                 }
967                                 else
968                                 {
969 #include "prvm_execprogram.h"
970                                 }
971 #undef PRVMBOUNDSCHECK
972                         }
973                         else
974                         {
975                                 if (prog->trace)
976                                 {
977 #define PRVMTRACE 1
978 #include "prvm_execprogram.h"
979 #undef PRVMTRACE
980                                 }
981                                 else
982                                 {
983 #include "prvm_execprogram.h"
984                                 }
985                         }
986                 }
987 #undef PRVMRUNAWAYCHECK
988         }
989         else
990         {
991                 if (prvm_statementprofiling.integer)
992                 {
993 #define PRVMSTATEMENTPROFILING 1
994                         if (prvm_boundscheck)
995                         {
996 #define PRVMBOUNDSCHECK 1
997                                 if (prog->trace)
998                                 {
999 #define PRVMTRACE 1
1000 #include "prvm_execprogram.h"
1001 #undef PRVMTRACE
1002                                 }
1003                                 else
1004                                 {
1005 #include "prvm_execprogram.h"
1006                                 }
1007 #undef PRVMBOUNDSCHECK
1008                         }
1009                         else
1010                         {
1011                                 if (prog->trace)
1012                                 {
1013 #define PRVMTRACE 1
1014 #include "prvm_execprogram.h"
1015 #undef PRVMTRACE
1016                                 }
1017                                 else
1018                                 {
1019 #include "prvm_execprogram.h"
1020                                 }
1021                         }
1022 #undef PRVMSTATEMENTPROFILING
1023                 }
1024                 else
1025                 {
1026                         if (prvm_boundscheck)
1027                         {
1028 #define PRVMBOUNDSCHECK 1
1029                                 if (prog->trace)
1030                                 {
1031 #define PRVMTRACE 1
1032 #include "prvm_execprogram.h"
1033 #undef PRVMTRACE
1034                                 }
1035                                 else
1036                                 {
1037 #include "prvm_execprogram.h"
1038                                 }
1039 #undef PRVMBOUNDSCHECK
1040                         }
1041                         else
1042                         {
1043                                 if (prog->trace)
1044                                 {
1045 #define PRVMTRACE 1
1046 #include "prvm_execprogram.h"
1047 #undef PRVMTRACE
1048                                 }
1049                                 else
1050                                 {
1051 #include "prvm_execprogram.h"
1052                                 }
1053                         }
1054                 }
1055         }
1056
1057 cleanup:
1058         if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1059                 Con_Printf("PRVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
1060         // delete tempstrings created by this function
1061         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1062
1063         f->totaltime += (Sys_DoubleTime() - calltime);
1064
1065         SV_FlushBroadcastMessages();
1066 }