reset stack position when new progs loaded, or error occurs
[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         dfunction_t             *f;
28 } prstack_t;
29
30 #define MAX_STACK_DEPTH         32
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 qboolean        pr_trace;
40 dfunction_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         dfunction_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_strings + f->s_file, pr_strings + 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         dfunction_t     *f, *best;
214         int                     max;
215         int                     num;
216         int                     i;
217
218         num = 0;
219         do
220         {
221                 max = 0;
222                 best = NULL;
223                 for (i=0 ; i<progs->numfunctions ; i++)
224                 {
225                         f = &pr_functions[i];
226                         if (f->profile > max)
227                         {
228                                 max = f->profile;
229                                 best = f;
230                         }
231                 }
232                 if (best)
233                 {
234                         if (num < 10)
235                                 Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name);
236                         num++;
237                         best->profile = 0;
238                 }
239         } while (best);
240 }
241
242
243 /*
244 ============
245 PR_RunError
246
247 Aborts the currently executing function
248 ============
249 */
250 void PR_RunError (char *error, ...)
251 {
252         int                     i;
253         va_list         argptr;
254         char            string[1024];
255
256         va_start (argptr,error);
257         vsprintf (string,error,argptr);
258         va_end (argptr);
259
260         if (pr_xfunction)
261         {
262                 for (i = -4;i <= 0;i++)
263                         if (pr_xstatement + i >= pr_xfunction->first_statement)
264                                 PR_PrintStatement (pr_statements + pr_xstatement + i);
265         }
266         else
267                 Con_Printf("null function executing??\n");
268         PR_StackTrace ();
269         Con_Printf ("%s\n", string);
270
271         // dump the stack so host_error can shutdown functions
272         pr_depth = 0;
273         localstack_used = 0;
274
275         Host_Error ("Program error");
276 }
277
278 /*
279 ============================================================================
280 PR_ExecuteProgram
281
282 The interpretation main loop
283 ============================================================================
284 */
285
286 /*
287 ====================
288 PR_EnterFunction
289
290 Returns the new program statement counter
291 ====================
292 */
293 int PR_EnterFunction (dfunction_t *f)
294 {
295         int             i, j, c, o;
296
297         if (!f)
298                 PR_RunError ("PR_EnterFunction: NULL function\n");
299
300         pr_stack[pr_depth].s = pr_xstatement;
301         pr_stack[pr_depth].f = pr_xfunction;
302         pr_depth++;
303         if (pr_depth >= MAX_STACK_DEPTH)
304                 PR_RunError ("stack overflow");
305
306 // save off any locals that the new function steps on
307         c = f->locals;
308         if (localstack_used + c > LOCALSTACK_SIZE)
309                 PR_RunError ("PR_ExecuteProgram: locals stack overflow\n");
310
311         for (i=0 ; i < c ; i++)
312                 localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
313         localstack_used += c;
314
315 // copy parameters
316         o = f->parm_start;
317         for (i=0 ; i<f->numparms ; i++)
318         {
319                 for (j=0 ; j<f->parm_size[i] ; j++)
320                 {
321                         ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];
322                         o++;
323                 }
324         }
325
326         pr_xfunction = f;
327         return f->first_statement - 1;  // offset the s++
328 }
329
330 /*
331 ====================
332 PR_LeaveFunction
333 ====================
334 */
335 int PR_LeaveFunction (void)
336 {
337         int             i, c;
338
339         if (pr_depth <= 0)
340                 Host_Error ("prog stack underflow");
341
342         if (!pr_xfunction)
343                 PR_RunError ("PR_LeaveFunction: NULL function\n");
344 // restore locals from the stack
345         c = pr_xfunction->locals;
346         localstack_used -= c;
347         if (localstack_used < 0)
348                 PR_RunError ("PR_ExecuteProgram: locals stack underflow\n");
349
350         for (i=0 ; i < c ; i++)
351                 ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
352
353 // up stack
354         pr_depth--;
355         pr_xfunction = pr_stack[pr_depth].f;
356         return pr_stack[pr_depth].s;
357 }
358
359 void PR_Execute_ProgsLoaded(void)
360 {
361         // dump the stack
362         pr_depth = 0;
363         localstack_used = 0;
364 }
365
366 /*
367 ====================
368 PR_ExecuteProgram
369 ====================
370 */
371 // LordHavoc: optimized
372 #define OPA ((eval_t *)&pr_globals[(unsigned short) st->a])
373 #define OPB ((eval_t *)&pr_globals[(unsigned short) st->b])
374 #define OPC ((eval_t *)&pr_globals[(unsigned short) st->c])
375 extern cvar_t pr_boundscheck;
376 void PR_ExecuteProgram (func_t fnum, char *errormessage)
377 {
378         dstatement_t    *st;
379         dfunction_t     *f, *newf;
380         edict_t *ed;
381         eval_t  *ptr;
382         int             profile, startprofile, cachedpr_trace, exitdepth;
383
384         if (!fnum || fnum >= progs->numfunctions)
385         {
386                 if (pr_global_struct->self)
387                         ED_Print (PROG_TO_EDICT(pr_global_struct->self));
388                 Host_Error ("PR_ExecuteProgram: %s", errormessage);
389         }
390
391         f = &pr_functions[fnum];
392
393         pr_trace = false;
394
395         // we know we're done when pr_depth drops to this
396         exitdepth = pr_depth;
397
398 // make a stack frame
399         st = &pr_statements[PR_EnterFunction (f)];
400         startprofile = profile = 0;
401
402 chooseexecprogram:
403         cachedpr_trace = pr_trace;
404         if (pr_boundscheck.integer)
405         {
406 #define PRBOUNDSCHECK 1
407                 if (pr_trace)
408                 {
409 #define PRTRACE 1
410 #include "pr_execprogram.h"
411                 }
412                 else
413                 {
414 #undef PRTRACE
415 #include "pr_execprogram.h"
416                 }
417         }
418         else
419         {
420 #undef PRBOUNDSCHECK
421                 if (pr_trace)
422                 {
423 #define PRTRACE 1
424 #include "pr_execprogram.h"
425                 }
426                 else
427                 {
428 #undef PRTRACE
429 #include "pr_execprogram.h"
430                 }
431         }
432 }
433