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