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