]> 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 extern ddef_t *PRVM_ED_FieldAtOfs(int ofs);
317
318
319 //=============================================================================
320
321 /*
322 =================
323 PRVM_PrintStatement
324 =================
325 */
326 extern cvar_t prvm_statementprofiling;
327 void PRVM_PrintStatement (dstatement_t *s)
328 {
329         size_t i;
330         int opnum = (int)(s - prog->statements);
331
332         Con_Printf("s%i: ", opnum);
333         if( prog->statement_linenums )
334                 Con_Printf( "%s:%i: ", PRVM_GetString( prog->xfunction->s_file ), prog->statement_linenums[ opnum ] );
335
336         if (prvm_statementprofiling.integer)
337                 Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]);
338
339         if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]))
340         {
341                 Con_Printf("%s ",  prvm_opnames[s->op]);
342                 i = strlen(prvm_opnames[s->op]);
343                 // don't count a preceding color tag when padding the name
344                 if (prvm_opnames[s->op][0] == STRING_COLOR_TAG)
345                         i -= 2;
346                 for ( ; i<10 ; i++)
347                         Con_Print(" ");
348         }
349         if (s->op == OP_IF || s->op == OP_IFNOT)
350                 Con_Printf("%s, s%i",PRVM_GlobalString((unsigned short) s->a),(signed short)s->b + opnum);
351         else if (s->op == OP_GOTO)
352                 Con_Printf("s%i",(signed short)s->a + opnum);
353         else if ( (unsigned)(s->op - OP_STORE_F) < 6)
354         {
355                 Con_Print(PRVM_GlobalString((unsigned short) s->a));
356                 Con_Print(", ");
357                 Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
358         }
359         else if (s->op == OP_ADDRESS || (unsigned)(s->op - OP_LOAD_F) < 6)
360         {
361                 if (s->a)
362                         Con_Print(PRVM_GlobalString((unsigned short) s->a));
363                 if (s->b)
364                 {
365                         Con_Print(", ");
366                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
367                 }
368                 if (s->c)
369                 {
370                         Con_Print(", ");
371                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
372                 }
373         }
374         else
375         {
376                 if (s->a)
377                         Con_Print(PRVM_GlobalString((unsigned short) s->a));
378                 if (s->b)
379                 {
380                         Con_Print(", ");
381                         Con_Print(PRVM_GlobalString((unsigned short) s->b));
382                 }
383                 if (s->c)
384                 {
385                         if(!s->b) // added for debugging --blub
386                                 Con_Print(", (nil)");
387                         Con_Print(", ");
388                         Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
389                 }
390         }
391         Con_Print("\n");
392 }
393
394 void PRVM_PrintFunctionStatements (const char *name)
395 {
396         int i, firststatement, endstatement;
397         mfunction_t *func;
398         func = PRVM_ED_FindFunction (name);
399         if (!func)
400         {
401                 Con_Printf("%s progs: no function named %s\n", PRVM_NAME, name);
402                 return;
403         }
404         firststatement = func->first_statement;
405         if (firststatement < 0)
406         {
407                 Con_Printf("%s progs: function %s is builtin #%i\n", PRVM_NAME, name, -firststatement);
408                 return;
409         }
410
411         // find the end statement
412         endstatement = prog->progs->numstatements;
413         for (i = 0;i < prog->progs->numfunctions;i++)
414                 if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement)
415                         endstatement = prog->functions[i].first_statement;
416
417         // now print the range of statements
418         Con_Printf("%s progs: disassembly of function %s (statements %i-%i, locals %i-%i):\n", PRVM_NAME, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1);
419         for (i = firststatement;i < endstatement;i++)
420         {
421                 PRVM_PrintStatement(prog->statements + i);
422                 prog->statement_profile[i] = 0;
423         }
424 }
425
426 /*
427 ============
428 PRVM_PrintFunction_f
429
430 ============
431 */
432 void PRVM_PrintFunction_f (void)
433 {
434         if (Cmd_Argc() != 3)
435         {
436                 Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
437                 return;
438         }
439
440         PRVM_Begin;
441         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
442                 return;
443
444         PRVM_PrintFunctionStatements(Cmd_Argv(2));
445
446         PRVM_End;
447 }
448
449 /*
450 ============
451 PRVM_StackTrace
452 ============
453 */
454 void PRVM_StackTrace (void)
455 {
456         mfunction_t     *f;
457         int                     i;
458
459         prog->stack[prog->depth].s = prog->xstatement;
460         prog->stack[prog->depth].f = prog->xfunction;
461         for (i = prog->depth;i > 0;i--)
462         {
463                 f = prog->stack[i].f;
464
465                 if (!f)
466                         Con_Print("<NULL FUNCTION>\n");
467                 else
468                         Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement);
469         }
470 }
471
472 void PRVM_ShortStackTrace(char *buf, size_t bufsize)
473 {
474         mfunction_t     *f;
475         int                     i;
476
477         if(prog)
478         {
479                 dpsnprintf(buf, bufsize, "(%s) ", prog->name);
480         }
481         else
482         {
483                 strlcpy(buf, "<NO PROG>", bufsize);
484                 return;
485         }
486
487         prog->stack[prog->depth].s = prog->xstatement;
488         prog->stack[prog->depth].f = prog->xfunction;
489         for (i = prog->depth;i > 0;i--)
490         {
491                 f = prog->stack[i].f;
492
493                 if(strlcat(buf,
494                         f
495                                 ? va("%s:%s(%i) ", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement)
496                                 : "<NULL> ",
497                         bufsize
498                 ) >= bufsize)
499                         break;
500         }
501 }
502
503
504 void PRVM_CallProfile (void)
505 {
506         mfunction_t *f, *best;
507         int i;
508         double max;
509         double sum;
510
511         Con_Printf( "%s Call Profile:\n", PRVM_NAME );
512
513         sum = 0;
514         do
515         {
516                 max = 0;
517                 best = NULL;
518                 for (i=0 ; i<prog->progs->numfunctions ; i++)
519                 {
520                         f = &prog->functions[i];
521                         if (max < f->totaltime)
522                         {
523                                 max = f->totaltime;
524                                 best = f;
525                         }
526                 }
527                 if (best)
528                 {
529                         sum += best->totaltime;
530                         Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(best->s_name));
531                         best->totaltime = 0;
532                 }
533         } while (best);
534
535         Con_Printf("Total time since last profile reset: %9.4f\n", Sys_DoubleTime() - prog->starttime);
536         Con_Printf("       - used by QC code of this VM: %9.4f\n", sum);
537
538         prog->starttime = Sys_DoubleTime();
539 }
540
541 void PRVM_Profile (int maxfunctions, int mininstructions, int sortby)
542 {
543         mfunction_t *f, *best;
544         int i, num;
545         double max;
546
547         Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", PRVM_NAME );
548         //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
549
550         num = 0;
551         do
552         {
553                 max = 0;
554                 best = NULL;
555                 for (i=0 ; i<prog->progs->numfunctions ; i++)
556                 {
557                         f = &prog->functions[i];
558                         if(sortby)
559                         {
560                                 if (max < f->profile_total + f->builtinsprofile_total + f->callcount)
561                                 {
562                                         max = f->profile_total + f->builtinsprofile_total + f->callcount;
563                                         best = f;
564                                 }
565                         }
566                         else
567                         {
568                                 if (max < f->profile + f->builtinsprofile + f->callcount)
569                                 {
570                                         max = f->profile + f->builtinsprofile + f->callcount;
571                                         best = f;
572                                 }
573                         }
574                 }
575                 if (best)
576                 {
577                         if (num < maxfunctions && max >= mininstructions)
578                         {
579                                 if (best->first_statement < 0)
580                                         Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(best->s_name));
581                                         //                 12345678901 12345678901 12345678901 12345678901 123.45%
582                                 else
583                                         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));
584                         }
585                         num++;
586                         best->profile = 0;
587                         best->builtinsprofile = 0;
588                         best->profile_total = 0;
589                         best->builtinsprofile_total = 0;
590                         best->callcount = 0;
591                 }
592         } while (best);
593 }
594
595 /*
596 ============
597 PRVM_CallProfile_f
598
599 ============
600 */
601 void PRVM_CallProfile_f (void)
602 {
603         if (Cmd_Argc() != 2)
604         {
605                 Con_Print("prvm_callprofile <program name>\n");
606                 return;
607         }
608
609         PRVM_Begin;
610         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
611                 return;
612
613         PRVM_CallProfile();
614
615         PRVM_End;
616 }
617
618 /*
619 ============
620 PRVM_Profile_f
621
622 ============
623 */
624 void PRVM_Profile_f (void)
625 {
626         int howmany;
627
628         howmany = 1<<30;
629         if (Cmd_Argc() == 3)
630                 howmany = atoi(Cmd_Argv(2));
631         else if (Cmd_Argc() != 2)
632         {
633                 Con_Print("prvm_profile <program name>\n");
634                 return;
635         }
636
637         PRVM_Begin;
638         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
639                 return;
640
641         PRVM_Profile(howmany, 1, 0);
642
643         PRVM_End;
644 }
645
646 void PRVM_ChildProfile_f (void)
647 {
648         int howmany;
649
650         howmany = 1<<30;
651         if (Cmd_Argc() == 3)
652                 howmany = atoi(Cmd_Argv(2));
653         else if (Cmd_Argc() != 2)
654         {
655                 Con_Print("prvm_childprofile <program name>\n");
656                 return;
657         }
658
659         PRVM_Begin;
660         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
661                 return;
662
663         PRVM_Profile(howmany, 1, 1);
664
665         PRVM_End;
666 }
667
668 void PRVM_CrashAll(void)
669 {
670         int i;
671         prvm_prog_t *oldprog = prog;
672
673         for(i = 0; i < PRVM_MAXPROGS; i++)
674         {
675                 if(!PRVM_ProgLoaded(i))
676                         continue;
677                 PRVM_SetProg(i);
678                 PRVM_Crash();
679         }
680
681         prog = oldprog;
682 }
683
684 void PRVM_PrintState(void)
685 {
686         int i;
687         if(prog->statestring)
688         {
689                 Con_Printf("Caller-provided information: %s\n", prog->statestring);
690         }
691         if (prog->xfunction)
692         {
693                 for (i = -7; i <= 0;i++)
694                         if (prog->xstatement + i >= prog->xfunction->first_statement)
695                                 PRVM_PrintStatement (prog->statements + prog->xstatement + i);
696         }
697         else
698                 Con_Print("null function executing??\n");
699         PRVM_StackTrace ();
700 }
701
702 extern sizebuf_t vm_tempstringsbuf;
703 extern cvar_t prvm_errordump;
704 void Host_Savegame_to (const char *name);
705 void PRVM_Crash(void)
706 {
707         if (prog == NULL)
708                 return;
709
710         prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash
711
712         if( prog->depth > 0 )
713         {
714                 Con_Printf("QuakeC crash report for %s:\n", PRVM_NAME);
715                 PRVM_PrintState();
716         }
717
718         if(prvm_errordump.integer)
719         {
720                 // make a savegame
721                 Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME));
722         }
723
724         // dump the stack so host_error can shutdown functions
725         prog->depth = 0;
726         prog->localstack_used = 0;
727
728         // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
729         vm_tempstringsbuf.cursize = 0;
730
731         // reset the prog pointer
732         prog = NULL;
733 }
734
735 /*
736 ============================================================================
737 PRVM_ExecuteProgram
738
739 The interpretation main loop
740 ============================================================================
741 */
742
743 /*
744 ====================
745 PRVM_EnterFunction
746
747 Returns the new program statement counter
748 ====================
749 */
750 int PRVM_EnterFunction (mfunction_t *f)
751 {
752         int             i, j, c, o;
753
754         if (!f)
755                 PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME);
756
757         prog->stack[prog->depth].s = prog->xstatement;
758         prog->stack[prog->depth].f = prog->xfunction;
759         prog->stack[prog->depth].profile_acc = -f->profile;
760         prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
761         prog->depth++;
762         if (prog->depth >=PRVM_MAX_STACK_DEPTH)
763                 PRVM_ERROR ("stack overflow");
764
765 // save off any locals that the new function steps on
766         c = f->locals;
767         if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE)
768                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME);
769
770         for (i=0 ; i < c ; i++)
771                 prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
772         prog->localstack_used += c;
773
774 // copy parameters
775         o = f->parm_start;
776         for (i=0 ; i<f->numparms ; i++)
777         {
778                 for (j=0 ; j<f->parm_size[i] ; j++)
779                 {
780                         ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j];
781                         o++;
782                 }
783         }
784
785         ++f->recursion;
786         prog->xfunction = f;
787         return f->first_statement - 1;  // offset the s++
788 }
789
790 /*
791 ====================
792 PRVM_LeaveFunction
793 ====================
794 */
795 int PRVM_LeaveFunction (void)
796 {
797         int             i, c;
798         mfunction_t *f;
799
800         if (prog->depth <= 0)
801                 PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME);
802
803         if (!prog->xfunction)
804                 PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME);
805 // restore locals from the stack
806         c = prog->xfunction->locals;
807         prog->localstack_used -= c;
808         if (prog->localstack_used < 0)
809                 PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME);
810
811         for (i=0 ; i < c ; i++)
812                 ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
813
814 // up stack
815         prog->depth--;
816         f = prog->xfunction;
817         --f->recursion;
818         prog->xfunction = prog->stack[prog->depth].f;
819         prog->stack[prog->depth].profile_acc += f->profile;
820         prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile;
821         if(prog->depth > 0)
822         {
823                 prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc;
824                 prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc;
825         }
826         if(!f->recursion)
827         {
828                 // if f is already on the call stack...
829                 // we cannot add this profile data to it now
830                 // or we would add it more than once
831                 // so, let's only add to the function's profile if it is the outermost call
832                 f->profile_total += prog->stack[prog->depth].profile_acc;
833                 f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc;
834         }
835         
836         return prog->stack[prog->depth].s;
837 }
838
839 void PRVM_Init_Exec(void)
840 {
841         // dump the stack
842         prog->depth = 0;
843         prog->localstack_used = 0;
844         // reset the string table
845         // nothing here yet
846 }
847
848 void CStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
849 {
850         // This function should not be called...
851         PRVM_ERROR("CStateOp not implemented.\n");
852 }
853
854 void CWStateOp(prvm_prog_t *prog, float vara, float varb, mfunction_t *currentFunc)
855 {
856         // This function should not be called...
857         PRVM_ERROR("CWStateOp not implemented.\n");
858 }
859
860 void ThinkTimeOp(prvm_prog_t *prog, prvm_edict_t *ent, float varb)
861 {
862         ent->fields.server->nextthink = prog->globals.server->time + varb;
863 }
864
865 /*
866 ====================
867 MVM_ExecuteProgram
868 ====================
869 */
870 // LordHavoc: optimized
871 #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
872 #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
873 #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
874 extern cvar_t prvm_traceqc;
875 extern cvar_t prvm_statementprofiling;
876 extern sizebuf_t vm_tempstringsbuf;
877 extern qboolean prvm_runawaycheck;
878 extern qboolean prvm_boundscheck;
879 void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
880 {
881         dstatement_t    *st, *startst;
882         mfunction_t     *f, *newf;
883         prvm_edict_t    *ed;
884         prvm_eval_t     *ptr;
885         int             jumpcount, cachedpr_trace, exitdepth;
886         int             restorevm_tempstringsbuf_cursize;
887         double  calltime;
888
889         calltime = Sys_DoubleTime();
890
891         if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
892         {
893                 if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
894                         PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
895                 PRVM_ERROR ("MVM_ExecuteProgram: %s", errormessage);
896         }
897
898         f = &prog->functions[fnum];
899
900         // after executing this function, delete all tempstrings it created
901         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
902
903         prog->trace = prvm_traceqc.integer;
904
905         // we know we're done when pr_depth drops to this
906         exitdepth = prog->depth;
907
908 // make a stack frame
909         st = &prog->statements[PRVM_EnterFunction (f)];
910         // save the starting statement pointer for profiling
911         // (when the function exits or jumps, the (st - startst) integer value is
912         // added to the function's profile counter)
913         startst = st;
914         // instead of counting instructions, we count jumps
915         jumpcount = 0;
916         // add one to the callcount of this function because otherwise engine-called functions aren't counted
917         prog->xfunction->callcount++;
918
919 chooseexecprogram:
920         cachedpr_trace = prog->trace;
921         if (prvm_runawaycheck)
922         {
923 #define PRVMRUNAWAYCHECK 1
924                 if (prvm_statementprofiling.integer)
925                 {
926 #define PRVMSTATEMENTPROFILING 1
927                         if (prvm_boundscheck)
928                         {
929 #define PRVMBOUNDSCHECK 1
930                                 if (prog->trace)
931                                 {
932 #define PRVMTRACE 1
933 #include "prvm_execprogram.h"
934 #undef PRVMTRACE
935                                 }
936                                 else
937                                 {
938 #include "prvm_execprogram.h"
939                                 }
940 #undef PRVMBOUNDSCHECK
941                         }
942                         else
943                         {
944                                 if (prog->trace)
945                                 {
946 #define PRVMTRACE 1
947 #include "prvm_execprogram.h"
948 #undef PRVMTRACE
949                                 }
950                                 else
951                                 {
952 #include "prvm_execprogram.h"
953                                 }
954                         }
955 #undef PRVMSTATEMENTPROFILING
956                 }
957                 else
958                 {
959                         if (prvm_boundscheck)
960                         {
961 #define PRVMBOUNDSCHECK 1
962                                 if (prog->trace)
963                                 {
964 #define PRVMTRACE 1
965 #include "prvm_execprogram.h"
966 #undef PRVMTRACE
967                                 }
968                                 else
969                                 {
970 #include "prvm_execprogram.h"
971                                 }
972 #undef PRVMBOUNDSCHECK
973                         }
974                         else
975                         {
976                                 if (prog->trace)
977                                 {
978 #define PRVMTRACE 1
979 #include "prvm_execprogram.h"
980 #undef PRVMTRACE
981                                 }
982                                 else
983                                 {
984 #include "prvm_execprogram.h"
985                                 }
986                         }
987                 }
988 #undef PRVMRUNAWAYCHECK
989         }
990         else
991         {
992                 if (prvm_statementprofiling.integer)
993                 {
994 #define PRVMSTATEMENTPROFILING 1
995                         if (prvm_boundscheck)
996                         {
997 #define PRVMBOUNDSCHECK 1
998                                 if (prog->trace)
999                                 {
1000 #define PRVMTRACE 1
1001 #include "prvm_execprogram.h"
1002 #undef PRVMTRACE
1003                                 }
1004                                 else
1005                                 {
1006 #include "prvm_execprogram.h"
1007                                 }
1008 #undef PRVMBOUNDSCHECK
1009                         }
1010                         else
1011                         {
1012                                 if (prog->trace)
1013                                 {
1014 #define PRVMTRACE 1
1015 #include "prvm_execprogram.h"
1016 #undef PRVMTRACE
1017                                 }
1018                                 else
1019                                 {
1020 #include "prvm_execprogram.h"
1021                                 }
1022                         }
1023 #undef PRVMSTATEMENTPROFILING
1024                 }
1025                 else
1026                 {
1027                         if (prvm_boundscheck)
1028                         {
1029 #define PRVMBOUNDSCHECK 1
1030                                 if (prog->trace)
1031                                 {
1032 #define PRVMTRACE 1
1033 #include "prvm_execprogram.h"
1034 #undef PRVMTRACE
1035                                 }
1036                                 else
1037                                 {
1038 #include "prvm_execprogram.h"
1039                                 }
1040 #undef PRVMBOUNDSCHECK
1041                         }
1042                         else
1043                         {
1044                                 if (prog->trace)
1045                                 {
1046 #define PRVMTRACE 1
1047 #include "prvm_execprogram.h"
1048 #undef PRVMTRACE
1049                                 }
1050                                 else
1051                                 {
1052 #include "prvm_execprogram.h"
1053                                 }
1054                         }
1055                 }
1056         }
1057
1058 cleanup:
1059         if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1060                 Con_Printf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
1061         // delete tempstrings created by this function
1062         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1063
1064         f->totaltime += (Sys_DoubleTime() - calltime);
1065
1066         SV_FlushBroadcastMessages();
1067 }
1068
1069 /*
1070 ====================
1071 CLVM_ExecuteProgram
1072 ====================
1073 */
1074 // LordHavoc: optimized
1075 #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
1076 #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
1077 #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
1078 extern cvar_t prvm_traceqc;
1079 extern cvar_t prvm_statementprofiling;
1080 extern sizebuf_t vm_tempstringsbuf;
1081 extern qboolean prvm_runawaycheck;
1082 extern qboolean prvm_boundscheck;
1083 void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
1084 {
1085         dstatement_t    *st, *startst;
1086         mfunction_t     *f, *newf;
1087         prvm_edict_t    *ed;
1088         prvm_eval_t     *ptr;
1089         int             jumpcount, cachedpr_trace, exitdepth;
1090         int             restorevm_tempstringsbuf_cursize;
1091         double  calltime;
1092
1093         calltime = Sys_DoubleTime();
1094
1095         if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
1096         {
1097                 if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
1098                         PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
1099                 PRVM_ERROR ("CLVM_ExecuteProgram: %s", errormessage);
1100         }
1101
1102         f = &prog->functions[fnum];
1103
1104         // after executing this function, delete all tempstrings it created
1105         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1106
1107         prog->trace = prvm_traceqc.integer;
1108
1109         // we know we're done when pr_depth drops to this
1110         exitdepth = prog->depth;
1111
1112 // make a stack frame
1113         st = &prog->statements[PRVM_EnterFunction (f)];
1114         // save the starting statement pointer for profiling
1115         // (when the function exits or jumps, the (st - startst) integer value is
1116         // added to the function's profile counter)
1117         startst = st;
1118         // instead of counting instructions, we count jumps
1119         jumpcount = 0;
1120         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1121         prog->xfunction->callcount++;
1122
1123 chooseexecprogram:
1124         cachedpr_trace = prog->trace;
1125         if (prvm_runawaycheck)
1126         {
1127 #define PRVMRUNAWAYCHECK 1
1128                 if (prvm_statementprofiling.integer)
1129                 {
1130 #define PRVMSTATEMENTPROFILING 1
1131                         if (prvm_boundscheck)
1132                         {
1133 #define PRVMBOUNDSCHECK 1
1134                                 if (prog->trace)
1135                                 {
1136 #define PRVMTRACE 1
1137 #include "prvm_execprogram.h"
1138 #undef PRVMTRACE
1139                                 }
1140                                 else
1141                                 {
1142 #include "prvm_execprogram.h"
1143                                 }
1144 #undef PRVMBOUNDSCHECK
1145                         }
1146                         else
1147                         {
1148                                 if (prog->trace)
1149                                 {
1150 #define PRVMTRACE 1
1151 #include "prvm_execprogram.h"
1152 #undef PRVMTRACE
1153                                 }
1154                                 else
1155                                 {
1156 #include "prvm_execprogram.h"
1157                                 }
1158                         }
1159 #undef PRVMSTATEMENTPROFILING
1160                 }
1161                 else
1162                 {
1163                         if (prvm_boundscheck)
1164                         {
1165 #define PRVMBOUNDSCHECK 1
1166                                 if (prog->trace)
1167                                 {
1168 #define PRVMTRACE 1
1169 #include "prvm_execprogram.h"
1170 #undef PRVMTRACE
1171                                 }
1172                                 else
1173                                 {
1174 #include "prvm_execprogram.h"
1175                                 }
1176 #undef PRVMBOUNDSCHECK
1177                         }
1178                         else
1179                         {
1180                                 if (prog->trace)
1181                                 {
1182 #define PRVMTRACE 1
1183 #include "prvm_execprogram.h"
1184 #undef PRVMTRACE
1185                                 }
1186                                 else
1187                                 {
1188 #include "prvm_execprogram.h"
1189                                 }
1190                         }
1191                 }
1192 #undef PRVMRUNAWAYCHECK
1193         }
1194         else
1195         {
1196                 if (prvm_statementprofiling.integer)
1197                 {
1198 #define PRVMSTATEMENTPROFILING 1
1199                         if (prvm_boundscheck)
1200                         {
1201 #define PRVMBOUNDSCHECK 1
1202                                 if (prog->trace)
1203                                 {
1204 #define PRVMTRACE 1
1205 #include "prvm_execprogram.h"
1206 #undef PRVMTRACE
1207                                 }
1208                                 else
1209                                 {
1210 #include "prvm_execprogram.h"
1211                                 }
1212 #undef PRVMBOUNDSCHECK
1213                         }
1214                         else
1215                         {
1216                                 if (prog->trace)
1217                                 {
1218 #define PRVMTRACE 1
1219 #include "prvm_execprogram.h"
1220 #undef PRVMTRACE
1221                                 }
1222                                 else
1223                                 {
1224 #include "prvm_execprogram.h"
1225                                 }
1226                         }
1227 #undef PRVMSTATEMENTPROFILING
1228                 }
1229                 else
1230                 {
1231                         if (prvm_boundscheck)
1232                         {
1233 #define PRVMBOUNDSCHECK 1
1234                                 if (prog->trace)
1235                                 {
1236 #define PRVMTRACE 1
1237 #include "prvm_execprogram.h"
1238 #undef PRVMTRACE
1239                                 }
1240                                 else
1241                                 {
1242 #include "prvm_execprogram.h"
1243                                 }
1244 #undef PRVMBOUNDSCHECK
1245                         }
1246                         else
1247                         {
1248                                 if (prog->trace)
1249                                 {
1250 #define PRVMTRACE 1
1251 #include "prvm_execprogram.h"
1252 #undef PRVMTRACE
1253                                 }
1254                                 else
1255                                 {
1256 #include "prvm_execprogram.h"
1257                                 }
1258                         }
1259                 }
1260         }
1261
1262 cleanup:
1263         if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1264                 Con_Printf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
1265         // delete tempstrings created by this function
1266         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1267
1268         f->totaltime += (Sys_DoubleTime() - calltime);
1269
1270         SV_FlushBroadcastMessages();
1271 }
1272
1273 /*
1274 ====================
1275 SVVM_ExecuteProgram
1276 ====================
1277 */
1278 // LordHavoc: optimized
1279 #define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
1280 #define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
1281 #define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
1282 extern cvar_t prvm_traceqc;
1283 extern cvar_t prvm_statementprofiling;
1284 extern sizebuf_t vm_tempstringsbuf;
1285 extern qboolean prvm_runawaycheck;
1286 extern qboolean prvm_boundscheck;
1287 void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
1288 {
1289         dstatement_t    *st, *startst;
1290         mfunction_t     *f, *newf;
1291         prvm_edict_t    *ed;
1292         prvm_eval_t     *ptr;
1293         int             jumpcount, cachedpr_trace, exitdepth;
1294         int             restorevm_tempstringsbuf_cursize;
1295         double  calltime;
1296
1297         calltime = Sys_DoubleTime();
1298
1299         if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
1300         {
1301                 if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
1302                         PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
1303                 PRVM_ERROR ("SVVM_ExecuteProgram: %s", errormessage);
1304         }
1305
1306         f = &prog->functions[fnum];
1307
1308         // after executing this function, delete all tempstrings it created
1309         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1310
1311         prog->trace = prvm_traceqc.integer;
1312
1313         // we know we're done when pr_depth drops to this
1314         exitdepth = prog->depth;
1315
1316 // make a stack frame
1317         st = &prog->statements[PRVM_EnterFunction (f)];
1318         // save the starting statement pointer for profiling
1319         // (when the function exits or jumps, the (st - startst) integer value is
1320         // added to the function's profile counter)
1321         startst = st;
1322         // instead of counting instructions, we count jumps
1323         jumpcount = 0;
1324         // add one to the callcount of this function because otherwise engine-called functions aren't counted
1325         prog->xfunction->callcount++;
1326
1327 chooseexecprogram:
1328         cachedpr_trace = prog->trace;
1329         if (prvm_runawaycheck)
1330         {
1331 #define PRVMRUNAWAYCHECK 1
1332                 if (prvm_statementprofiling.integer)
1333                 {
1334 #define PRVMSTATEMENTPROFILING 1
1335                         if (prvm_boundscheck)
1336                         {
1337 #define PRVMBOUNDSCHECK 1
1338                                 if (prog->trace)
1339                                 {
1340 #define PRVMTRACE 1
1341 #include "prvm_execprogram.h"
1342 #undef PRVMTRACE
1343                                 }
1344                                 else
1345                                 {
1346 #include "prvm_execprogram.h"
1347                                 }
1348 #undef PRVMBOUNDSCHECK
1349                         }
1350                         else
1351                         {
1352                                 if (prog->trace)
1353                                 {
1354 #define PRVMTRACE 1
1355 #include "prvm_execprogram.h"
1356 #undef PRVMTRACE
1357                                 }
1358                                 else
1359                                 {
1360 #include "prvm_execprogram.h"
1361                                 }
1362                         }
1363 #undef PRVMSTATEMENTPROFILING
1364                 }
1365                 else
1366                 {
1367                         if (prvm_boundscheck)
1368                         {
1369 #define PRVMBOUNDSCHECK 1
1370                                 if (prog->trace)
1371                                 {
1372 #define PRVMTRACE 1
1373 #include "prvm_execprogram.h"
1374 #undef PRVMTRACE
1375                                 }
1376                                 else
1377                                 {
1378 #include "prvm_execprogram.h"
1379                                 }
1380 #undef PRVMBOUNDSCHECK
1381                         }
1382                         else
1383                         {
1384                                 if (prog->trace)
1385                                 {
1386 #define PRVMTRACE 1
1387 #include "prvm_execprogram.h"
1388 #undef PRVMTRACE
1389                                 }
1390                                 else
1391                                 {
1392 #include "prvm_execprogram.h"
1393                                 }
1394                         }
1395                 }
1396 #undef PRVMRUNAWAYCHECK
1397         }
1398         else
1399         {
1400                 if (prvm_statementprofiling.integer)
1401                 {
1402 #define PRVMSTATEMENTPROFILING 1
1403                         if (prvm_boundscheck)
1404                         {
1405 #define PRVMBOUNDSCHECK 1
1406                                 if (prog->trace)
1407                                 {
1408 #define PRVMTRACE 1
1409 #include "prvm_execprogram.h"
1410 #undef PRVMTRACE
1411                                 }
1412                                 else
1413                                 {
1414 #include "prvm_execprogram.h"
1415                                 }
1416 #undef PRVMBOUNDSCHECK
1417                         }
1418                         else
1419                         {
1420                                 if (prog->trace)
1421                                 {
1422 #define PRVMTRACE 1
1423 #include "prvm_execprogram.h"
1424 #undef PRVMTRACE
1425                                 }
1426                                 else
1427                                 {
1428 #include "prvm_execprogram.h"
1429                                 }
1430                         }
1431 #undef PRVMSTATEMENTPROFILING
1432                 }
1433                 else
1434                 {
1435                         if (prvm_boundscheck)
1436                         {
1437 #define PRVMBOUNDSCHECK 1
1438                                 if (prog->trace)
1439                                 {
1440 #define PRVMTRACE 1
1441 #include "prvm_execprogram.h"
1442 #undef PRVMTRACE
1443                                 }
1444                                 else
1445                                 {
1446 #include "prvm_execprogram.h"
1447                                 }
1448 #undef PRVMBOUNDSCHECK
1449                         }
1450                         else
1451                         {
1452                                 if (prog->trace)
1453                                 {
1454 #define PRVMTRACE 1
1455 #include "prvm_execprogram.h"
1456 #undef PRVMTRACE
1457                                 }
1458                                 else
1459                                 {
1460 #include "prvm_execprogram.h"
1461                                 }
1462                         }
1463                 }
1464         }
1465
1466 cleanup:
1467         if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
1468                 Con_Printf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
1469         // delete tempstrings created by this function
1470         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1471
1472         f->totaltime += (Sys_DoubleTime() - calltime);
1473
1474         SV_FlushBroadcastMessages();
1475 }