cleaned up pr_builtins array (now uses NULL instead of PF_fixme) and now reports...
[divverent/darkplaces.git] / pr_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
23
24 typedef struct
25 {
26         int                             s;
27         mfunction_t             *f;
28 } prstack_t;
29
30 #define MAX_STACK_DEPTH         256
31 prstack_t       pr_stack[MAX_STACK_DEPTH];
32 int                     pr_depth = 0;
33
34 #define LOCALSTACK_SIZE         2048
35 int                     localstack[LOCALSTACK_SIZE];
36 int                     localstack_used;
37
38
39 int                     pr_trace;
40 mfunction_t     *pr_xfunction;
41 int                     pr_xstatement;
42
43
44 int             pr_argc;
45
46 char *pr_opnames[] =
47 {
48 "DONE",
49
50 "MUL_F",
51 "MUL_V",
52 "MUL_FV",
53 "MUL_VF",
54
55 "DIV",
56
57 "ADD_F",
58 "ADD_V",
59
60 "SUB_F",
61 "SUB_V",
62
63 "EQ_F",
64 "EQ_V",
65 "EQ_S",
66 "EQ_E",
67 "EQ_FNC",
68
69 "NE_F",
70 "NE_V",
71 "NE_S",
72 "NE_E",
73 "NE_FNC",
74
75 "LE",
76 "GE",
77 "LT",
78 "GT",
79
80 "INDIRECT",
81 "INDIRECT",
82 "INDIRECT",
83 "INDIRECT",
84 "INDIRECT",
85 "INDIRECT",
86
87 "ADDRESS",
88
89 "STORE_F",
90 "STORE_V",
91 "STORE_S",
92 "STORE_ENT",
93 "STORE_FLD",
94 "STORE_FNC",
95
96 "STOREP_F",
97 "STOREP_V",
98 "STOREP_S",
99 "STOREP_ENT",
100 "STOREP_FLD",
101 "STOREP_FNC",
102
103 "RETURN",
104
105 "NOT_F",
106 "NOT_V",
107 "NOT_S",
108 "NOT_ENT",
109 "NOT_FNC",
110
111 "IF",
112 "IFNOT",
113
114 "CALL0",
115 "CALL1",
116 "CALL2",
117 "CALL3",
118 "CALL4",
119 "CALL5",
120 "CALL6",
121 "CALL7",
122 "CALL8",
123
124 "STATE",
125
126 "GOTO",
127
128 "AND",
129 "OR",
130
131 "BITAND",
132 "BITOR"
133 };
134
135 char *PR_GlobalString (int ofs);
136 char *PR_GlobalStringNoContents (int ofs);
137
138
139 //=============================================================================
140
141 /*
142 =================
143 PR_PrintStatement
144 =================
145 */
146 void PR_PrintStatement (dstatement_t *s)
147 {
148         int             i;
149
150         if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))
151         {
152                 Con_Printf ("%s ",  pr_opnames[s->op]);
153                 i = strlen(pr_opnames[s->op]);
154                 for ( ; i<10 ; i++)
155                         Con_Printf (" ");
156         }
157
158         if (s->op == OP_IF || s->op == OP_IFNOT)
159                 Con_Printf ("%sbranch %i",PR_GlobalString((unsigned short) s->a),s->b);
160         else if (s->op == OP_GOTO)
161         {
162                 Con_Printf ("branch %i",s->a);
163         }
164         else if ( (unsigned)(s->op - OP_STORE_F) < 6)
165         {
166                 Con_Printf ("%s", PR_GlobalString((unsigned short) s->a));
167                 Con_Printf ("%s", PR_GlobalStringNoContents((unsigned short) s->b));
168         }
169         else
170         {
171                 if (s->a)
172                         Con_Printf ("%s", PR_GlobalString((unsigned short) s->a));
173                 if (s->b)
174                         Con_Printf ("%s", PR_GlobalString((unsigned short) s->b));
175                 if (s->c)
176                         Con_Printf ("%s", PR_GlobalStringNoContents((unsigned short) s->c));
177         }
178         Con_Printf ("\n");
179 }
180
181 /*
182 ============
183 PR_StackTrace
184 ============
185 */
186 void PR_StackTrace (void)
187 {
188         mfunction_t     *f;
189         int                     i;
190
191         pr_stack[pr_depth].s = pr_xstatement;
192         pr_stack[pr_depth].f = pr_xfunction;
193         for (i = pr_depth;i > 0;i--)
194         {
195                 f = pr_stack[i].f;
196
197                 if (!f)
198                         Con_Printf ("<NULL FUNCTION>\n");
199                 else
200                         Con_Printf ("%12s : %s : statement %i\n", PR_GetString(f->s_file), PR_GetString(f->s_name), pr_stack[i].s - f->first_statement);
201         }
202 }
203
204
205 /*
206 ============
207 PR_Profile_f
208
209 ============
210 */
211 void PR_Profile_f (void)
212 {
213         mfunction_t *f, *best;
214         int i, num, max/*, howmany*/;
215
216         //howmany = 10;
217         //if (Cmd_Argc() == 2)
218         //      howmany = atoi(Cmd_Argv(1));
219         num = 0;
220         do
221         {
222                 max = 0;
223                 best = NULL;
224                 for (i=0 ; i<progs->numfunctions ; i++)
225                 {
226                         f = &pr_functions[i];
227                         if (f->profile > max)
228                         {
229                                 max = f->profile;
230                                 best = f;
231                         }
232                 }
233                 if (best)
234                 {
235                         //if (num < howmany)
236                                 Con_Printf ("%7i %7i %s\n", best->profile, best->builtinsprofile, PR_GetString(best->s_name));
237                         num++;
238                         best->profile = 0;
239                         best->builtinsprofile = 0;
240                 }
241         } while (best);
242 }
243
244
245 void PR_Crash(void)
246 {
247         int i;
248         if (pr_depth < 1)
249         {
250                 // kill the stack just to be sure
251                 pr_depth = 0;
252                 localstack_used = 0;
253                 return;
254         }
255
256         Con_Printf("QuakeC crash report:\n");
257         if (pr_xfunction)
258         {
259                 for (i = -4;i <= 0;i++)
260                         if (pr_xstatement + i >= pr_xfunction->first_statement)
261                                 PR_PrintStatement (pr_statements + pr_xstatement + i);
262         }
263         else
264                 Con_Printf("null function executing??\n");
265         PR_StackTrace ();
266
267         // dump the stack so host_error can shutdown functions
268         pr_depth = 0;
269         localstack_used = 0;
270 }
271
272 /*
273 ============================================================================
274 PR_ExecuteProgram
275
276 The interpretation main loop
277 ============================================================================
278 */
279
280 /*
281 ====================
282 PR_EnterFunction
283
284 Returns the new program statement counter
285 ====================
286 */
287 int PR_EnterFunction (mfunction_t *f)
288 {
289         int             i, j, c, o;
290
291         if (!f)
292                 Host_Error ("PR_EnterFunction: NULL function\n");
293
294         pr_stack[pr_depth].s = pr_xstatement;
295         pr_stack[pr_depth].f = pr_xfunction;
296         pr_depth++;
297         if (pr_depth >= MAX_STACK_DEPTH)
298                 Host_Error ("stack overflow");
299
300 // save off any locals that the new function steps on
301         c = f->locals;
302         if (localstack_used + c > LOCALSTACK_SIZE)
303                 Host_Error ("PR_ExecuteProgram: locals stack overflow\n");
304
305         for (i=0 ; i < c ; i++)
306                 localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
307         localstack_used += c;
308
309 // copy parameters
310         o = f->parm_start;
311         for (i=0 ; i<f->numparms ; i++)
312         {
313                 for (j=0 ; j<f->parm_size[i] ; j++)
314                 {
315                         ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];
316                         o++;
317                 }
318         }
319
320         pr_xfunction = f;
321         return f->first_statement - 1;  // offset the s++
322 }
323
324 /*
325 ====================
326 PR_LeaveFunction
327 ====================
328 */
329 int PR_LeaveFunction (void)
330 {
331         int             i, c;
332
333         if (pr_depth <= 0)
334                 Host_Error ("prog stack underflow");
335
336         if (!pr_xfunction)
337                 Host_Error ("PR_LeaveFunction: NULL function\n");
338 // restore locals from the stack
339         c = pr_xfunction->locals;
340         localstack_used -= c;
341         if (localstack_used < 0)
342                 Host_Error ("PR_ExecuteProgram: locals stack underflow\n");
343
344         for (i=0 ; i < c ; i++)
345                 ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
346
347 // up stack
348         pr_depth--;
349         pr_xfunction = pr_stack[pr_depth].f;
350         return pr_stack[pr_depth].s;
351 }
352
353 void PR_ReInitStrings (void);
354 void PR_Execute_ProgsLoaded(void)
355 {
356         // dump the stack
357         pr_depth = 0;
358         localstack_used = 0;
359         // reset the string table
360         PR_ReInitStrings();
361 }
362
363 /*
364 ====================
365 PR_ExecuteProgram
366 ====================
367 */
368 // LordHavoc: optimized
369 #define OPA ((eval_t *)&pr_globals[(unsigned short) st->a])
370 #define OPB ((eval_t *)&pr_globals[(unsigned short) st->b])
371 #define OPC ((eval_t *)&pr_globals[(unsigned short) st->c])
372 extern cvar_t pr_boundscheck;
373 extern cvar_t pr_traceqc;
374 void PR_ExecuteProgram (func_t fnum, const char *errormessage)
375 {
376         dstatement_t    *st;
377         mfunction_t     *f, *newf;
378         edict_t *ed;
379         eval_t  *ptr;
380         int             profile, startprofile, cachedpr_trace, exitdepth;
381
382         if (!fnum || fnum >= progs->numfunctions)
383         {
384                 if (pr_global_struct->self)
385                         ED_Print (PROG_TO_EDICT(pr_global_struct->self));
386                 Host_Error ("PR_ExecuteProgram: %s", errormessage);
387         }
388
389         f = &pr_functions[fnum];
390
391         pr_trace = pr_traceqc.integer;
392
393         // we know we're done when pr_depth drops to this
394         exitdepth = pr_depth;
395
396 // make a stack frame
397         st = &pr_statements[PR_EnterFunction (f)];
398         startprofile = profile = 0;
399
400 chooseexecprogram:
401         cachedpr_trace = pr_trace;
402         if (pr_boundscheck.integer)
403         {
404 #define PRBOUNDSCHECK 1
405                 if (pr_trace)
406                 {
407 #define PRTRACE 1
408 #include "pr_execprogram.h"
409                 }
410                 else
411                 {
412 #undef PRTRACE
413 #include "pr_execprogram.h"
414                 }
415         }
416         else
417         {
418 #undef PRBOUNDSCHECK
419                 if (pr_trace)
420                 {
421 #define PRTRACE 1
422 #include "pr_execprogram.h"
423                 }
424                 else
425                 {
426 #undef PRTRACE
427 #include "pr_execprogram.h"
428                 }
429         }
430 }
431
432 void PR_ReInitStrings (void)
433 {
434 }