]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_exec.c
changed Sys_Sleep from (void) to (int milliseconds), now wastes a lot less cpu time...
[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
247 void PR_Crash(void)
248 {
249         int i;
250         if (pr_depth < 1)
251         {
252                 // kill the stack just to be sure
253                 pr_depth = 0;
254                 localstack_used = 0;
255                 return;
256         }
257
258         Con_Printf("QuakeC crash report:\n");
259         if (pr_xfunction)
260         {
261                 for (i = -4;i <= 0;i++)
262                         if (pr_xstatement + i >= pr_xfunction->first_statement)
263                                 PR_PrintStatement (pr_statements + pr_xstatement + i);
264         }
265         else
266                 Con_Printf("null function executing??\n");
267         PR_StackTrace ();
268
269         // dump the stack so host_error can shutdown functions
270         pr_depth = 0;
271         localstack_used = 0;
272 }
273
274 /*
275 ============================================================================
276 PR_ExecuteProgram
277
278 The interpretation main loop
279 ============================================================================
280 */
281
282 /*
283 ====================
284 PR_EnterFunction
285
286 Returns the new program statement counter
287 ====================
288 */
289 int PR_EnterFunction (mfunction_t *f)
290 {
291         int             i, j, c, o;
292
293         if (!f)
294                 Host_Error ("PR_EnterFunction: NULL function\n");
295
296         pr_stack[pr_depth].s = pr_xstatement;
297         pr_stack[pr_depth].f = pr_xfunction;
298         pr_depth++;
299         if (pr_depth >= MAX_STACK_DEPTH)
300                 Host_Error ("stack overflow");
301
302 // save off any locals that the new function steps on
303         c = f->locals;
304         if (localstack_used + c > LOCALSTACK_SIZE)
305                 Host_Error ("PR_ExecuteProgram: locals stack overflow\n");
306
307         for (i=0 ; i < c ; i++)
308                 localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
309         localstack_used += c;
310
311 // copy parameters
312         o = f->parm_start;
313         for (i=0 ; i<f->numparms ; i++)
314         {
315                 for (j=0 ; j<f->parm_size[i] ; j++)
316                 {
317                         ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];
318                         o++;
319                 }
320         }
321
322         pr_xfunction = f;
323         return f->first_statement - 1;  // offset the s++
324 }
325
326 /*
327 ====================
328 PR_LeaveFunction
329 ====================
330 */
331 int PR_LeaveFunction (void)
332 {
333         int             i, c;
334
335         if (pr_depth <= 0)
336                 Host_Error ("prog stack underflow");
337
338         if (!pr_xfunction)
339                 Host_Error ("PR_LeaveFunction: NULL function\n");
340 // restore locals from the stack
341         c = pr_xfunction->locals;
342         localstack_used -= c;
343         if (localstack_used < 0)
344                 Host_Error ("PR_ExecuteProgram: locals stack underflow\n");
345
346         for (i=0 ; i < c ; i++)
347                 ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
348
349 // up stack
350         pr_depth--;
351         pr_xfunction = pr_stack[pr_depth].f;
352         return pr_stack[pr_depth].s;
353 }
354
355 void PR_ReInitStrings (void);
356 void PR_Execute_ProgsLoaded(void)
357 {
358         // dump the stack
359         pr_depth = 0;
360         localstack_used = 0;
361         // reset the string table
362         PR_ReInitStrings();
363 }
364
365 /*
366 ====================
367 PR_ExecuteProgram
368 ====================
369 */
370 // LordHavoc: optimized
371 #define OPA ((eval_t *)&pr_globals[(unsigned short) st->a])
372 #define OPB ((eval_t *)&pr_globals[(unsigned short) st->b])
373 #define OPC ((eval_t *)&pr_globals[(unsigned short) st->c])
374 extern cvar_t pr_boundscheck;
375 extern cvar_t pr_traceqc;
376 void PR_ExecuteProgram (func_t fnum, const char *errormessage)
377 {
378         dstatement_t    *st;
379         mfunction_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 = pr_traceqc.integer;
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
434 void PR_ReInitStrings (void)
435 {
436 }