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