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