]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_execprogram.h
Merge branch 'master' into blub/dp1
[divverent/darkplaces.git] / prvm_execprogram.h
1 #undef RUNAWAYCHECK
2 #undef GLOBALSIZE
3 #undef PTR_GBL
4 #undef PTR_FLD
5 #undef PTR_STR
6 #undef PTR_MEM
7 #undef PTR_ISGBL
8 #undef PTR_ISFLD
9 #undef PTR_ISSTR
10 #undef PTR_ISMEM
11 #undef PTR_VALUE
12 #undef PTR_ISVALID
13 #undef PTR_ptr
14 #undef PTR_ptr2
15 #undef PTR_ptr3
16
17 #if PRVMRUNAWAYCHECK
18 #  define RUNAWAYCHECK()                                                \
19         do {                                                            \
20                 if (++jumpcount == 10000000)                            \
21                 {                                                       \
22                         prog->xstatement = st - prog->statements;       \
23                         PRVM_Profile(1<<30, 1000000, 0);                        \
24                         PRVM_ERROR("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", PRVM_NAME, jumpcount); \
25                 }                                                       \
26         } while(0)
27 #else
28 #    define RUNAWAYCHECK()
29 #endif
30 #define GLOBALSIZE ((signed)sizeof(*prog->globals.generic)*prog->progs->numglobals)
31
32 // TODO: (64bit)
33 // 0x3fffffffffffffff
34 // ~(3 << 62)
35 #define PTR_VALUE(x) ((unsigned int)(x) & 0x3FFFFFFF)
36
37 // Pointer:
38 // [type: 2 bits] [value: 30 bits]
39 // types:
40 //   0  -  Entity field area
41 //   1  -  Global area
42 //   2  -  Malloc()ed area
43
44 // TODO: (64 bit)
45 // s/30/62/ in the following lines:
46 #define PTR_FLD(x)   (PTR_VALUE(x))
47 #define PTR_ISFLD(x) ( ((x)>>30) == 0 )
48
49 #define PTR_GBL(x)   (PTR_VALUE(x) | (1<<30))
50 #define PTR_ISGBL(x) ( ((x)>>30) == 1 )
51
52 #define PTR_MEM(x)   (PTR_VALUE(x) | (2<<30))
53 #define PTR_ISMEM(x) ( ((x)>>30) == 2 )
54
55 #define PTR_size (signed)sizeof(int)
56
57 #define PTR_ISVALID(x)                                                  \
58         (                                                               \
59         ptrvalA = ((int *)(x) - (int *)prog->edictsfields),             \
60         ptrvalB = ((int *)(x) - (int *)prog->globals.generic),          \
61         ptrvalC = ((int *)(x) - (int *)/* TODO: fill in memory area*/ 0), \
62         (ptrvalA >= 0 && ptrvalA + 1 <= prog->entityfieldsarea) ? 1 : \
63         (ptrvalB >= 0 && ptrvalB + 1 <= GLOBALSIZE) ? 1 :       \
64         (ptrvalC >= 0 && ptrvalC + 1 <= /* TODO: fill in memory area size */0) ? 1 : \
65         0 )
66 // well, the last change removed all #ifs - I'll still keep them
67 #define PRVMBOUNDSCHECK 1
68 #if PRVMBOUNDSCHECK
69 #define PTR_ptr3(from, off, access)                                     \
70         if (PTR_ISGBL(from))                                            \
71         {                                                               \
72                 ptrval_t p = PTR_VALUE(from) + (off);                   \
73                 if (p < 0 || p + (access)*PTR_size > GLOBALSIZE) \
74                 {                                                       \
75                         prog->xfunction->profile += (st - startst);     \
76                         prog->xstatement = st - prog->statements;       \
77                         PRVM_ERROR("%s attempted to access an out of bounds global (%i)", PRVM_NAME, (int)p);   \
78                         goto cleanup;                                   \
79                 }                                                       \
80                 ptr = (prvm_eval_t*)((int *)prog->globals.generic + p); \
81         }                                                               \
82         else if (PTR_ISMEM(from))                                       \
83         {                                                               \
84                 ptrval_t p = PTR_VALUE(from) + (off);                   \
85                 if (p < 0 || p + (access)*PTR_size > 0 /* TODO: FILL IN */) \
86                 {                                                       \
87                         prog->xfunction->profile += (st - startst);     \
88                         prog->xstatement = st - prog->statements;       \
89                         PRVM_ERROR("%s attempted to access out of bounds memory (%i)", PRVM_NAME, (int)p); \
90                         goto cleanup;                                   \
91                 }                                                       \
92                 ptr = (prvm_eval_t*)((int *)0 /* TODO: FILL IN*/ + p /* TODO: REMOVE: */ * 0); \
93         }                                                               \
94         else                                                            \
95         {                                                               \
96                 ptrval_t p = PTR_VALUE(from) + (off);                   \
97                 if (p < 0 || p + (access)*PTR_size > prog->entityfieldsarea) \
98                 {                                                       \
99                         prog->xfunction->profile += (st - startst);     \
100                         prog->xstatement = st - prog->statements;       \
101                         PRVM_ERROR("%s attempted to access an out of bounds edict field (%i)", PRVM_NAME, (int)p); \
102                         goto cleanup;                                   \
103                 }                                                       \
104                 ptr = (prvm_eval_t*)((int *)prog->edictsfields + p);    \
105                 if (p < prog->progs->entityfields && !prog->allowworldwrites) \
106                         Con_DPrintf("WARNING: assignment to world.%s (field %i) in %s\n", PRVM_GetString(PRVM_ED_FieldAtOfs(p)->s_name), (int)p, PRVM_NAME); \
107         }
108 #else
109
110 #define PTR_ptr3(from, off, access)                                             \
111         if (PTR_ISGBL(from))                                            \
112         {                                                               \
113                 ptrval_t p = PTR_VALUE(from) + (off);                   \
114                 ptr = (prvm_eval_t *)((int*)prog->globals.generic + p); \
115         }                                                               \
116         else if (PTR_ISMEM(from))                                       \
117         {                                                               \
118                 ptrval_t p = PTR_VALUE(from) + (off);                   \
119                 ptr = (prvm_eval_t *)((int*)0 /* TODO: FILL IN*/ + p /* TODO: REMOVE: */ * 0); \
120         }                                                               \
121         else                                                            \
122         {                                                               \
123                 ptrval_t p = PTR_VALUE(from) + (off);                   \
124                 ptr = (prvm_eval_t *)((int*)prog->edictsfields + p);    \
125         }
126 #endif
127 #define PTR_ptr2(from, off) PTR_ptr3(from, off, 1)
128 #define PTR_ptr(from) PTR_ptr3(from, 0, 1)
129
130 typedef long ptrval_t;
131
132 // This code isn't #ifdef/#define protectable, don't try.
133 prvm_eval_t *swtch = NULL;
134 int swtchtype = 0;
135 ptrval_t ptrvalA, ptrvalB, ptrvalC;
136 ptrvalA = 0; // get rid of the unused-warning for now
137 ptrvalB = 0;
138 ptrvalC = 0;
139                 while (1)
140                 {
141                         st++;
142
143 #if PRVMSLOWINTERPRETER
144                         if (prog->trace)
145                                 PRVM_PrintStatement(st);
146                         prog->statement_profile[st - prog->statements]++;
147 #endif
148
149                         switch (st->op)
150                         {
151                         case OP_ADD_F:
152                                 OPC->_float = OPA->_float + OPB->_float;
153                                 break;
154                         case OP_ADD_V:
155                                 OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
156                                 OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
157                                 OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
158                                 break;
159                         case OP_SUB_F:
160                                 OPC->_float = OPA->_float - OPB->_float;
161                                 break;
162                         case OP_SUB_V:
163                                 OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
164                                 OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
165                                 OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
166                                 break;
167                         case OP_MUL_F:
168                                 OPC->_float = OPA->_float * OPB->_float;
169                                 break;
170                         case OP_MUL_V:
171                                 OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
172                                 break;
173                         case OP_MUL_FV:
174                                 OPC->vector[0] = OPA->_float * OPB->vector[0];
175                                 OPC->vector[1] = OPA->_float * OPB->vector[1];
176                                 OPC->vector[2] = OPA->_float * OPB->vector[2];
177                                 break;
178                         case OP_MUL_VF:
179                                 OPC->vector[0] = OPB->_float * OPA->vector[0];
180                                 OPC->vector[1] = OPB->_float * OPA->vector[1];
181                                 OPC->vector[2] = OPB->_float * OPA->vector[2];
182                                 break;
183                         case OP_DIV_F:
184                                 if( OPB->_float != 0.0f )
185                                 {
186                                         OPC->_float = OPA->_float / OPB->_float;
187                                 }
188                                 else
189                                 {
190                                         if (developer.integer)
191                                         {
192                                                 prog->xfunction->profile += (st - startst);
193                                                 startst = st;
194                                                 prog->xstatement = st - prog->statements;
195                                                 VM_Warning( "Attempted division by zero in %s\n", PRVM_NAME );
196                                         }
197                                         OPC->_float = 0.0f;
198                                 }
199                                 break;
200                         case OP_BITAND:
201                                 OPC->_float = (int)OPA->_float & (int)OPB->_float;
202                                 break;
203                         case OP_BITOR:
204                                 OPC->_float = (int)OPA->_float | (int)OPB->_float;
205                                 break;
206                         case OP_GE:
207                                 OPC->_float = OPA->_float >= OPB->_float;
208                                 break;
209                         case OP_LE:
210                                 OPC->_float = OPA->_float <= OPB->_float;
211                                 break;
212                         case OP_GT:
213                                 OPC->_float = OPA->_float > OPB->_float;
214                                 break;
215                         case OP_LT:
216                                 OPC->_float = OPA->_float < OPB->_float;
217                                 break;
218                         case OP_AND:
219                                 OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) && FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add AND_I to be used by fteqcc for anything not a float
220                                 break;
221                         case OP_OR:
222                                 OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) || FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add OR_I to be used by fteqcc for anything not a float
223                                 break;
224                         case OP_NOT_F:
225                                 OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int);
226                                 break;
227                         case OP_NOT_V:
228                                 OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
229                                 break;
230                         case OP_NOT_S:
231                                 OPC->_float = !OPA->string || !*PRVM_GetString(OPA->string);
232                                 break;
233                         case OP_NOT_FNC:
234                                 OPC->_float = !OPA->function;
235                                 break;
236                         case OP_NOT_ENT:
237                                 OPC->_float = (OPA->edict == 0);
238                                 break;
239                         case OP_EQ_F:
240                                 OPC->_float = OPA->_float == OPB->_float;
241                                 break;
242                         case OP_EQ_V:
243                                 OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
244                                 break;
245                         case OP_EQ_S:
246                                 OPC->_float = !strcmp(PRVM_GetString(OPA->string),PRVM_GetString(OPB->string));
247                                 break;
248                         case OP_EQ_E:
249                                 OPC->_float = OPA->_int == OPB->_int;
250                                 break;
251                         case OP_EQ_FNC:
252                                 OPC->_float = OPA->function == OPB->function;
253                                 break;
254                         case OP_NE_F:
255                                 OPC->_float = OPA->_float != OPB->_float;
256                                 break;
257                         case OP_NE_V:
258                                 OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
259                                 break;
260                         case OP_NE_S:
261                                 OPC->_float = strcmp(PRVM_GetString(OPA->string),PRVM_GetString(OPB->string));
262                                 break;
263                         case OP_NE_E:
264                                 OPC->_float = OPA->_int != OPB->_int;
265                                 break;
266                         case OP_NE_FNC:
267                                 OPC->_float = OPA->function != OPB->function;
268                                 break;
269
270                 //==================
271                         case OP_STORE_F:
272                         case OP_STORE_ENT:
273                         case OP_STORE_FLD:              // integers
274                         case OP_STORE_S:
275                         case OP_STORE_FNC:              // pointers
276                         case OP_STORE_P:
277                         case OP_STORE_I:
278                                 OPB->_int = OPA->_int;
279                                 break;
280                         case OP_STORE_V:
281                                 OPB->ivector[0] = OPA->ivector[0];
282                                 OPB->ivector[1] = OPA->ivector[1];
283                                 OPB->ivector[2] = OPA->ivector[2];
284                                 break;
285
286                         case OP_STOREP_F:
287                         case OP_STOREP_ENT:
288                         case OP_STOREP_FLD:             // integers
289                         case OP_STOREP_S:
290                         case OP_STOREP_FNC:             // pointers
291                         case OP_STOREP_P:
292                                 PTR_ptr(OPB->_int);
293                                 ptr->_int = OPA->_int;
294                                 break;
295                         case OP_STOREP_V:
296                                 PTR_ptr3(OPB->_int, 0, 3);
297                                 ptr->ivector[0] = OPA->ivector[0];
298                                 ptr->ivector[1] = OPA->ivector[1];
299                                 ptr->ivector[2] = OPA->ivector[2];
300                                 break;
301
302                         case OP_ADDRESS:
303                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
304                                 {
305                                         prog->xfunction->profile += (st - startst);
306                                         prog->xstatement = st - prog->statements;
307                                         PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
308                                         goto cleanup;
309                                 }
310                                 if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
311                                 {
312                                         prog->xfunction->profile += (st - startst);
313                                         prog->xstatement = st - prog->statements;
314                                         PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int);
315                                         goto cleanup;
316                                 }
317 #if 0
318                                 if (OPA->edict == 0 && !prog->allowworldwrites)
319                                 {
320                                         prog->xfunction->profile += (st - startst);
321                                         prog->xstatement = st - prog->statements;
322                                         PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME);
323                                         goto cleanup;
324                                 }
325 #endif
326                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
327                                 OPC->_int = PTR_FLD(((int *)ed->fields.vp + OPB->_int) - (int *)prog->edictsfields);
328                                 break;
329
330                         case OP_LOAD_F:
331                         case OP_LOAD_FLD:
332                         case OP_LOAD_ENT:
333                         case OP_LOAD_S:
334                         case OP_LOAD_FNC:
335                         case OP_LOAD_P:
336 #if PRVMBOUNDSCHECK
337                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
338                                {
339                                        prog->xfunction->profile += (st - startst);
340                                        prog->xstatement = st - prog->statements;
341                                        PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
342                                        goto cleanup;
343                                }
344                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
345                                {
346                                        prog->xfunction->profile += (st - startst);
347                                        prog->xstatement = st - prog->statements;
348                                        PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
349                                        goto cleanup;
350                                }
351 #endif
352                                ed = PRVM_PROG_TO_EDICT(OPA->edict);
353                                OPC->_int = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->_int;
354                                break;
355
356                        case OP_LOAD_V:
357 #if PRVMBOUNDSCHECK
358                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
359                                {
360                                        prog->xfunction->profile += (st - startst);
361                                        prog->xstatement = st - prog->statements;
362                                        PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
363                                        goto cleanup;
364                                }
365                                if (OPB->_int < 0 || OPB->_int + 2 >= prog->progs->entityfields)
366                                {
367                                        prog->xfunction->profile += (st - startst);
368                                        prog->xstatement = st - prog->statements;
369                                        PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
370                                        goto cleanup;
371                                }
372 #endif
373                                ed = PRVM_PROG_TO_EDICT(OPA->edict);
374                                OPC->ivector[0] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[0];
375                                OPC->ivector[1] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[1];
376                                OPC->ivector[2] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[2];
377                                break;
378
379                //==================
380
381                        case OP_IFNOT:
382                                if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int))
383                                // TODO add an "int-if", and change this one to OPA->_float
384                                // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
385                                // and entity, string, field values can never have that value
386                                {
387                                        prog->xfunction->profile += (st - startst);
388                                        st += st->b - 1;        // offset the s++
389                                        startst = st;
390                                                                                
391                                        // no bounds check needed, it is done when loading progs
392                                         RUNAWAYCHECK();
393                                 }
394                                 break;
395
396                         case OP_IF:
397                                 if(FLOAT_IS_TRUE_FOR_INT(OPA->_int))
398                                 // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float
399                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
400                                 // and entity, string, field values can never have that value
401                                 {
402                                         prog->xfunction->profile += (st - startst);
403                                         st += st->b - 1;        // offset the s++
404                                         startst = st;
405                                         RUNAWAYCHECK();
406                                 }
407                                 break;
408
409                         case OP_IFNOT_F:
410                                 if (!OPA->_float)
411                                 {
412                                         prog->xfunction->profile += (st - startst);
413                                         st += st->b - 1;        // offset the s++
414                                         startst = st;
415                                         RUNAWAYCHECK();
416                                 }
417                                 break;
418
419                         case OP_IF_F:
420                                 if (OPA->_float)
421                                 {
422                                         prog->xfunction->profile += (st - startst);
423                                         st += st->b - 1;        // offset the s++
424                                         startst = st;
425                                         // no bounds check needed, it is done when loading progs
426                                         RUNAWAYCHECK();
427                                 }
428                                 break;
429
430                         case OP_GOTO:
431                                 prog->xfunction->profile += (st - startst);
432                                 st += st->a - 1;        // offset the s++
433                                 startst = st;
434                                 // no bounds check needed, it is done when loading progs
435                                 RUNAWAYCHECK();
436                                 break;
437
438                                 // CALLxH used and tested, they do work!
439                         case OP_CALL8H:
440                         case OP_CALL7H:
441                         case OP_CALL6H:
442                         case OP_CALL5H:
443                         case OP_CALL4H:
444                         case OP_CALL3H:
445                         case OP_CALL2H:
446                                 PRVM_G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
447                                 PRVM_G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
448                                 PRVM_G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
449                         case OP_CALL1H:
450                                 PRVM_G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
451                                 PRVM_G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
452                                 PRVM_G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
453                                 // fall through
454                         case OP_CALL0:
455                         case OP_CALL1:
456                         case OP_CALL2:
457                         case OP_CALL3:
458                         case OP_CALL4:
459                         case OP_CALL5:
460                         case OP_CALL6:
461                         case OP_CALL7:
462                         case OP_CALL8:
463                                 prog->xfunction->profile += (st - startst);
464                                 startst = st;
465                                 prog->xstatement = st - prog->statements;
466                                 // handle CALLxH too
467                                 if (st->op >= OP_CALL1H && st->op <= OP_CALL8H)
468                                         prog->argc = st->op - (OP_CALL1H-1);
469                                 else
470                                         prog->argc = st->op - OP_CALL0;
471                                 if (!OPA->function)
472                                         PRVM_ERROR("NULL function in %s", PRVM_NAME);
473
474                                 if(!OPA->function || OPA->function >= (unsigned int)prog->progs->numfunctions)
475                                 {
476                                         prog->xfunction->profile += (st - startst);
477                                         prog->xstatement = st - prog->statements; // we better stay on the previously executed statement
478                                         PRVM_ERROR("%s CALL outside the program", PRVM_NAME);
479                                         goto cleanup;
480                                 }
481
482                                 newf = &prog->functions[OPA->function];
483                                 newf->callcount++;
484
485                                 if (newf->first_statement < 0)
486                                 {
487                                         // negative statements are built in functions
488                                         int builtinnumber = -newf->first_statement;
489                                         prog->xfunction->builtinsprofile++;
490                                         if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
491                                                 prog->builtins[builtinnumber]();
492                                         else
493                                                 PRVM_ERROR("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, PRVM_NAME);
494                                 }
495                                 else
496                                         st = prog->statements + PRVM_EnterFunction(newf);
497                                 startst = st;
498                                 break;
499
500                         case OP_DONE:
501                         case OP_RETURN:
502                                 prog->xfunction->profile += (st - startst);
503                                 prog->xstatement = st - prog->statements;
504
505                                 prog->globals.generic[OFS_RETURN] = prog->globals.generic[(unsigned short) st->a];
506                                 prog->globals.generic[OFS_RETURN+1] = prog->globals.generic[(unsigned short) st->a+1];
507                                 prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[(unsigned short) st->a+2];
508
509                                 st = prog->statements + PRVM_LeaveFunction();
510                                 startst = st;
511                                 if (prog->depth <= exitdepth)
512                                         goto cleanup; // all done
513                                 if (prog->trace != cachedpr_trace)
514                                         goto chooseexecprogram;
515                                 break;
516
517                         case OP_STATE:
518                                 if(prog->flag & PRVM_OP_STATE)
519                                 {
520                                         ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
521                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.nextthink)->_float = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float + 0.1;
522                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.frame)->_float = OPA->_float;
523                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.think)->function = OPB->function;
524                                 }
525                                 else
526                                 {
527                                         prog->xfunction->profile += (st - startst);
528                                         prog->xstatement = st - prog->statements;
529                                         PRVM_ERROR("OP_STATE not supported by %s", PRVM_NAME);
530                                 }
531                                 break;
532
533 // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
534
535                         case OP_ADD_I:
536                                 OPC->_int = OPA->_int + OPB->_int;
537                                 break;
538                         case OP_ADD_IF:
539                                 OPC->_int = OPA->_int + (int) OPB->_float;
540                                 break;
541                         case OP_ADD_FI:
542                                 OPC->_float = OPA->_float + (float) OPB->_int;
543                                 break;
544                         case OP_SUB_I:
545                                 OPC->_int = OPA->_int - OPB->_int;
546                                 break;
547                         case OP_SUB_IF:
548                                 OPC->_int = OPA->_int - (int) OPB->_float;
549                                 break;
550                         case OP_SUB_FI:
551                                 OPC->_float = OPA->_float - (float) OPB->_int;
552                                 break;
553                         case OP_MUL_I:
554                                 OPC->_int = OPA->_int * OPB->_int;
555                                 break;
556                         case OP_MUL_IF:
557                                 OPC->_int = OPA->_int * (int) OPB->_float;
558                                 break;
559                         case OP_MUL_FI:
560                                 OPC->_float = OPA->_float * (float) OPB->_int;
561                                 break;
562                         case OP_MUL_VI:
563                                 OPC->vector[0] = (float) OPB->_int * OPA->vector[0];
564                                 OPC->vector[1] = (float) OPB->_int * OPA->vector[1];
565                                 OPC->vector[2] = (float) OPB->_int * OPA->vector[2];
566                                 break;
567                         case OP_DIV_VF:
568                                 {
569                                         float temp = 1.0f / OPB->_float;
570                                         OPC->vector[0] = temp * OPA->vector[0];
571                                         OPC->vector[1] = temp * OPA->vector[1];
572                                         OPC->vector[2] = temp * OPA->vector[2];
573                                 }
574                                 break;
575                         case OP_DIV_I:
576                                 OPC->_int = OPA->_int / OPB->_int;
577                                 break;
578                         case OP_DIV_IF:
579                                 OPC->_int = OPA->_int / (int) OPB->_float;
580                                 break;
581                         case OP_DIV_FI:
582                                 OPC->_float = OPA->_float / (float) OPB->_int;
583                                 break;
584                         case OP_STORE_IF:
585                                 OPB->_float = OPA->_int;
586                                 break;
587                         case OP_STORE_FI:
588                                 OPB->_int = OPA->_float;
589                                 break;
590                         case OP_BITAND_I:
591                                 OPC->_int = OPA->_int & OPB->_int;
592                                 break;
593                         case OP_BITOR_I:
594                                 OPC->_int = OPA->_int | OPB->_int;
595                                 break;
596                         case OP_BITAND_IF:
597                                 OPC->_int = OPA->_int & (int)OPB->_float;
598                                 break;
599                         case OP_BITOR_IF:
600                                 OPC->_int = OPA->_int | (int)OPB->_float;
601                                 break;
602                         case OP_BITAND_FI:
603                                 OPC->_float = (int)OPA->_float & OPB->_int;
604                                 break;
605                         case OP_BITOR_FI:
606                                 OPC->_float = (int)OPA->_float | OPB->_int;
607                                 break;
608                         case OP_GE_I:
609                                 OPC->_float = OPA->_int >= OPB->_int;
610                                 break;
611                         case OP_LE_I:
612                                 OPC->_float = OPA->_int <= OPB->_int;
613                                 break;
614                         case OP_GT_I:
615                                 OPC->_float = OPA->_int > OPB->_int;
616                                 break;
617                         case OP_LT_I:
618                                 OPC->_float = OPA->_int < OPB->_int;
619                                 break;
620                         case OP_AND_I:
621                                 OPC->_float = OPA->_int && OPB->_int;
622                                 break;
623                         case OP_OR_I:
624                                 OPC->_float = OPA->_int || OPB->_int;
625                                 break;
626                         case OP_GE_IF:
627                                 OPC->_float = (float)OPA->_int >= OPB->_float;
628                                 break;
629                         case OP_LE_IF:
630                                 OPC->_float = (float)OPA->_int <= OPB->_float;
631                                 break;
632                         case OP_GT_IF:
633                                 OPC->_float = (float)OPA->_int > OPB->_float;
634                                 break;
635                         case OP_LT_IF:
636                                 OPC->_float = (float)OPA->_int < OPB->_float;
637                                 break;
638                         case OP_AND_IF:
639                                 OPC->_float = (float)OPA->_int && OPB->_float;
640                                 break;
641                         case OP_OR_IF:
642                                 OPC->_float = (float)OPA->_int || OPB->_float;
643                                 break;
644                         case OP_GE_FI:
645                                 OPC->_float = OPA->_float >= (float)OPB->_int;
646                                 break;
647                         case OP_LE_FI:
648                                 OPC->_float = OPA->_float <= (float)OPB->_int;
649                                 break;
650                         case OP_GT_FI:
651                                 OPC->_float = OPA->_float > (float)OPB->_int;
652                                 break;
653                         case OP_LT_FI:
654                                 OPC->_float = OPA->_float < (float)OPB->_int;
655                                 break;
656                         case OP_AND_FI:
657                                 OPC->_float = OPA->_float && (float)OPB->_int;
658                                 break;
659                         case OP_OR_FI:
660                                 OPC->_float = OPA->_float || (float)OPB->_int;
661                                 break;
662                         case OP_NOT_I:
663                                 OPC->_float = !OPA->_int;
664                                 break;
665                         case OP_EQ_I:
666                                 OPC->_float = OPA->_int == OPB->_int;
667                                 break;
668                         case OP_EQ_IF:
669                                 OPC->_float = (float)OPA->_int == OPB->_float;
670                                 break;
671                         case OP_EQ_FI:
672                                 OPC->_float = OPA->_float == (float)OPB->_int;
673                                 break;
674                         case OP_NE_I:
675                                 OPC->_float = OPA->_int != OPB->_int;
676                                 break;
677                         case OP_NE_IF:
678                                 OPC->_float = (float)OPA->_int != OPB->_float;
679                                 break;
680                         case OP_NE_FI:
681                                 OPC->_float = OPA->_float != (float)OPB->_int;
682                                 break;
683                         case OP_STOREP_I:
684                                 PTR_ptr(OPB->_int);
685                                 ptr->_int = OPA->_int;
686                                 break;
687                         case OP_LOAD_I:
688 #if PRBOUNDSCHECK
689                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
690                                 {
691                                         prog->xfunction->profile += (st - startst);
692                                         prog->xstatement = st - prog->statements;
693                                         PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
694                                         goto cleanup;
695                                 }
696                                 if (OPB->_int < 0 || OPB->_int >= prog->progs->entityfields)
697                                 {
698                                         prog->xfunction->profile += (st - startst);
699                                         prog->xstatement = st - prog->statements;
700                                         PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME);
701                                         goto cleanup;
702                                 }
703 #endif
704                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
705                                 OPC->_int = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->_int;
706                                 break;
707                         case OP_LOADA_I:
708                         case OP_LOADA_F:
709                         case OP_LOADA_FLD:
710                         case OP_LOADA_ENT:
711                         case OP_LOADA_S:
712                         case OP_LOADA_FNC:
713                                 ptr = (prvm_eval_t *)(&OPA->_int + OPB->_int);
714 #if PRVMBOUNDSCHECK
715                                 if (!PTR_ISVALID(ptr))
716                                 {
717                                         prog->xfunction->profile += (st - startst);
718                                         prog->xstatement = st - prog->statements;
719                                         PRVM_ERROR ("%s Progs attempted to read from an out of bounds address (%i)", PRVM_NAME, OPB->_int);
720                                         goto cleanup;
721                                 }
722 #endif
723                                 OPC->_int = ptr->_int;
724                                 break;
725
726                         case OP_LOADA_V:
727                                 ptr = (prvm_eval_t *)(&OPA->_int + OPB->_int);
728 #if PRVMBOUNDSCHECK
729                                 if (!PTR_ISVALID(ptr))
730                                 {
731                                         prog->xfunction->profile += (st - startst);
732                                         prog->xstatement = st - prog->statements;
733                                         PRVM_ERROR ("%s Progs attempted to read from an out of bounds address (%i)", PRVM_NAME, OPB->_int);
734                                         goto cleanup;
735                                 }
736 #endif
737                                 OPC->vector[0] = ptr->vector[0];
738                                 OPC->vector[1] = ptr->vector[1];
739                                 OPC->vector[2] = ptr->vector[2];
740                                 break;
741                         case OP_BOUNDCHECK:
742                                 if ((unsigned int)OPA->_int < (unsigned int)st->c || (unsigned int)OPA->_int >= (unsigned int)st->b)
743                                 {
744                                         prog->xfunction->profile += (st - startst);
745                                         prog->xstatement = st - prog->statements;
746                                         PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c);
747                                         goto cleanup;
748                                 }
749                                 break;
750
751                         case OP_RAND0: // random number between 0 and 1
752                                 PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0,1);
753                                 break;
754                         case OP_RAND1: // random number between 0 and OPA
755                                 PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0,OPA->_float);
756                                 break;
757                         case OP_RAND2: // random number between OPA and OPB
758                                 if(OPA->_float < OPB->_float)
759                                         PRVM_G_FLOAT(OFS_RETURN) = lhrandom(OPA->_float, OPB->_float);
760                                 else
761                                         PRVM_G_FLOAT(OFS_RETURN) = lhrandom(OPB->_float, OPA->_float);
762                                 break;
763                         case OP_RANDV0: // random vector between 0 and 1
764                                 PRVM_G_VECTOR(OFS_RETURN)[0] = lhrandom(0,1);
765                                 PRVM_G_VECTOR(OFS_RETURN)[1] = lhrandom(0,1);
766                                 PRVM_G_VECTOR(OFS_RETURN)[2] = lhrandom(0,1);
767                                 break;
768                         case OP_RANDV1: // random vector between 0 and OPA
769                                 PRVM_G_VECTOR(OFS_RETURN)[0] = lhrandom(0,OPA->vector[0]);
770                                 PRVM_G_VECTOR(OFS_RETURN)[1] = lhrandom(0,OPA->vector[1]);
771                                 PRVM_G_VECTOR(OFS_RETURN)[2] = lhrandom(0,OPA->vector[2]);
772                                 break;
773                         case OP_RANDV2: // random vector between OPA and OPB
774                         {
775                                 int i;
776                                 for(i = 0; i < 3; ++i)
777                                 {
778                                         if(OPA->vector[i] < OPB->vector[i])
779                                                 PRVM_G_VECTOR(OFS_RETURN)[i] = lhrandom(OPA->vector[i], OPB->vector[i]);
780                                         else
781                                                 PRVM_G_VECTOR(OFS_RETURN)[i] = lhrandom(OPB->vector[i], OPA->vector[i]);
782                                 }
783                                 break;
784                         }
785
786                         case OP_SWITCH_F:
787                         case OP_SWITCH_V:
788                         case OP_SWITCH_S:
789                         case OP_SWITCH_E:
790                         case OP_SWITCH_I:
791                         case OP_SWITCH_FNC:
792                         {
793                                 swtch = OPA;
794                                 swtchtype = st->op;
795                                 RUNAWAYCHECK();
796                                 prog->xfunction->profile += (st - startst);
797                                 startst = st;
798                                 st += st->b - 1;        // offset the s++
799                                 break;
800                         }
801                         case OP_CASE:
802                         {
803                                 switch(swtchtype)
804                                 {
805                                 case OP_SWITCH_F:
806                                         if(swtch->_float == OPA->_float)
807                                         {
808                                                 RUNAWAYCHECK();
809                                                 prog->xfunction->profile += (st - startst);
810                                                 startst = st;
811                                                 st += st->b - 1;
812                                         }
813                                         break;
814                                 case OP_SWITCH_E:
815                                 case OP_SWITCH_I:
816                                 case OP_SWITCH_FNC:
817                                         if(swtch->_int == OPA->_int)
818                                         {
819                                                 RUNAWAYCHECK();
820                                                 prog->xfunction->profile += (st - startst);
821                                                 startst = st;
822                                                 st += st->b-1;
823                                         }
824                                         break;
825                                 case OP_SWITCH_S:
826                                         if(swtch->_int == OPA->_int)
827                                         {
828                                                 RUNAWAYCHECK();
829                                                 prog->xfunction->profile += (st - startst);
830                                                 startst = st;
831                                                 st += st->b-1;
832                                         }
833                                         // switch(string) case "string" ->
834                                         // one of them may be null, not both
835                                         if((!swtch->_int && PRVM_GetString(OPA->string)) || (!OPA->_int && PRVM_GetString(swtch->string)))
836                                                 break;
837                                         if(!strcmp(PRVM_GetString(swtch->string), PRVM_GetString(OPA->string)))
838                                         {
839                                                 RUNAWAYCHECK();
840                                                 prog->xfunction->profile += (st - startst);
841                                                 startst = st;
842                                                 st += st->b-1;
843                                         }
844                                         break;
845                                 case OP_SWITCH_V:
846                                         if(swtch->vector[0] == OPA->vector[0] &&
847                                            swtch->vector[1] == OPA->vector[1] &&
848                                            swtch->vector[2] == OPA->vector[2])
849                                         {
850                                                 RUNAWAYCHECK();
851                                                 prog->xfunction->profile += (st - startst);
852                                                 startst = st;
853                                                 st += st->b-1;
854                                         }
855                                         break;
856                                 default:
857                                         PRVM_ERROR("OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
858                                         break;
859                                 }
860                                 break;
861                         }
862
863                         case OP_CASERANGE:
864                                 switch(swtchtype)
865                                 {
866                                 case OP_SWITCH_F:
867                                         if(swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
868                                         {
869                                                 RUNAWAYCHECK();
870                                                 st += st->c-1;
871                                         }
872                                         break;
873                                 default:
874                                         PRVM_ERROR("OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
875                                 }
876                                 break;
877
878                         case OP_CONV_ITOF:
879                                 OPC->_float = (float)OPA->_int;
880                                 break;
881                         case OP_CONV_FTOI:
882                                 OPC->_int = (int)(OPA->_float);
883                                 break;
884                         case OP_CP_ITOF:
885                                 PTR_ptr(OPA->_int);
886                                 OPC->_float = (float)(ptr->_int);
887                                 break;
888                         case OP_CP_FTOI:
889                                 PTR_ptr(OPA->_int);
890                                 OPC->_int = (int)(ptr->_float);
891                                 break;
892
893                         case OP_ADDSTOREP_F:
894                                 PTR_ptr(OPB->_int);
895                                 OPC->_float = (ptr->_float += OPA->_float);
896                                 break;
897                         case OP_ADDSTOREP_V:
898                                 PTR_ptr3(OPB->_int, 0, 3);
899                                 OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
900                                 OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
901                                 OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
902                                 break;
903
904                         case OP_SUBSTOREP_F:
905                                 PTR_ptr(OPB->_int);
906                                 OPC->_float = (ptr->_float -= OPA->_float);
907                                 break;
908                         case OP_SUBSTOREP_V:
909                                 PTR_ptr3(OPB->_int, 0, 3);
910                                 OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
911                                 OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
912                                 OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
913                                 break;
914
915                         case OP_MULSTOREP_F:
916                                 PTR_ptr(OPB->_int);
917                                 OPC->_float = (ptr->_float *= OPA->_float);
918                                 break;
919                         case OP_MULSTOREP_V:
920                                 // e.v *= a_float!
921                                 PTR_ptr3(OPB->_int, 0, 3);
922                                 OPC->vector[0] = (ptr->vector[0] -= OPA->_float);
923                                 OPC->vector[1] = (ptr->vector[1] -= OPA->_float);
924                                 OPC->vector[2] = (ptr->vector[2] -= OPA->_float);
925                                 break;
926
927                         case OP_DIVSTOREP_F:
928                                 PTR_ptr(OPB->_int);
929                                 OPC->_float = (ptr->_float /= OPA->_float);
930                                 break;
931
932                         case OP_IFNOTS:
933                                 if(!OPA->string || !PRVM_GetString(OPA->string))
934                                         st += st->b-1;
935                                 break;
936                         case OP_IFS:
937                                 if(OPA->string && PRVM_GetString(OPA->string))
938                                         st += st->b-1;
939                                 break;
940
941                         case OP_GLOBALADDRESS:
942                                 OPC->_int = ((&(OPA->_int) + OPB->_int) - (int*)prog->globals.generic);
943 #if PRVMBOUNDSCHECK
944                                 if (OPC->_int < 0 || OPC->_int + 4 > GLOBALSIZE)
945                                 {
946                                         prog->xfunction->profile += (st - startst);
947                                         prog->xstatement = st - prog->statements;
948                                         PRVM_ERROR("%s attempted to address an invalid global (%i)", PRVM_NAME, OPC->_int);
949                                         goto cleanup;
950                                 }
951 #endif
952                                 OPC->_int = PTR_GBL(OPC->_int);
953                                 break;
954
955                         case OP_POINTER_ADD:
956                                 // NOTE: dp pointers are no pointers as in byte-offsets, but item-offsets
957                                 // so we use *1
958                                 // I hope this is never used as an optimization for "A = B + C * 4" :P
959                                 OPC->_int = OPA->_int + OPB->_int*1;
960                                 break;
961
962                         case OP_ADD_SF: //(char*)c = (char*)a + (float)b
963                                 OPC->_int = OPA->_int + (int)OPB->_float;
964                                 break;
965                         case OP_SUB_S:  //(float)c = (char*)a - (char*)b
966                                 OPC->_int = OPA->_int - OPB->_int;
967                                 break;
968
969                         case OP_LOADP_I:
970                         case OP_LOADP_F:
971                         case OP_LOADP_FLD:
972                         case OP_LOADP_ENT:
973                         case OP_LOADP_S:
974                         case OP_LOADP_FNC:
975                                 PTR_ptr2(OPA->_int, OPB->_int);
976                                 OPC->_int = ptr->_int;
977                                 break;
978                         case OP_LOADP_V:
979                                 PTR_ptr3(OPA->_int, OPB->_int, 3);
980                                 OPC->vector[0] = ptr->vector[0];
981                                 OPC->vector[1] = ptr->vector[1];
982                                 OPC->vector[2] = ptr->vector[2];
983                                 break;
984                         /*
985                         // not wanted, keeping it in this comment for now though, because...
986                         case OP_STOREP_C:
987                                 PTR_ptr(OPB->_int);
988                                 break;
989
990                         // ... because this could still be reconsidered, after all it only loads
991                         case OP_LOADP_C:
992                                 PTR_ptr2(OPA->_int, (int)OPB->_float);
993                                 OPC->_int = ptr->_int;
994                                 break;
995                         */
996
997                         case OP_XOR_I:
998                                 OPC->_int = OPA->_int ^ OPB->_int;
999                                 break;
1000                         case OP_RSHIFT_I:
1001                                 OPC->_int = OPA->_int >> OPB->_int;
1002                                 break;
1003                         case OP_LSHIFT_I:
1004                                 OPC->_int = OPA->_int << OPB->_int;
1005                                 break;
1006
1007                         // hexen2 opcodes.. afaik fteqcc shouldn't use those
1008 /*
1009                         case OP_CSTATE:
1010                                 CStateOp(prog, OPA->_float, OPB->_float, newf);
1011                                 break;
1012
1013                         case OP_CWSTATE:
1014                                 CWStateOp(prog, OPA->_float, OPB->_float, newf);
1015                                 break;
1016 */
1017                         case OP_THINKTIME:
1018                                 ThinkTimeOp(prog, PRVM_PROG_TO_EDICT(OPA->edict), OPB->_float);
1019                                 break;
1020
1021                         default:
1022                                 prog->xfunction->profile += (st - startst);
1023                                 prog->xstatement = st - prog->statements;
1024                                 // prvm_opnames
1025                                 if(st->op < OP_NUMOPS)
1026                                         PRVM_ERROR("Instruction %i: %s\n", st->op, prvm_opnames[st->op]);
1027                                 PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME);
1028                                 goto cleanup;
1029                         }
1030                 }
1031