]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_execprogram.h
Merge branch 'master' into 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
67 #if PRVMBOUNDSCHECK
68 #define PTR_ptr3(from, off, access)                                     \
69         if (PTR_ISGBL(from))                                            \
70         {                                                               \
71                 ptrval_t p = PTR_VALUE(from) + (off);                   \
72                 if (p < 0 || p + (access)*PTR_size > GLOBALSIZE) \
73                 {                                                       \
74                         prog->xfunction->profile += (st - startst);     \
75                         prog->xstatement = st - prog->statements;       \
76                         PRVM_ERROR("%s attempted to access an out of bounds global (%i)", PRVM_NAME, (int)p);   \
77                         goto cleanup;                                   \
78                 }                                                       \
79                 ptr = (prvm_eval_t*)((int *)prog->globals.generic + p); \
80         }                                                               \
81         else if (PTR_ISMEM(from))                                       \
82         {                                                               \
83                 ptrval_t p = PTR_VALUE(from) + (off);                   \
84                 if (p < 0 || p + (access)*PTR_size > 0 /* TODO: FILL IN */) \
85                 {                                                       \
86                         prog->xfunction->profile += (st - startst);     \
87                         prog->xstatement = st - prog->statements;       \
88                         PRVM_ERROR("%s attempted to access out of bounds memory (%i)", PRVM_NAME, (int)p); \
89                         goto cleanup;                                   \
90                 }                                                       \
91                 ptr = (prvm_eval_t*)((int *)0 /* TODO: FILL IN*/ + p /* TODO: REMOVE: */ * 0); \
92         }                                                               \
93         else                                                            \
94         {                                                               \
95                 ptrval_t p = PTR_VALUE(from) + (off);                   \
96                 if (p < 0 || p + (access)*PTR_size > prog->entityfieldsarea) \
97                 {                                                       \
98                         prog->xfunction->profile += (st - startst);     \
99                         prog->xstatement = st - prog->statements;       \
100                         PRVM_ERROR("%s attempted to access an out of bounds edict field (%i)", PRVM_NAME, (int)p); \
101                         goto cleanup;                                   \
102                 }                                                       \
103                 ptr = (prvm_eval_t*)((int *)prog->edictsfields + p);    \
104                 if (p < prog->progs->entityfields && !prog->allowworldwrites) \
105                         Con_DPrintf("WARNING: assignment to world.%s (field %i) in %s\n", PRVM_GetString(PRVM_ED_FieldAtOfs(p)->s_name), (int)p, PRVM_NAME); \
106         }
107 #else
108
109 #define PTR_ptr3(from, off, access)                                             \
110         if (PTR_ISGBL(from))                                            \
111         {                                                               \
112                 ptrval_t p = PTR_VALUE(from) + (off);                   \
113                 ptr = (prvm_eval_t *)((int*)prog->globals.generic + p); \
114         }                                                               \
115         else if (PTR_ISMEM(from))                                       \
116         {                                                               \
117                 ptrval_t p = PTR_VALUE(from) + (off);                   \
118                 ptr = (prvm_eval_t *)((int*)0 /* TODO: FILL IN*/ + p /* TODO: REMOVE: */ * 0); \
119         }                                                               \
120         else                                                            \
121         {                                                               \
122                 ptrval_t p = PTR_VALUE(from) + (off);                   \
123                 ptr = (prvm_eval_t *)((int*)prog->edictsfields + p);    \
124         }
125 #endif
126 #define PTR_ptr2(from, off) PTR_ptr3(from, off, 1)
127 #define PTR_ptr(from) PTR_ptr3(from, 0, 1)
128
129 typedef long ptrval_t;
130
131 // This code isn't #ifdef/#define protectable, don't try.
132 prvm_eval_t *swtch = NULL;
133 int swtchtype = 0;
134 ptrval_t ptrvalA, ptrvalB, ptrvalC;
135 ptrvalA = 0; // get rid of the unused-warning for now
136 ptrvalB = 0;
137 ptrvalC = 0;
138                 while (1)
139                 {
140                         st++;
141
142 #if PRVMTRACE
143                         PRVM_PrintStatement(st);
144 #endif
145 #if PRVMSTATEMENTPROFILING
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 PRVMBOUNDSCHECK
304                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
305                                 {
306                                         prog->xfunction->profile += (st - startst);
307                                         prog->xstatement = st - prog->statements;
308                                         PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
309                                         goto cleanup;
310                                 }
311                                 if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
312                                 {
313                                         prog->xfunction->profile += (st - startst);
314                                         prog->xstatement = st - prog->statements;
315                                         PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int);
316                                         goto cleanup;
317                                 }
318 #endif
319 #if 0
320                                 if (OPA->edict == 0 && !prog->allowworldwrites)
321                                 {
322                                         prog->xfunction->profile += (st - startst);
323                                         prog->xstatement = st - prog->statements;
324                                         PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME);
325                                         goto cleanup;
326                                 }
327 #endif
328                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
329                                 OPC->_int = PTR_FLD(((int *)ed->fields.vp + OPB->_int) - (int *)prog->edictsfields);
330                                 break;
331
332                         case OP_LOAD_F:
333                         case OP_LOAD_FLD:
334                         case OP_LOAD_ENT:
335                         case OP_LOAD_S:
336                         case OP_LOAD_FNC:
337                         case OP_LOAD_P:
338 #if PRVMBOUNDSCHECK
339                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
340                                 {
341                                         prog->xfunction->profile += (st - startst);
342                                         prog->xstatement = st - prog->statements;
343                                         PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
344                                         goto cleanup;
345                                 }
346                                 if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
347                                 {
348                                         prog->xfunction->profile += (st - startst);
349                                         prog->xstatement = st - prog->statements;
350                                         PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
351                                         goto cleanup;
352                                 }
353 #endif
354                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
355                                 OPC->_int = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->_int;
356                                 break;
357
358                         case OP_LOAD_V:
359 #if PRVMBOUNDSCHECK
360                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
361                                 {
362                                         prog->xfunction->profile += (st - startst);
363                                         prog->xstatement = st - prog->statements;
364                                         PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
365                                         goto cleanup;
366                                 }
367                                 if (OPB->_int < 0 || OPB->_int + 2 >= prog->progs->entityfields)
368                                 {
369                                         prog->xfunction->profile += (st - startst);
370                                         prog->xstatement = st - prog->statements;
371                                         PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
372                                         goto cleanup;
373                                 }
374 #endif
375                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
376                                 OPC->ivector[0] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[0];
377                                 OPC->ivector[1] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[1];
378                                 OPC->ivector[2] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->ivector[2];
379                                 break;
380
381                 //==================
382
383                         case OP_IFNOT:
384                                 if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int))
385                                 // TODO add an "int-if", and change this one to OPA->_float
386                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
387                                 // and entity, string, field values can never have that value
388                                 {
389                                         prog->xfunction->profile += (st - startst);
390                                         st += st->b - 1;        // offset the s++
391                                         startst = st;
392                                         
393                                         // no bounds check needed, it is done when loading progs
394                                         RUNAWAYCHECK();
395                                 }
396                                 break;
397
398                         case OP_IF:
399                                 if(FLOAT_IS_TRUE_FOR_INT(OPA->_int))
400                                 // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float
401                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
402                                 // and entity, string, field values can never have that value
403                                 {
404                                         prog->xfunction->profile += (st - startst);
405                                         st += st->b - 1;        // offset the s++
406                                         startst = st;
407                                         RUNAWAYCHECK();
408                                 }
409                                 break;
410
411                         case OP_IFNOT_F:
412                                 if (!OPA->_float)
413                                 {
414                                         prog->xfunction->profile += (st - startst);
415                                         st += st->b - 1;        // offset the s++
416                                         startst = st;
417                                         RUNAWAYCHECK();
418                                 }
419                                 break;
420
421                         case OP_IF_F:
422                                 if (OPA->_float)
423                                 {
424                                         prog->xfunction->profile += (st - startst);
425                                         st += st->b - 1;        // offset the s++
426                                         startst = st;
427                                         // no bounds check needed, it is done when loading progs
428                                         RUNAWAYCHECK();
429                                 }
430                                 break;
431
432                         case OP_GOTO:
433                                 prog->xfunction->profile += (st - startst);
434                                 st += st->a - 1;        // offset the s++
435                                 startst = st;
436                                 // no bounds check needed, it is done when loading progs
437                                 RUNAWAYCHECK();
438                                 break;
439
440                                 // CALLxH used and tested, they do work!
441                         case OP_CALL8H:
442                         case OP_CALL7H:
443                         case OP_CALL6H:
444                         case OP_CALL5H:
445                         case OP_CALL4H:
446                         case OP_CALL3H:
447                         case OP_CALL2H:
448                                 PRVM_G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
449                                 PRVM_G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
450                                 PRVM_G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
451                         case OP_CALL1H:
452                                 PRVM_G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
453                                 PRVM_G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
454                                 PRVM_G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
455                                 // fall through
456                         case OP_CALL0:
457                         case OP_CALL1:
458                         case OP_CALL2:
459                         case OP_CALL3:
460                         case OP_CALL4:
461                         case OP_CALL5:
462                         case OP_CALL6:
463                         case OP_CALL7:
464                         case OP_CALL8:
465                                 prog->xfunction->profile += (st - startst);
466                                 startst = st;
467                                 prog->xstatement = st - prog->statements;
468                                 // handle CALLxH too
469                                 if (st->op >= OP_CALL1H && st->op <= OP_CALL8H)
470                                         prog->argc = st->op - (OP_CALL1H-1);
471                                 else
472                                         prog->argc = st->op - OP_CALL0;
473                                 if (!OPA->function)
474                                         PRVM_ERROR("NULL function in %s", PRVM_NAME);
475
476 #if PRVMBOUNDSCHECK
477                                 if(!OPA->function || OPA->function >= (unsigned int)prog->progs->numfunctions)
478                                 {
479                                         prog->xfunction->profile += (st - startst);
480                                         prog->xstatement = st - prog->statements; // we better stay on the previously executed statement
481                                         PRVM_ERROR("%s CALL outside the program", PRVM_NAME);
482                                         goto cleanup;
483                                 }
484 #endif
485
486                                 newf = &prog->functions[OPA->function];
487                                 newf->callcount++;
488
489                                 if (newf->first_statement < 0)
490                                 {
491                                         // negative statements are built in functions
492                                         int builtinnumber = -newf->first_statement;
493                                         prog->xfunction->builtinsprofile++;
494                                         if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
495                                                 prog->builtins[builtinnumber]();
496                                         else
497                                                 PRVM_ERROR("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, PRVM_NAME);
498                                 }
499                                 else
500                                         st = prog->statements + PRVM_EnterFunction(newf);
501                                 startst = st;
502                                 break;
503
504                         case OP_DONE:
505                         case OP_RETURN:
506                                 prog->xfunction->profile += (st - startst);
507                                 prog->xstatement = st - prog->statements;
508
509                                 prog->globals.generic[OFS_RETURN] = prog->globals.generic[(unsigned short) st->a];
510                                 prog->globals.generic[OFS_RETURN+1] = prog->globals.generic[(unsigned short) st->a+1];
511                                 prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[(unsigned short) st->a+2];
512
513                                 st = prog->statements + PRVM_LeaveFunction();
514                                 startst = st;
515                                 if (prog->depth <= exitdepth)
516                                         goto cleanup; // all done
517                                 if (prog->trace != cachedpr_trace)
518                                         goto chooseexecprogram;
519                                 break;
520
521                         case OP_STATE:
522                                 if(prog->flag & PRVM_OP_STATE)
523                                 {
524                                         ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
525                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.nextthink)->_float = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float + 0.1;
526                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.frame)->_float = OPA->_float;
527                                         PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.think)->function = OPB->function;
528                                 }
529                                 else
530                                 {
531                                         prog->xfunction->profile += (st - startst);
532                                         prog->xstatement = st - prog->statements;
533                                         PRVM_ERROR("OP_STATE not supported by %s", PRVM_NAME);
534                                 }
535                                 break;
536
537 // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
538
539                         case OP_ADD_I:
540                                 OPC->_int = OPA->_int + OPB->_int;
541                                 break;
542                         case OP_ADD_IF:
543                                 OPC->_int = OPA->_int + (int) OPB->_float;
544                                 break;
545                         case OP_ADD_FI:
546                                 OPC->_float = OPA->_float + (float) OPB->_int;
547                                 break;
548                         case OP_SUB_I:
549                                 OPC->_int = OPA->_int - OPB->_int;
550                                 break;
551                         case OP_SUB_IF:
552                                 OPC->_int = OPA->_int - (int) OPB->_float;
553                                 break;
554                         case OP_SUB_FI:
555                                 OPC->_float = OPA->_float - (float) OPB->_int;
556                                 break;
557                         case OP_MUL_I:
558                                 OPC->_int = OPA->_int * OPB->_int;
559                                 break;
560                         case OP_MUL_IF:
561                                 OPC->_int = OPA->_int * (int) OPB->_float;
562                                 break;
563                         case OP_MUL_FI:
564                                 OPC->_float = OPA->_float * (float) OPB->_int;
565                                 break;
566                         case OP_MUL_VI:
567                                 OPC->vector[0] = (float) OPB->_int * OPA->vector[0];
568                                 OPC->vector[1] = (float) OPB->_int * OPA->vector[1];
569                                 OPC->vector[2] = (float) OPB->_int * OPA->vector[2];
570                                 break;
571                         case OP_DIV_VF:
572                                 {
573                                         float temp = 1.0f / OPB->_float;
574                                         OPC->vector[0] = temp * OPA->vector[0];
575                                         OPC->vector[1] = temp * OPA->vector[1];
576                                         OPC->vector[2] = temp * OPA->vector[2];
577                                 }
578                                 break;
579                         case OP_DIV_I:
580                                 OPC->_int = OPA->_int / OPB->_int;
581                                 break;
582                         case OP_DIV_IF:
583                                 OPC->_int = OPA->_int / (int) OPB->_float;
584                                 break;
585                         case OP_DIV_FI:
586                                 OPC->_float = OPA->_float / (float) OPB->_int;
587                                 break;
588                         case OP_STORE_IF:
589                                 OPB->_float = OPA->_int;
590                                 break;
591                         case OP_STORE_FI:
592                                 OPB->_int = OPA->_float;
593                                 break;
594                         case OP_BITAND_I:
595                                 OPC->_int = OPA->_int & OPB->_int;
596                                 break;
597                         case OP_BITOR_I:
598                                 OPC->_int = OPA->_int | OPB->_int;
599                                 break;
600                         case OP_BITAND_IF:
601                                 OPC->_int = OPA->_int & (int)OPB->_float;
602                                 break;
603                         case OP_BITOR_IF:
604                                 OPC->_int = OPA->_int | (int)OPB->_float;
605                                 break;
606                         case OP_BITAND_FI:
607                                 OPC->_float = (int)OPA->_float & OPB->_int;
608                                 break;
609                         case OP_BITOR_FI:
610                                 OPC->_float = (int)OPA->_float | OPB->_int;
611                                 break;
612                         case OP_GE_I:
613                                 OPC->_float = OPA->_int >= OPB->_int;
614                                 break;
615                         case OP_LE_I:
616                                 OPC->_float = OPA->_int <= OPB->_int;
617                                 break;
618                         case OP_GT_I:
619                                 OPC->_float = OPA->_int > OPB->_int;
620                                 break;
621                         case OP_LT_I:
622                                 OPC->_float = OPA->_int < OPB->_int;
623                                 break;
624                         case OP_AND_I:
625                                 OPC->_float = OPA->_int && OPB->_int;
626                                 break;
627                         case OP_OR_I:
628                                 OPC->_float = OPA->_int || OPB->_int;
629                                 break;
630                         case OP_GE_IF:
631                                 OPC->_float = (float)OPA->_int >= OPB->_float;
632                                 break;
633                         case OP_LE_IF:
634                                 OPC->_float = (float)OPA->_int <= OPB->_float;
635                                 break;
636                         case OP_GT_IF:
637                                 OPC->_float = (float)OPA->_int > OPB->_float;
638                                 break;
639                         case OP_LT_IF:
640                                 OPC->_float = (float)OPA->_int < OPB->_float;
641                                 break;
642                         case OP_AND_IF:
643                                 OPC->_float = (float)OPA->_int && OPB->_float;
644                                 break;
645                         case OP_OR_IF:
646                                 OPC->_float = (float)OPA->_int || OPB->_float;
647                                 break;
648                         case OP_GE_FI:
649                                 OPC->_float = OPA->_float >= (float)OPB->_int;
650                                 break;
651                         case OP_LE_FI:
652                                 OPC->_float = OPA->_float <= (float)OPB->_int;
653                                 break;
654                         case OP_GT_FI:
655                                 OPC->_float = OPA->_float > (float)OPB->_int;
656                                 break;
657                         case OP_LT_FI:
658                                 OPC->_float = OPA->_float < (float)OPB->_int;
659                                 break;
660                         case OP_AND_FI:
661                                 OPC->_float = OPA->_float && (float)OPB->_int;
662                                 break;
663                         case OP_OR_FI:
664                                 OPC->_float = OPA->_float || (float)OPB->_int;
665                                 break;
666                         case OP_NOT_I:
667                                 OPC->_float = !OPA->_int;
668                                 break;
669                         case OP_EQ_I:
670                                 OPC->_float = OPA->_int == OPB->_int;
671                                 break;
672                         case OP_EQ_IF:
673                                 OPC->_float = (float)OPA->_int == OPB->_float;
674                                 break;
675                         case OP_EQ_FI:
676                                 OPC->_float = OPA->_float == (float)OPB->_int;
677                                 break;
678                         case OP_NE_I:
679                                 OPC->_float = OPA->_int != OPB->_int;
680                                 break;
681                         case OP_NE_IF:
682                                 OPC->_float = (float)OPA->_int != OPB->_float;
683                                 break;
684                         case OP_NE_FI:
685                                 OPC->_float = OPA->_float != (float)OPB->_int;
686                                 break;
687                         case OP_STOREP_I:
688                                 PTR_ptr(OPB->_int);
689                                 ptr->_int = OPA->_int;
690                                 break;
691                         case OP_LOAD_I:
692 #if PRBOUNDSCHECK
693                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
694                                 {
695                                         prog->xfunction->profile += (st - startst);
696                                         prog->xstatement = st - prog->statements;
697                                         PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
698                                         goto cleanup;
699                                 }
700                                 if (OPB->_int < 0 || OPB->_int >= prog->progs->entityfields)
701                                 {
702                                         prog->xfunction->profile += (st - startst);
703                                         prog->xstatement = st - prog->statements;
704                                         PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME);
705                                         goto cleanup;
706                                 }
707 #endif
708                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
709                                 OPC->_int = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->_int;
710                                 break;
711                         case OP_LOADA_I:
712                         case OP_LOADA_F:
713                         case OP_LOADA_FLD:
714                         case OP_LOADA_ENT:
715                         case OP_LOADA_S:
716                         case OP_LOADA_FNC:
717                                 ptr = (prvm_eval_t *)(&OPA->_int + OPB->_int);
718 #if PRVMBOUNDSCHECK
719                                 if (!PTR_ISVALID(ptr))
720                                 {
721                                         prog->xfunction->profile += (st - startst);
722                                         prog->xstatement = st - prog->statements;
723                                         PRVM_ERROR ("%s Progs attempted to read from an out of bounds address (%i)", PRVM_NAME, OPB->_int);
724                                         goto cleanup;
725                                 }
726 #endif
727                                 OPC->_int = ptr->_int;
728                                 break;
729
730                         case OP_LOADA_V:
731                                 ptr = (prvm_eval_t *)(&OPA->_int + OPB->_int);
732 #if PRVMBOUNDSCHECK
733                                 if (!PTR_ISVALID(ptr))
734                                 {
735                                         prog->xfunction->profile += (st - startst);
736                                         prog->xstatement = st - prog->statements;
737                                         PRVM_ERROR ("%s Progs attempted to read from an out of bounds address (%i)", PRVM_NAME, OPB->_int);
738                                         goto cleanup;
739                                 }
740 #endif
741                                 OPC->vector[0] = ptr->vector[0];
742                                 OPC->vector[1] = ptr->vector[1];
743                                 OPC->vector[2] = ptr->vector[2];
744                                 break;
745                         case OP_BOUNDCHECK:
746                                 if ((unsigned int)OPA->_int < (unsigned int)st->c || (unsigned int)OPA->_int >= (unsigned int)st->b)
747                                 {
748                                         prog->xfunction->profile += (st - startst);
749                                         prog->xstatement = st - prog->statements;
750                                         PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c);
751                                         goto cleanup;
752                                 }
753                                 break;
754
755                         case OP_RAND0: // random number between 0 and 1
756                                 PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0,1);
757                                 break;
758                         case OP_RAND1: // random number between 0 and OPA
759                                 PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0,OPA->_float);
760                                 break;
761                         case OP_RAND2: // random number between OPA and OPB
762                                 if(OPA->_float < OPB->_float)
763                                         PRVM_G_FLOAT(OFS_RETURN) = lhrandom(OPA->_float, OPB->_float);
764                                 else
765                                         PRVM_G_FLOAT(OFS_RETURN) = lhrandom(OPB->_float, OPA->_float);
766                                 break;
767                         case OP_RANDV0: // random vector between 0 and 1
768                                 PRVM_G_VECTOR(OFS_RETURN)[0] = lhrandom(0,1);
769                                 PRVM_G_VECTOR(OFS_RETURN)[1] = lhrandom(0,1);
770                                 PRVM_G_VECTOR(OFS_RETURN)[2] = lhrandom(0,1);
771                                 break;
772                         case OP_RANDV1: // random vector between 0 and OPA
773                                 PRVM_G_VECTOR(OFS_RETURN)[0] = lhrandom(0,OPA->vector[0]);
774                                 PRVM_G_VECTOR(OFS_RETURN)[1] = lhrandom(0,OPA->vector[1]);
775                                 PRVM_G_VECTOR(OFS_RETURN)[2] = lhrandom(0,OPA->vector[2]);
776                                 break;
777                         case OP_RANDV2: // random vector between OPA and OPB
778                         {
779                                 int i;
780                                 for(i = 0; i < 3; ++i)
781                                 {
782                                         if(OPA->vector[i] < OPB->vector[i])
783                                                 PRVM_G_VECTOR(OFS_RETURN)[i] = lhrandom(OPA->vector[i], OPB->vector[i]);
784                                         else
785                                                 PRVM_G_VECTOR(OFS_RETURN)[i] = lhrandom(OPB->vector[i], OPA->vector[i]);
786                                 }
787                                 break;
788                         }
789
790                         case OP_SWITCH_F:
791                         case OP_SWITCH_V:
792                         case OP_SWITCH_S:
793                         case OP_SWITCH_E:
794                         case OP_SWITCH_I:
795                         case OP_SWITCH_FNC:
796                         {
797                                 swtch = OPA;
798                                 swtchtype = st->op;
799                                 RUNAWAYCHECK();
800                                 prog->xfunction->profile += (st - startst);
801                                 startst = st;
802                                 st += st->b - 1;        // offset the s++
803                                 break;
804                         }
805                         case OP_CASE:
806                         {
807                                 switch(swtchtype)
808                                 {
809                                 case OP_SWITCH_F:
810                                         if(swtch->_float == OPA->_float)
811                                         {
812                                                 RUNAWAYCHECK();
813                                                 prog->xfunction->profile += (st - startst);
814                                                 startst = st;
815                                                 st += st->b - 1;
816                                         }
817                                         break;
818                                 case OP_SWITCH_E:
819                                 case OP_SWITCH_I:
820                                 case OP_SWITCH_FNC:
821                                         if(swtch->_int == OPA->_int)
822                                         {
823                                                 RUNAWAYCHECK();
824                                                 prog->xfunction->profile += (st - startst);
825                                                 startst = st;
826                                                 st += st->b-1;
827                                         }
828                                         break;
829                                 case OP_SWITCH_S:
830                                         if(swtch->_int == OPA->_int)
831                                         {
832                                                 RUNAWAYCHECK();
833                                                 prog->xfunction->profile += (st - startst);
834                                                 startst = st;
835                                                 st += st->b-1;
836                                         }
837                                         // switch(string) case "string" ->
838                                         // one of them may be null, not both
839                                         if((!swtch->_int && PRVM_GetString(OPA->string)) || (!OPA->_int && PRVM_GetString(swtch->string)))
840                                                 break;
841                                         if(!strcmp(PRVM_GetString(swtch->string), PRVM_GetString(OPA->string)))
842                                         {
843                                                 RUNAWAYCHECK();
844                                                 prog->xfunction->profile += (st - startst);
845                                                 startst = st;
846                                                 st += st->b-1;
847                                         }
848                                         break;
849                                 case OP_SWITCH_V:
850                                         if(swtch->vector[0] == OPA->vector[0] &&
851                                            swtch->vector[1] == OPA->vector[1] &&
852                                            swtch->vector[2] == OPA->vector[2])
853                                         {
854                                                 RUNAWAYCHECK();
855                                                 prog->xfunction->profile += (st - startst);
856                                                 startst = st;
857                                                 st += st->b-1;
858                                         }
859                                         break;
860                                 default:
861                                         PRVM_ERROR("OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
862                                         break;
863                                 }
864                                 break;
865                         }
866
867                         case OP_CASERANGE:
868                                 switch(swtchtype)
869                                 {
870                                 case OP_SWITCH_F:
871                                         if(swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
872                                         {
873                                                 RUNAWAYCHECK();
874                                                 st += st->c-1;
875                                         }
876                                         break;
877                                 default:
878                                         PRVM_ERROR("OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
879                                 }
880                                 break;
881
882                         case OP_CONV_ITOF:
883                                 OPC->_float = (float)OPA->_int;
884                                 break;
885                         case OP_CONV_FTOI:
886                                 OPC->_int = (int)(OPA->_float);
887                                 break;
888                         case OP_CP_ITOF:
889                                 PTR_ptr(OPA->_int);
890                                 OPC->_float = (float)(ptr->_int);
891                                 break;
892                         case OP_CP_FTOI:
893                                 PTR_ptr(OPA->_int);
894                                 OPC->_int = (int)(ptr->_float);
895                                 break;
896
897                         case OP_ADDSTOREP_F:
898                                 PTR_ptr(OPB->_int);
899                                 OPC->_float = (ptr->_float += OPA->_float);
900                                 break;
901                         case OP_ADDSTOREP_V:
902                                 PTR_ptr3(OPB->_int, 0, 3);
903                                 OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
904                                 OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
905                                 OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
906                                 break;
907
908                         case OP_SUBSTOREP_F:
909                                 PTR_ptr(OPB->_int);
910                                 OPC->_float = (ptr->_float -= OPA->_float);
911                                 break;
912                         case OP_SUBSTOREP_V:
913                                 PTR_ptr3(OPB->_int, 0, 3);
914                                 OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
915                                 OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
916                                 OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
917                                 break;
918
919                         case OP_MULSTOREP_F:
920                                 PTR_ptr(OPB->_int);
921                                 OPC->_float = (ptr->_float *= OPA->_float);
922                                 break;
923                         case OP_MULSTOREP_V:
924                                 // e.v *= a_float!
925                                 PTR_ptr3(OPB->_int, 0, 3);
926                                 OPC->vector[0] = (ptr->vector[0] -= OPA->_float);
927                                 OPC->vector[1] = (ptr->vector[1] -= OPA->_float);
928                                 OPC->vector[2] = (ptr->vector[2] -= OPA->_float);
929                                 break;
930
931                         case OP_DIVSTOREP_F:
932                                 PTR_ptr(OPB->_int);
933                                 OPC->_float = (ptr->_float /= OPA->_float);
934                                 break;
935
936                         case OP_IFNOTS:
937                                 if(!OPA->string || !PRVM_GetString(OPA->string))
938                                         st += st->b-1;
939                                 break;
940                         case OP_IFS:
941                                 if(OPA->string && PRVM_GetString(OPA->string))
942                                         st += st->b-1;
943                                 break;
944
945                         case OP_GLOBALADDRESS:
946                                 OPC->_int = ((&(OPA->_int) + OPB->_int) - (int*)prog->globals.generic);
947 #if PRVMBOUNDSCHECK
948                                 if (OPC->_int < 0 || OPC->_int + 4 > GLOBALSIZE)
949                                 {
950                                         prog->xfunction->profile += (st - startst);
951                                         prog->xstatement = st - prog->statements;
952                                         PRVM_ERROR("%s attempted to address an invalid global (%i)", PRVM_NAME, OPC->_int);
953                                         goto cleanup;
954                                 }
955 #endif
956                                 OPC->_int = PTR_GBL(OPC->_int);
957                                 break;
958
959                         case OP_POINTER_ADD:
960                                 // NOTE: dp pointers are no pointers as in byte-offsets, but item-offsets
961                                 // so we use *1
962                                 // I hope this is never used as an optimization for "A = B + C * 4" :P
963                                 OPC->_int = OPA->_int + OPB->_int*1;
964                                 break;
965
966                         case OP_ADD_SF: //(char*)c = (char*)a + (float)b
967                                 OPC->_int = OPA->_int + (int)OPB->_float;
968                                 break;
969                         case OP_SUB_S:  //(float)c = (char*)a - (char*)b
970                                 OPC->_int = OPA->_int - OPB->_int;
971                                 break;
972
973                         case OP_LOADP_I:
974                         case OP_LOADP_F:
975                         case OP_LOADP_FLD:
976                         case OP_LOADP_ENT:
977                         case OP_LOADP_S:
978                         case OP_LOADP_FNC:
979                                 PTR_ptr2(OPA->_int, OPB->_int);
980                                 OPC->_int = ptr->_int;
981                                 break;
982                         case OP_LOADP_V:
983                                 PTR_ptr3(OPA->_int, OPB->_int, 3);
984                                 OPC->vector[0] = ptr->vector[0];
985                                 OPC->vector[1] = ptr->vector[1];
986                                 OPC->vector[2] = ptr->vector[2];
987                                 break;
988                         /*
989                         // not wanted, keeping it in this comment for now though, because...
990                         case OP_STOREP_C:
991                                 PTR_ptr(OPB->_int);
992                                 break;
993
994                         // ... because this could still be reconsidered, after all it only loads
995                         case OP_LOADP_C:
996                                 PTR_ptr2(OPA->_int, (int)OPB->_float);
997                                 OPC->_int = ptr->_int;
998                                 break;
999                         */
1000
1001                         case OP_XOR_I:
1002                                 OPC->_int = OPA->_int ^ OPB->_int;
1003                                 break;
1004                         case OP_RSHIFT_I:
1005                                 OPC->_int = OPA->_int >> OPB->_int;
1006                                 break;
1007                         case OP_LSHIFT_I:
1008                                 OPC->_int = OPA->_int << OPB->_int;
1009                                 break;
1010
1011                         // hexen2 opcodes.. afaik fteqcc shouldn't use those
1012 /*
1013                         case OP_CSTATE:
1014                                 CStateOp(prog, OPA->_float, OPB->_float, newf);
1015                                 break;
1016
1017                         case OP_CWSTATE:
1018                                 CWStateOp(prog, OPA->_float, OPB->_float, newf);
1019                                 break;
1020 */
1021                         case OP_THINKTIME:
1022                                 ThinkTimeOp(prog, PRVM_PROG_TO_EDICT(OPA->edict), OPB->_float);
1023                                 break;
1024
1025                         default:
1026                                 prog->xfunction->profile += (st - startst);
1027                                 prog->xstatement = st - prog->statements;
1028                                 // prvm_opnames
1029                                 if(st->op < OP_NUMOPS)
1030                                         PRVM_ERROR("Instruction %i: %s\n", st->op, prvm_opnames[st->op]);
1031                                 PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME);
1032                                 goto cleanup;
1033                         }
1034                 }
1035