]> git.xonotic.org Git - xonotic/gmqcc.git/blob - execloop.h
cache filenames as such instead of using code_cachedstring
[xonotic/gmqcc.git] / execloop.h
1 #if 0
2     /* Expected variables */
3     qc_program     *prog;
4 #endif
5
6 #define OPA ( (qcany*) (prog->globals + st->o1.u1) )
7 #define OPB ( (qcany*) (prog->globals + st->o2.u1) )
8 #define OPC ( (qcany*) (prog->globals + st->o3.u1) )
9
10 #define GLOBAL(x) ( (qcany*) (prog->globals + (x)) )
11
12 /* to be consistent with current darkplaces behaviour */
13 #if !defined(FLOAT_IS_TRUE_FOR_INT)
14 #   define FLOAT_IS_TRUE_FOR_INT(x) ( (x) & 0x7FFFFFFF )
15 #endif
16
17 while (1) {
18         prog_section_function  *newf;
19         qcany          *ed;
20         qcany          *ptr;
21
22     ++st;
23
24 #if QCVM_PROFILE
25     prog->profile[st - prog->code]++;
26 #endif
27
28 #if QCVM_TRACE
29     prog_print_statement(prog, st);
30 #endif
31
32     switch (st->opcode)
33     {
34         default:
35             qcvmerror(prog, "Illegal instruction in %s\n", prog->filename);
36             goto cleanup;
37
38                 case INSTR_DONE:
39                 case INSTR_RETURN:
40                         /* TODO: add instruction count to function profile count */
41                         GLOBAL(OFS_RETURN)->ivector[0] = OPA->ivector[0];
42                         GLOBAL(OFS_RETURN)->ivector[1] = OPA->ivector[1];
43                         GLOBAL(OFS_RETURN)->ivector[2] = OPA->ivector[2];
44
45             st = prog->code + prog_leavefunction(prog);
46             if (!prog->stack_count)
47                 goto cleanup;
48
49             break;
50
51                 case INSTR_MUL_F:
52                         OPC->_float = OPA->_float * OPB->_float;
53                         break;
54                 case INSTR_MUL_V:
55                         OPC->_float = OPA->vector[0]*OPB->vector[0] +
56                                       OPA->vector[1]*OPB->vector[1] +
57                                       OPA->vector[2]*OPB->vector[2];
58                         break;
59                 case INSTR_MUL_FV:
60                         OPC->vector[0] = OPA->_float * OPB->vector[0];
61                         OPC->vector[1] = OPA->_float * OPB->vector[1];
62                         OPC->vector[2] = OPA->_float * OPB->vector[2];
63                         break;
64                 case INSTR_MUL_VF:
65                         OPC->vector[0] = OPB->_float * OPA->vector[0];
66                         OPC->vector[1] = OPB->_float * OPA->vector[1];
67                         OPC->vector[2] = OPB->_float * OPA->vector[2];
68                         break;
69                 case INSTR_DIV_F:
70                         if (OPB->_float != 0.0f)
71                                 OPC->_float = OPA->_float / OPB->_float;
72                         else
73                                 OPC->_float = 0;
74                         break;
75
76                 case INSTR_ADD_F:
77                         OPC->_float = OPA->_float + OPB->_float;
78                         break;
79                 case INSTR_ADD_V:
80                         OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
81                         OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
82                         OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
83                         break;
84                 case INSTR_SUB_F:
85                         OPC->_float = OPA->_float - OPB->_float;
86                         break;
87                 case INSTR_SUB_V:
88                         OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
89                         OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
90                         OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
91                         break;
92
93                 case INSTR_EQ_F:
94                         OPC->_float = (OPA->_float == OPB->_float);
95                         break;
96                 case INSTR_EQ_V:
97                         OPC->_float = ((OPA->vector[0] == OPB->vector[0]) &&
98                                            (OPA->vector[1] == OPB->vector[1]) &&
99                                            (OPA->vector[2] == OPB->vector[2]) );
100                         break;
101                 case INSTR_EQ_S:
102                         OPC->_float = !strcmp(prog_getstring(prog, OPA->string),
103                                               prog_getstring(prog, OPB->string));
104                         break;
105                 case INSTR_EQ_E:
106                         OPC->_float = (OPA->_int == OPB->_int);
107                         break;
108                 case INSTR_EQ_FNC:
109                         OPC->_float = (OPA->function == OPB->function);
110                         break;
111                 case INSTR_NE_F:
112                         OPC->_float = (OPA->_float != OPB->_float);
113                         break;
114                 case INSTR_NE_V:
115                         OPC->_float = ((OPA->vector[0] != OPB->vector[0]) ||
116                                        (OPA->vector[1] != OPB->vector[1]) ||
117                                        (OPA->vector[2] != OPB->vector[2]) );
118                         break;
119                 case INSTR_NE_S:
120                         OPC->_float = !!strcmp(prog_getstring(prog, OPA->string),
121                                                prog_getstring(prog, OPB->string));
122                         break;
123                 case INSTR_NE_E:
124                         OPC->_float = (OPA->_int != OPB->_int);
125                         break;
126                 case INSTR_NE_FNC:
127                         OPC->_float = (OPA->function != OPB->function);
128                         break;
129
130                 case INSTR_LE:
131                         OPC->_float = (OPA->_float <= OPB->_float);
132                         break;
133                 case INSTR_GE:
134                         OPC->_float = (OPA->_float >= OPB->_float);
135                         break;
136                 case INSTR_LT:
137                         OPC->_float = (OPA->_float < OPB->_float);
138                         break;
139                 case INSTR_GT:
140                         OPC->_float = (OPA->_float > OPB->_float);
141                         break;
142
143                 case INSTR_LOAD_F:
144                 case INSTR_LOAD_S:
145                 case INSTR_LOAD_FLD:
146                 case INSTR_LOAD_ENT:
147                 case INSTR_LOAD_FNC:
148                         if (OPA->edict < 0 || OPA->edict >= prog->entities) {
149                             qcvmerror(prog, "progs `%s` attempted to read an out of bounds entity", prog->filename);
150                                 goto cleanup;
151                         }
152                         if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields)) {
153                                 qcvmerror(prog, "prog `%s` attempted to read an invalid field from entity (%i)",
154                                           prog->filename,
155                                           OPB->_int);
156                                 goto cleanup;
157                         }
158                         ed = prog_getedict(prog, OPA->edict);
159                         OPC->_int = ((qcany*)( ((qcint*)ed) + OPB->_int ))->_int;
160                         break;
161                 case INSTR_LOAD_V:
162                         if (OPA->edict < 0 || OPA->edict >= prog->entities) {
163                             qcvmerror(prog, "progs `%s` attempted to read an out of bounds entity", prog->filename);
164                                 goto cleanup;
165                         }
166                         if (OPB->_int < 0 || OPB->_int + 3 > prog->entityfields)
167                         {
168                                 qcvmerror(prog, "prog `%s` attempted to read an invalid field from entity (%i)",
169                                           prog->filename,
170                                           OPB->_int + 2);
171                                 goto cleanup;
172                         }
173                         ed = prog_getedict(prog, OPA->edict);
174                         OPC->ivector[0] = ((qcany*)( ((qcint*)ed) + OPB->_int ))->ivector[0];
175                         OPC->ivector[1] = ((qcany*)( ((qcint*)ed) + OPB->_int ))->ivector[1];
176                         OPC->ivector[2] = ((qcany*)( ((qcint*)ed) + OPB->_int ))->ivector[2];
177                         break;
178
179                 case INSTR_ADDRESS:
180                         if (OPA->edict < 0 || OPA->edict >= prog->entities) {
181                                 qcvmerror(prog, "prog `%s` attempted to address an out of bounds entity %i", prog->filename, OPA->edict);
182                                 goto cleanup;
183                         }
184                         if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields))
185                         {
186                                 qcvmerror(prog, "prog `%s` attempted to read an invalid field from entity (%i)",
187                                           prog->filename,
188                                           OPB->_int);
189                                 goto cleanup;
190                         }
191
192                         ed = prog_getedict(prog, OPA->edict);
193                         OPC->_int = ((qcint*)ed) - prog->entitydata;
194                         OPC->_int += OPB->_int;
195                         break;
196
197                 case INSTR_STORE_F:
198                 case INSTR_STORE_S:
199                 case INSTR_STORE_ENT:
200                 case INSTR_STORE_FLD:
201                 case INSTR_STORE_FNC:
202                         OPB->_int = OPA->_int;
203                         break;
204                 case INSTR_STORE_V:
205                         OPB->ivector[0] = OPA->ivector[0];
206                         OPB->ivector[1] = OPA->ivector[1];
207                         OPB->ivector[2] = OPA->ivector[2];
208                         break;
209
210                 case INSTR_STOREP_F:
211                 case INSTR_STOREP_S:
212                 case INSTR_STOREP_ENT:
213                 case INSTR_STOREP_FLD:
214                 case INSTR_STOREP_FNC:
215                         if (OPB->_int < 0 || OPB->_int >= prog->entitydata_count) {
216                                 qcvmerror(prog, "`%s` attempted to write to an out of bounds edict (%i)", prog->filename, OPB->_int);
217                                 goto cleanup;
218                         }
219                         if (OPB->_int < prog->entityfields && !prog->allowworldwrites)
220                                 qcvmerror(prog, "`%s` tried to assign to world.%s (field %i)\n",
221                                           prog->filename,
222                                           prog_getstring(prog, prog_entfield(prog, OPB->_int)->name),
223                                           OPB->_int);
224                         ptr = (qcany*)(prog->entitydata + OPB->_int);
225                         ptr->_int = OPA->_int;
226                         break;
227                 case INSTR_STOREP_V:
228                         if (OPB->_int < 0 || OPB->_int + 2 >= prog->entitydata_count) {
229                                 qcvmerror(prog, "`%s` attempted to write to an out of bounds edict (%i)", prog->filename, OPB->_int);
230                                 goto cleanup;
231                         }
232                         if (OPB->_int < prog->entityfields && !prog->allowworldwrites)
233                                 qcvmerror(prog, "`%s` tried to assign to world.%s (field %i)\n",
234                                           prog->filename,
235                                           prog_getstring(prog, prog_entfield(prog, OPB->_int)->name),
236                                           OPB->_int);
237                         ptr = (qcany*)(prog->entitydata + OPB->_int);
238                         ptr->ivector[0] = OPA->ivector[0];
239                         ptr->ivector[1] = OPA->ivector[1];
240                         ptr->ivector[2] = OPA->ivector[2];
241                         break;
242
243                 case INSTR_NOT_F:
244                         OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int);
245                         break;
246                 case INSTR_NOT_V:
247                         OPC->_float = !OPA->vector[0] &&
248                                       !OPA->vector[1] &&
249                                       !OPA->vector[2];
250                         break;
251                 case INSTR_NOT_S:
252                         OPC->_float = !OPA->string ||
253                                       !*prog_getstring(prog, OPA->string);
254                         break;
255                 case INSTR_NOT_ENT:
256                         OPC->_float = (OPA->edict == 0);
257                         break;
258                 case INSTR_NOT_FNC:
259                         OPC->_float = !OPA->function;
260                         break;
261
262                 case INSTR_IF:
263                     /* this is consistent with darkplaces' behaviour */
264                         if(FLOAT_IS_TRUE_FOR_INT(OPA->_int))
265                         {
266                                 st += st->o2.s1 - 1;    /* offset the s++ */
267                                 if (++jumpcount >= maxjumps)
268                                         qcvmerror(prog, "`%s` hit the runaway loop counter limit of %li jumps", prog->filename, jumpcount);
269                         }
270                         break;
271                 case INSTR_IFNOT:
272                         if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int))
273                         {
274                                 st += st->o2.s1 - 1;    /* offset the s++ */
275                                 if (++jumpcount >= maxjumps)
276                                         qcvmerror(prog, "`%s` hit the runaway loop counter limit of %li jumps", prog->filename, jumpcount);
277                         }
278                         break;
279
280                 case INSTR_CALL0:
281                 case INSTR_CALL1:
282                 case INSTR_CALL2:
283                 case INSTR_CALL3:
284                 case INSTR_CALL4:
285                 case INSTR_CALL5:
286                 case INSTR_CALL6:
287                 case INSTR_CALL7:
288                 case INSTR_CALL8:
289                         prog->argc = st->opcode - INSTR_CALL0;
290                         if (!OPA->function)
291                                 qcvmerror(prog, "NULL function in `%s`", prog->filename);
292
293                         if(!OPA->function || OPA->function >= (unsigned int)prog->functions_count)
294                         {
295                                 qcvmerror(prog, "CALL outside the program in `%s`", prog->filename);
296                                 goto cleanup;
297                         }
298
299                         newf = &prog->functions[OPA->function];
300                         newf->profile++;
301
302                         prog->statement = (st - prog->code) + 1;
303
304                         if (newf->entry < 0)
305                         {
306                                 /* negative statements are built in functions */
307                                 int builtinnumber = -newf->entry;
308                                 if (builtinnumber < prog->builtins_count && prog->builtins[builtinnumber])
309                                         prog->builtins[builtinnumber](prog);
310                                 else
311                                         qcvmerror(prog, "No such builtin #%i in %s! Try updating your gmqcc sources",
312                                                   builtinnumber, prog->filename);
313                         }
314                         else
315                                 st = prog->code + prog_enterfunction(prog, newf) - 1; /* offset st++ */
316                         if (prog->vmerror)
317                                 goto cleanup;
318                         break;
319
320                 case INSTR_STATE:
321                     qcvmerror(prog, "`%s` tried to execute a STATE operation", prog->filename);
322                         break;
323
324                 case INSTR_GOTO:
325                         st += st->o1.s1 - 1;    /* offset the s++ */
326                         if (++jumpcount == 10000000)
327                                         qcvmerror(prog, "`%s` hit the runaway loop counter limit of %li jumps", prog->filename, jumpcount);
328                         break;
329
330                 case INSTR_AND:
331                         OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) &&
332                                       FLOAT_IS_TRUE_FOR_INT(OPB->_int);
333                         break;
334                 case INSTR_OR:
335                         OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) ||
336                                       FLOAT_IS_TRUE_FOR_INT(OPB->_int);
337                         break;
338
339                 case INSTR_BITAND:
340                         OPC->_float = ((int)OPA->_float) & ((int)OPB->_float);
341                         break;
342                 case INSTR_BITOR:
343                         OPC->_float = ((int)OPA->_float) | ((int)OPB->_float);
344                         break;
345     }
346 }
347
348 #undef QCVM_PROFILE
349 #undef QCVM_TRACE