]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_execprogram.h
prvm: Implement integer and pointer opcodes
[xonotic/darkplaces.git] / prvm_execprogram.h
1 extern cvar_t prvm_garbagecollection_enable;
2 int i;
3 // NEED to reset startst after calling this! startst may or may not be clobbered!
4 #define ADVANCE_PROFILE_BEFORE_JUMP() \
5         prog->xfunction->profile += (st - startst); \
6         if (prvm_statementprofiling.integer || (prvm_coverage.integer & 4)) { \
7                 /* All statements from startst+1 to st have been hit. */ \
8                 while (++startst <= st) { \
9                         if (prog->statement_profile[startst - cached_statements]++ == 0 && (prvm_coverage.integer & 4)) \
10                                 PRVM_StatementCoverageEvent(prog, prog->xfunction, startst - cached_statements); \
11                 } \
12                 /* Observe: startst now is clobbered (now at st+1)! */ \
13         }
14
15 #ifdef PRVMTIMEPROFILING
16 #define PRE_ERROR() \
17         ADVANCE_PROFILE_BEFORE_JUMP(); \
18         prog->xstatement = st - cached_statements; \
19         tm = Sys_DirtyTime(); \
20         prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; \
21         startst = st; \
22         starttm = tm
23 #else
24 #define PRE_ERROR() \
25         ADVANCE_PROFILE_BEFORE_JUMP(); \
26         prog->xstatement = st - cached_statements; \
27         startst = st
28 #endif
29
30 // This code isn't #ifdef/#define protectable, don't try.
31
32 #if HAVE_COMPUTED_GOTOS && !(PRVMSLOWINTERPRETER || PRVMTIMEPROFILING)
33   // NOTE: Due to otherwise duplicate labels, only ONE interpreter path may
34   // ever hit this!
35 # define USE_COMPUTED_GOTOS 1
36 #endif
37
38 #if USE_COMPUTED_GOTOS
39   // Must exactly match opcode_e enum in pr_comp.h
40     const static void *dispatchtable[] = {
41         &&handle_OP_DONE,
42         &&handle_OP_MUL_F,
43         &&handle_OP_MUL_V,
44         &&handle_OP_MUL_FV,
45         &&handle_OP_MUL_VF,
46         &&handle_OP_DIV_F,
47         &&handle_OP_ADD_F,
48         &&handle_OP_ADD_V,
49         &&handle_OP_SUB_F,
50         &&handle_OP_SUB_V,
51
52         &&handle_OP_EQ_F,
53         &&handle_OP_EQ_V,
54         &&handle_OP_EQ_S,
55         &&handle_OP_EQ_E,
56         &&handle_OP_EQ_FNC,
57
58         &&handle_OP_NE_F,
59         &&handle_OP_NE_V,
60         &&handle_OP_NE_S,
61         &&handle_OP_NE_E,
62         &&handle_OP_NE_FNC,
63
64         &&handle_OP_LE,
65         &&handle_OP_GE,
66         &&handle_OP_LT,
67         &&handle_OP_GT,
68
69         &&handle_OP_LOAD_F,
70         &&handle_OP_LOAD_V,
71         &&handle_OP_LOAD_S,
72         &&handle_OP_LOAD_ENT,
73         &&handle_OP_LOAD_FLD,
74         &&handle_OP_LOAD_FNC,
75
76         &&handle_OP_ADDRESS,
77
78         &&handle_OP_STORE_F,
79         &&handle_OP_STORE_V,
80         &&handle_OP_STORE_S,
81         &&handle_OP_STORE_ENT,
82         &&handle_OP_STORE_FLD,
83         &&handle_OP_STORE_FNC,
84
85         &&handle_OP_STOREP_F,
86         &&handle_OP_STOREP_V,
87         &&handle_OP_STOREP_S,
88         &&handle_OP_STOREP_ENT,
89         &&handle_OP_STOREP_FLD,
90         &&handle_OP_STOREP_FNC,
91
92         &&handle_OP_RETURN,
93         &&handle_OP_NOT_F,
94         &&handle_OP_NOT_V,
95         &&handle_OP_NOT_S,
96         &&handle_OP_NOT_ENT,
97         &&handle_OP_NOT_FNC,
98         &&handle_OP_IF,
99         &&handle_OP_IFNOT,
100         &&handle_OP_CALL0,
101         &&handle_OP_CALL1,
102         &&handle_OP_CALL2,
103         &&handle_OP_CALL3,
104         &&handle_OP_CALL4,
105         &&handle_OP_CALL5,
106         &&handle_OP_CALL6,
107         &&handle_OP_CALL7,
108         &&handle_OP_CALL8,
109         &&handle_OP_STATE,
110         &&handle_OP_GOTO,
111         &&handle_OP_AND,
112         &&handle_OP_OR,
113
114         &&handle_OP_BITAND,
115         &&handle_OP_BITOR,
116
117         NULL,
118         NULL,
119         NULL,
120         NULL,
121         NULL,
122         NULL,
123         NULL,
124         NULL,
125         NULL,
126         NULL,
127         NULL,
128         NULL,
129         NULL,
130         NULL,
131         NULL,
132         NULL,
133         NULL,
134         NULL,
135         NULL,
136         NULL,
137         NULL,
138         NULL,
139         NULL,
140         NULL,
141         NULL,
142         NULL,
143         NULL,
144         NULL,
145         NULL,
146         NULL,
147         NULL,
148         NULL,
149         NULL,
150         NULL,
151         NULL,
152         NULL,
153         NULL,
154         NULL,
155         NULL,
156         NULL,
157         NULL,
158         NULL,
159         NULL,
160         NULL,
161         NULL,
162         NULL,
163         NULL,
164
165         &&handle_OP_STORE_I,
166
167         NULL,
168         NULL,
169
170         &&handle_OP_ADD_I,
171         &&handle_OP_ADD_FI,
172         &&handle_OP_ADD_IF,
173
174         &&handle_OP_SUB_I,
175         &&handle_OP_SUB_FI,
176         &&handle_OP_SUB_IF,
177         &&handle_OP_CONV_IF,
178         &&handle_OP_CONV_FI,
179
180         NULL,
181         NULL,
182
183         &&handle_OP_LOAD_I,
184         &&handle_OP_STOREP_I,
185
186         NULL,
187         NULL,
188
189         &&handle_OP_BITAND_I,
190         &&handle_OP_BITOR_I,
191
192         &&handle_OP_MUL_I,
193         &&handle_OP_DIV_I,
194         &&handle_OP_EQ_I,
195         &&handle_OP_NE_I,
196
197         NULL,
198         NULL,
199
200         &&handle_OP_NOT_I,
201
202         &&handle_OP_DIV_VF,
203
204         NULL,
205         NULL,
206         NULL,
207         NULL,
208         NULL,
209         NULL,
210         NULL,
211         NULL,
212         NULL,
213         NULL,
214         NULL,
215         NULL,
216
217         &&handle_OP_STORE_P,
218
219         NULL,
220         NULL,
221         NULL,
222         NULL,
223         NULL,
224         NULL,
225         NULL,
226         NULL,
227
228         &&handle_OP_LE_I,
229         &&handle_OP_GE_I,
230         &&handle_OP_LT_I,
231         &&handle_OP_GT_I,
232         
233         &&handle_OP_LE_IF,
234         &&handle_OP_GE_IF,
235         &&handle_OP_LT_IF,
236         &&handle_OP_GT_IF,
237
238         &&handle_OP_LE_FI,
239         &&handle_OP_GE_FI,
240         &&handle_OP_LT_FI,
241         &&handle_OP_GT_FI,
242
243         &&handle_OP_EQ_IF,
244         &&handle_OP_EQ_FI,
245
246         NULL,
247         NULL,
248         NULL,
249         NULL,
250
251         &&handle_OP_MUL_IF,
252         &&handle_OP_MUL_FI,
253         &&handle_OP_MUL_VI,
254
255         NULL,
256
257         &&handle_OP_DIV_IF,
258         &&handle_OP_DIV_FI,
259         &&handle_OP_BITAND_IF,
260         &&handle_OP_BITOR_IF,
261         &&handle_OP_BITAND_FI,
262         &&handle_OP_BITOR_FI,
263         &&handle_OP_AND_I,
264         &&handle_OP_OR_I,
265         &&handle_OP_AND_IF,
266         &&handle_OP_OR_IF,
267         &&handle_OP_AND_FI,
268         &&handle_OP_OR_FI,
269         &&handle_OP_NE_IF,
270         &&handle_OP_NE_FI,
271
272         &&handle_OP_GSTOREP_I,
273         &&handle_OP_GSTOREP_F,
274         &&handle_OP_GSTOREP_ENT,
275         &&handle_OP_GSTOREP_FLD,
276         &&handle_OP_GSTOREP_S,
277         &&handle_OP_GSTOREP_FNC,                
278         &&handle_OP_GSTOREP_V,
279         &&handle_OP_GADDRESS,
280         &&handle_OP_GLOAD_I,
281         &&handle_OP_GLOAD_F,
282         &&handle_OP_GLOAD_FLD,
283         &&handle_OP_GLOAD_ENT,
284         &&handle_OP_GLOAD_S,
285         &&handle_OP_GLOAD_FNC,
286         &&handle_OP_BOUNDCHECK,
287         NULL,
288         NULL,
289         NULL,
290         NULL,
291         &&handle_OP_GLOAD_V
292             };
293 #define DISPATCH_OPCODE() \
294     goto *dispatchtable[(++st)->op]
295 #define HANDLE_OPCODE(opcode) handle_##opcode
296
297     DISPATCH_OPCODE(); // jump to first opcode
298 #else // USE_COMPUTED_GOTOS
299 #define DISPATCH_OPCODE() break
300 #define HANDLE_OPCODE(opcode) case opcode
301
302 #if PRVMSLOWINTERPRETER
303                 {
304                         if (prog->watch_global_type != ev_void)
305                         {
306                                 prvm_eval_t *g = PRVM_GLOBALFIELDVALUE(prog->watch_global);
307                                 prog->xstatement = st + 1 - cached_statements;
308                                 PRVM_Watchpoint(prog, 1, "Global watchpoint hit by engine", prog->watch_global_type, &prog->watch_global_value, g);
309                         }
310                         if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
311                         {
312                                 prvm_eval_t *g = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
313                                 prog->xstatement = st + 1 - cached_statements;
314                                 PRVM_Watchpoint(prog, 1, "Entityfield watchpoint hit by engine", prog->watch_field_type, &prog->watch_edictfield_value, g);
315                         }
316                 }
317 #endif
318
319                 while (1)
320                 {
321                         st++;
322 #endif // USE_COMPUTED_GOTOS
323
324 #if !USE_COMPUTED_GOTOS
325
326 #if PRVMSLOWINTERPRETER
327                         if (prog->trace)
328                                 PRVM_PrintStatement(prog, st);
329                         if (prog->break_statement >= 0)
330                                 if ((st - cached_statements) == prog->break_statement)
331                                 {
332                                         prog->xstatement = st - cached_statements;
333                                         PRVM_Breakpoint(prog, prog->break_stack_index, "Breakpoint hit");
334                                 }
335 #endif
336                         switch (st->op)
337                         {
338 #endif
339                         HANDLE_OPCODE(OP_ADD_F):
340                                 OPC->_float = OPA->_float + OPB->_float;
341                                 DISPATCH_OPCODE();
342                         HANDLE_OPCODE(OP_ADD_V):
343                                 OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
344                                 OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
345                                 OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
346                                 DISPATCH_OPCODE();
347                         HANDLE_OPCODE(OP_SUB_F):
348                                 OPC->_float = OPA->_float - OPB->_float;
349                                 DISPATCH_OPCODE();
350                         HANDLE_OPCODE(OP_SUB_V):
351                                 OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
352                                 OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
353                                 OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
354                                 DISPATCH_OPCODE();
355                         HANDLE_OPCODE(OP_MUL_F):
356                                 OPC->_float = OPA->_float * OPB->_float;
357                                 DISPATCH_OPCODE();
358                         HANDLE_OPCODE(OP_MUL_V):
359                                 OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
360                                 DISPATCH_OPCODE();
361                         HANDLE_OPCODE(OP_MUL_FV):
362                                 tempfloat = OPA->_float;
363                                 OPC->vector[0] = tempfloat * OPB->vector[0];
364                                 OPC->vector[1] = tempfloat * OPB->vector[1];
365                                 OPC->vector[2] = tempfloat * OPB->vector[2];
366                                 DISPATCH_OPCODE();
367                         HANDLE_OPCODE(OP_MUL_VF):
368                                 tempfloat = OPB->_float;
369                                 OPC->vector[0] = tempfloat * OPA->vector[0];
370                                 OPC->vector[1] = tempfloat * OPA->vector[1];
371                                 OPC->vector[2] = tempfloat * OPA->vector[2];
372                                 DISPATCH_OPCODE();
373                         HANDLE_OPCODE(OP_DIV_F):
374                                 if( OPB->_float != 0.0f )
375                                 {
376                                         OPC->_float = OPA->_float / OPB->_float;
377                                 }
378                                 else
379                                 {
380                                         if (developer.integer)
381                                         {
382                                                 PRE_ERROR();
383                                                 VM_Warning(prog, "Attempted division by zero in %s\n", prog->name );
384                                         }
385                                         OPC->_float = 0.0f;
386                                 }
387                                 DISPATCH_OPCODE();
388                         HANDLE_OPCODE(OP_BITAND):
389                                 OPC->_float = (prvm_int_t)OPA->_float & (prvm_int_t)OPB->_float;
390                                 DISPATCH_OPCODE();
391                         HANDLE_OPCODE(OP_BITOR):
392                                 OPC->_float = (prvm_int_t)OPA->_float | (prvm_int_t)OPB->_float;
393                                 DISPATCH_OPCODE();
394                         HANDLE_OPCODE(OP_GE):
395                                 OPC->_float = OPA->_float >= OPB->_float;
396                                 DISPATCH_OPCODE();
397                         HANDLE_OPCODE(OP_LE):
398                                 OPC->_float = OPA->_float <= OPB->_float;
399                                 DISPATCH_OPCODE();
400                         HANDLE_OPCODE(OP_GT):
401                                 OPC->_float = OPA->_float > OPB->_float;
402                                 DISPATCH_OPCODE();
403                         HANDLE_OPCODE(OP_LT):
404                                 OPC->_float = OPA->_float < OPB->_float;
405                                 DISPATCH_OPCODE();
406                         HANDLE_OPCODE(OP_AND):
407                                 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
408                                 DISPATCH_OPCODE();
409                         HANDLE_OPCODE(OP_OR):
410                                 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
411                                 DISPATCH_OPCODE();
412                         HANDLE_OPCODE(OP_NOT_F):
413                                 OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int);
414                                 DISPATCH_OPCODE();
415                         HANDLE_OPCODE(OP_NOT_V):
416                                 OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
417                                 DISPATCH_OPCODE();
418                         HANDLE_OPCODE(OP_NOT_S):
419                                 OPC->_float = !OPA->string || !*PRVM_GetString(prog, OPA->string);
420                                 DISPATCH_OPCODE();
421                         HANDLE_OPCODE(OP_NOT_FNC):
422                                 OPC->_float = !OPA->function;
423                                 DISPATCH_OPCODE();
424                         HANDLE_OPCODE(OP_NOT_ENT):
425                                 OPC->_float = (OPA->edict == 0);
426                                 DISPATCH_OPCODE();
427                         HANDLE_OPCODE(OP_EQ_F):
428                                 OPC->_float = OPA->_float == OPB->_float;
429                                 DISPATCH_OPCODE();
430                         HANDLE_OPCODE(OP_EQ_V):
431                                 OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
432                                 DISPATCH_OPCODE();
433                         HANDLE_OPCODE(OP_EQ_S):
434                                 OPC->_float = !strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
435                                 DISPATCH_OPCODE();
436                         HANDLE_OPCODE(OP_EQ_E):
437                                 OPC->_float = OPA->_int == OPB->_int;
438                                 DISPATCH_OPCODE();
439                         HANDLE_OPCODE(OP_EQ_FNC):
440                                 OPC->_float = OPA->function == OPB->function;
441                                 DISPATCH_OPCODE();
442                         HANDLE_OPCODE(OP_NE_F):
443                                 OPC->_float = OPA->_float != OPB->_float;
444                                 DISPATCH_OPCODE();
445                         HANDLE_OPCODE(OP_NE_V):
446                                 OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
447                                 DISPATCH_OPCODE();
448                         HANDLE_OPCODE(OP_NE_S):
449                                 OPC->_float = strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
450                                 DISPATCH_OPCODE();
451                         HANDLE_OPCODE(OP_NE_E):
452                                 OPC->_float = OPA->_int != OPB->_int;
453                                 DISPATCH_OPCODE();
454                         HANDLE_OPCODE(OP_NE_FNC):
455                                 OPC->_float = OPA->function != OPB->function;
456                                 DISPATCH_OPCODE();
457
458                 //==================
459                         HANDLE_OPCODE(OP_STORE_F):
460                         HANDLE_OPCODE(OP_STORE_ENT):
461                         HANDLE_OPCODE(OP_STORE_FLD):            // integers
462                         HANDLE_OPCODE(OP_STORE_FNC):            // pointers
463                                 OPB->_int = OPA->_int;
464                                 DISPATCH_OPCODE();
465                         HANDLE_OPCODE(OP_STORE_S):
466                                 // refresh the garbage collection on the string - this guards
467                                 // against a certain sort of repeated migration to earlier
468                                 // points in the scan that could otherwise result in the string
469                                 // being freed for being unused
470                                 if(prvm_garbagecollection_enable.integer)
471                                         PRVM_GetString(prog, OPA->_int);
472                                 OPB->_int = OPA->_int;
473                         DISPATCH_OPCODE();
474                         HANDLE_OPCODE(OP_STORE_V):
475                                 OPB->ivector[0] = OPA->ivector[0];
476                                 OPB->ivector[1] = OPA->ivector[1];
477                                 OPB->ivector[2] = OPA->ivector[2];
478                                 DISPATCH_OPCODE();
479
480                         HANDLE_OPCODE(OP_STOREP_F):
481                         HANDLE_OPCODE(OP_STOREP_ENT):
482                         HANDLE_OPCODE(OP_STOREP_FLD):           // integers
483                         HANDLE_OPCODE(OP_STOREP_FNC):           // pointers
484                                 if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields)
485                                 {
486                                         if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea)
487                                         {
488                                                 PRE_ERROR();
489                                                 prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
490                                                 goto cleanup;
491                                         }
492                                         if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
493                                         {
494                                                 PRE_ERROR();
495                                                 VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
496                                         }
497                                 }
498                                 ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int);
499                                 ptr->_int = OPA->_int;
500                                 DISPATCH_OPCODE();
501                         HANDLE_OPCODE(OP_STOREP_S):
502                                 if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields)
503                                 {
504                                         if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea)
505                                         {
506                                                 PRE_ERROR();
507                                                 prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
508                                                 goto cleanup;
509                                         }
510                                         if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
511                                         {
512                                                 PRE_ERROR();
513                                                 VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
514                                         }
515                                 }
516                                 // refresh the garbage collection on the string - this guards
517                                 // against a certain sort of repeated migration to earlier
518                                 // points in the scan that could otherwise result in the string
519                                 // being freed for being unused
520                                 if(prvm_garbagecollection_enable.integer)
521                                         PRVM_GetString(prog, OPA->_int);
522                                 ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int);
523                                 ptr->_int = OPA->_int;
524                                 DISPATCH_OPCODE();
525                         HANDLE_OPCODE(OP_STOREP_V):
526                                 if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3)
527                                 {
528                                         if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3)
529                                         {
530                                                 PRE_ERROR();
531                                                 prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
532                                                 goto cleanup;
533                                         }
534                                         if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
535                                         {
536                                                 PRE_ERROR();
537                                                 VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
538                                         }
539                                 }
540                                 ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int);
541                                 ptr->ivector[0] = OPA->ivector[0];
542                                 ptr->ivector[1] = OPA->ivector[1];
543                                 ptr->ivector[2] = OPA->ivector[2];
544                                 DISPATCH_OPCODE();
545
546                         HANDLE_OPCODE(OP_ADDRESS):
547                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
548                                 {
549                                         PRE_ERROR();
550                                         prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name);
551                                         goto cleanup;
552                                 }
553                                 if ((prvm_uint_t)OPB->_int >= cached_entityfields)
554                                 {
555                                         PRE_ERROR();
556                                         prog->error_cmd("%s attempted to address an invalid field (%i) in an edict", prog->name, (int)OPB->_int);
557                                         goto cleanup;
558                                 }
559 #if 0
560                                 if (OPA->edict == 0 && !cached_allowworldwrites)
561                                 {
562                                         PRE_ERROR();
563                                         prog->error_cmd("forbidden assignment to null/world entity in %s", prog->name);
564                                         goto cleanup;
565                                 }
566 #endif
567                                 OPC->_int = OPA->edict * cached_entityfields + OPB->_int;
568                                 DISPATCH_OPCODE();
569
570                         HANDLE_OPCODE(OP_LOAD_F):
571                         HANDLE_OPCODE(OP_LOAD_FLD):
572                         HANDLE_OPCODE(OP_LOAD_ENT):
573                         HANDLE_OPCODE(OP_LOAD_FNC):
574                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
575                                 {
576                                         PRE_ERROR();
577                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
578                                         goto cleanup;
579                                 }
580                                 if ((prvm_uint_t)OPB->_int >= cached_entityfields)
581                                 {
582                                         PRE_ERROR();
583                                         prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int);
584                                         goto cleanup;
585                                 }
586                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
587                                 OPC->_int = ((prvm_eval_t *)(ed->fields.ip + OPB->_int))->_int;
588                                 DISPATCH_OPCODE();
589                         HANDLE_OPCODE(OP_LOAD_S):
590                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
591                                 {
592                                         PRE_ERROR();
593                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
594                                         goto cleanup;
595                                 }
596                                 if ((prvm_uint_t)OPB->_int >= cached_entityfields)
597                                 {
598                                         PRE_ERROR();
599                                         prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int);
600                                         goto cleanup;
601                                 }
602                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
603                                 OPC->_int = ((prvm_eval_t *)(ed->fields.ip + OPB->_int))->_int;
604                                 // refresh the garbage collection on the string - this guards
605                                 // against a certain sort of repeated migration to earlier
606                                 // points in the scan that could otherwise result in the string
607                                 // being freed for being unused
608                                 if(prvm_garbagecollection_enable.integer)
609                                         PRVM_GetString(prog, OPC->_int);
610                                 DISPATCH_OPCODE();
611
612                         HANDLE_OPCODE(OP_LOAD_V):
613                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
614                                 {
615                                         PRE_ERROR();
616                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
617                                         goto cleanup;
618                                 }
619                                 if ((prvm_uint_t)OPB->_int > cached_entityfields_3)
620                                 {
621                                         PRE_ERROR();
622                                         prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int);
623                                         goto cleanup;
624                                 }
625                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
626                                 ptr = (prvm_eval_t *)(ed->fields.ip + OPB->_int);
627                                 OPC->ivector[0] = ptr->ivector[0];
628                                 OPC->ivector[1] = ptr->ivector[1];
629                                 OPC->ivector[2] = ptr->ivector[2];
630                                 DISPATCH_OPCODE();
631
632                 //==================
633
634                         HANDLE_OPCODE(OP_IFNOT):
635                                 if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int))
636                                 // TODO add an "int-if", and change this one to OPA->_float
637                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
638                                 // and entity, string, field values can never have that value
639                                 {
640                                         ADVANCE_PROFILE_BEFORE_JUMP();
641                                         st = cached_statements + st->jumpabsolute - 1;  // offset the st++
642                                         startst = st;
643                                         // no bounds check needed, it is done when loading progs
644                                         if (++jumpcount == 10000000 && prvm_runawaycheck)
645                                         {
646                                                 prog->xstatement = st - cached_statements;
647                                                 PRVM_Profile(prog, 1<<30, 1000000, 0);
648                                                 prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
649                                         }
650                                 }
651                                 DISPATCH_OPCODE();
652
653                         HANDLE_OPCODE(OP_IF):
654                                 if(FLOAT_IS_TRUE_FOR_INT(OPA->_int))
655                                 // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float
656                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
657                                 // and entity, string, field values can never have that value
658                                 {
659                                         ADVANCE_PROFILE_BEFORE_JUMP();
660                                         st = cached_statements + st->jumpabsolute - 1;  // offset the st++
661                                         startst = st;
662                                         // no bounds check needed, it is done when loading progs
663                                         if (++jumpcount == 10000000 && prvm_runawaycheck)
664                                         {
665                                                 prog->xstatement = st - cached_statements;
666                                                 PRVM_Profile(prog, 1<<30, 0.01, 0);
667                                                 prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
668                                         }
669                                 }
670                                 DISPATCH_OPCODE();
671
672                         HANDLE_OPCODE(OP_GOTO):
673                                 ADVANCE_PROFILE_BEFORE_JUMP();
674                                 st = cached_statements + st->jumpabsolute - 1;  // offset the st++
675                                 startst = st;
676                                 // no bounds check needed, it is done when loading progs
677                                 if (++jumpcount == 10000000 && prvm_runawaycheck)
678                                 {
679                                         prog->xstatement = st - cached_statements;
680                                         PRVM_Profile(prog, 1<<30, 0.01, 0);
681                                         prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
682                                 }
683                                 DISPATCH_OPCODE();
684
685                         HANDLE_OPCODE(OP_CALL0):
686                         HANDLE_OPCODE(OP_CALL1):
687                         HANDLE_OPCODE(OP_CALL2):
688                         HANDLE_OPCODE(OP_CALL3):
689                         HANDLE_OPCODE(OP_CALL4):
690                         HANDLE_OPCODE(OP_CALL5):
691                         HANDLE_OPCODE(OP_CALL6):
692                         HANDLE_OPCODE(OP_CALL7):
693                         HANDLE_OPCODE(OP_CALL8):
694 #ifdef PRVMTIMEPROFILING 
695                                 tm = Sys_DirtyTime();
696                                 prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
697                                 starttm = tm;
698 #endif
699                                 ADVANCE_PROFILE_BEFORE_JUMP();
700                                 startst = st;
701                                 prog->xstatement = st - cached_statements;
702                                 prog->argc = st->op - OP_CALL0;
703                                 if (!OPA->function)
704                                 {
705                                         prog->error_cmd("NULL function in %s", prog->name);
706                                 }
707
708                                 if(!OPA->function || OPA->function < 0 || OPA->function >= prog->numfunctions)
709                                 {
710                                         PRE_ERROR();
711                                         prog->error_cmd("%s CALL outside the program", prog->name);
712                                         goto cleanup;
713                                 }
714
715                                 enterfunc = &prog->functions[OPA->function];
716                                 if (enterfunc->callcount++ == 0 && (prvm_coverage.integer & 1))
717                                         PRVM_FunctionCoverageEvent(prog, enterfunc);
718
719                                 if (enterfunc->first_statement < 0)
720                                 {
721                                         // negative first_statement values are built in functions
722                                         int builtinnumber = -enterfunc->first_statement;
723                                         prog->xfunction->builtinsprofile++;
724                                         if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
725                                         {
726                                                 prog->builtins[builtinnumber](prog);
727 #ifdef PRVMTIMEPROFILING 
728                                                 tm = Sys_DirtyTime();
729                                                 enterfunc->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
730                                                 prog->xfunction->tbprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
731                                                 starttm = tm;
732 #endif
733                                                 // builtins may cause ED_Alloc() to be called, update cached variables
734                                                 cached_edictsfields = prog->edictsfields.fp;
735                                                 cached_entityfields = prog->entityfields;
736                                                 cached_entityfields_3 = prog->entityfields - 3;
737                                                 cached_entityfieldsarea = prog->entityfieldsarea;
738                                                 cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
739                                                 cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
740                                                 cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
741                                                 cached_max_edicts = prog->max_edicts;
742                                                 // these do not change
743                                                 //cached_statements = prog->statements;
744                                                 //cached_allowworldwrites = prog->allowworldwrites;
745                                                 //cached_flag = prog->flag;
746                                                 // if prog->trace changed we need to change interpreter path
747                                                 if (prog->trace != cachedpr_trace)
748                                                         goto chooseexecprogram;
749                                         }
750                                         else
751                                                 prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name);
752                                 }
753                                 else
754                                         st = cached_statements + PRVM_EnterFunction(prog, enterfunc);
755                                 startst = st;
756                                 DISPATCH_OPCODE();
757
758                         HANDLE_OPCODE(OP_DONE):
759                         HANDLE_OPCODE(OP_RETURN):
760 #ifdef PRVMTIMEPROFILING 
761                                 tm = Sys_DirtyTime();
762                                 prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
763                                 starttm = tm;
764 #endif
765                                 ADVANCE_PROFILE_BEFORE_JUMP();
766                                 prog->xstatement = st - cached_statements;
767
768                                 prog->globals.ip[OFS_RETURN  ] = prog->globals.ip[st->operand[0]  ];
769                                 prog->globals.ip[OFS_RETURN+1] = prog->globals.ip[st->operand[0]+1];
770                                 prog->globals.ip[OFS_RETURN+2] = prog->globals.ip[st->operand[0]+2];
771
772                                 st = cached_statements + PRVM_LeaveFunction(prog);
773                                 startst = st;
774                                 if (prog->depth <= exitdepth)
775                                         goto cleanup; // all done
776                                 DISPATCH_OPCODE();
777
778                         HANDLE_OPCODE(OP_STATE):
779                                 if(cached_flag & PRVM_OP_STATE)
780                                 {
781                                         ed = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
782                                         PRVM_gameedictfloat(ed,nextthink) = PRVM_gameglobalfloat(time) + 0.1;
783                                         PRVM_gameedictfloat(ed,frame) = OPA->_float;
784                                         PRVM_gameedictfunction(ed,think) = OPB->function;
785                                 }
786                                 else
787                                 {
788                                         PRE_ERROR();
789                                         prog->xstatement = st - cached_statements;
790                                         prog->error_cmd("OP_STATE not supported by %s", prog->name);
791                                 }
792                                 DISPATCH_OPCODE();
793
794                         HANDLE_OPCODE(OP_ADD_I):
795                                 OPC->_int = OPA->_int + OPB->_int;
796                                 DISPATCH_OPCODE();
797                         HANDLE_OPCODE(OP_ADD_IF):
798                                 OPC->_int = OPA->_int + (prvm_int_t) OPB->_float;
799                                 DISPATCH_OPCODE();
800                         HANDLE_OPCODE(OP_ADD_FI):
801                                 OPC->_float = OPA->_float + (prvm_vec_t) OPB->_int;
802                                 DISPATCH_OPCODE();
803                         HANDLE_OPCODE(OP_SUB_I):
804                                 OPC->_int = OPA->_int - OPB->_int;
805                                 DISPATCH_OPCODE();
806                         HANDLE_OPCODE(OP_SUB_IF):
807                                 OPC->_int = OPA->_int - (prvm_int_t) OPB->_float;
808                                 DISPATCH_OPCODE();
809                         HANDLE_OPCODE(OP_SUB_FI):
810                                 OPC->_float = OPA->_float - (prvm_vec_t) OPB->_int;
811                                 DISPATCH_OPCODE();
812                         HANDLE_OPCODE(OP_MUL_I):
813                                 OPC->_int = OPA->_int * OPB->_int;
814                                 DISPATCH_OPCODE();
815                         HANDLE_OPCODE(OP_MUL_IF):
816                                 OPC->_int = OPA->_int * (prvm_int_t) OPB->_float;
817                                 DISPATCH_OPCODE();
818                         HANDLE_OPCODE(OP_MUL_FI):
819                                 OPC->_float = OPA->_float * (prvm_vec_t) OPB->_int;
820                                 DISPATCH_OPCODE();
821                         HANDLE_OPCODE(OP_MUL_VI):
822                                 OPC->vector[0] = (prvm_vec_t) OPB->_int * OPA->vector[0];
823                                 OPC->vector[1] = (prvm_vec_t) OPB->_int * OPA->vector[1];
824                                 OPC->vector[2] = (prvm_vec_t) OPB->_int * OPA->vector[2];
825                                 DISPATCH_OPCODE();
826                         HANDLE_OPCODE(OP_DIV_VF):
827                                 {
828                                         float temp = 1.0f / OPB->_float;
829                                         OPC->vector[0] = temp * OPA->vector[0];
830                                         OPC->vector[1] = temp * OPA->vector[1];
831                                         OPC->vector[2] = temp * OPA->vector[2];
832                                 }
833                                 DISPATCH_OPCODE();
834                         HANDLE_OPCODE(OP_DIV_I):
835                                 OPC->_int = OPA->_int / OPB->_int;
836                                 DISPATCH_OPCODE();
837                         HANDLE_OPCODE(OP_DIV_IF):
838                                 OPC->_int = OPA->_int / (prvm_int_t) OPB->_float;
839                                 DISPATCH_OPCODE();
840                         HANDLE_OPCODE(OP_DIV_FI):
841                                 OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
842                                 DISPATCH_OPCODE();
843                         HANDLE_OPCODE(OP_CONV_IF):
844                                 OPC->_float = OPA->_int;
845                                 DISPATCH_OPCODE();
846                         HANDLE_OPCODE(OP_CONV_FI):
847                                 OPC->_int = OPA->_float;
848                                 DISPATCH_OPCODE();
849                         HANDLE_OPCODE(OP_BITAND_I):
850                                 OPC->_int = OPA->_int & OPB->_int;
851                                 DISPATCH_OPCODE();
852                         HANDLE_OPCODE(OP_BITOR_I):
853                                 OPC->_int = OPA->_int | OPB->_int;
854                                 DISPATCH_OPCODE();
855                         HANDLE_OPCODE(OP_BITAND_IF):
856                                 OPC->_int = OPA->_int & (prvm_int_t)OPB->_float;
857                                 DISPATCH_OPCODE();
858                         HANDLE_OPCODE(OP_BITOR_IF):
859                                 OPC->_int = OPA->_int | (prvm_int_t)OPB->_float;
860                                 DISPATCH_OPCODE();
861                         HANDLE_OPCODE(OP_BITAND_FI):
862                                 OPC->_float = (prvm_int_t)OPA->_float & OPB->_int;
863                                 DISPATCH_OPCODE();
864                         HANDLE_OPCODE(OP_BITOR_FI):
865                                 OPC->_float = (prvm_int_t)OPA->_float | OPB->_int;
866                                 DISPATCH_OPCODE();
867                         HANDLE_OPCODE(OP_GE_I):
868                                 OPC->_float = OPA->_int >= OPB->_int;
869                                 DISPATCH_OPCODE();
870                         HANDLE_OPCODE(OP_LE_I):
871                                 OPC->_float = OPA->_int <= OPB->_int;
872                                 DISPATCH_OPCODE();
873                         HANDLE_OPCODE(OP_GT_I):
874                                 OPC->_float = OPA->_int > OPB->_int;
875                                 DISPATCH_OPCODE();
876                         HANDLE_OPCODE(OP_LT_I):
877                                 OPC->_float = OPA->_int < OPB->_int;
878                                 DISPATCH_OPCODE();
879                         HANDLE_OPCODE(OP_AND_I):
880                                 OPC->_float = OPA->_int && OPB->_int;
881                                 DISPATCH_OPCODE();
882                         HANDLE_OPCODE(OP_OR_I):
883                                 OPC->_float = OPA->_int || OPB->_int;
884                                 DISPATCH_OPCODE();
885                         HANDLE_OPCODE(OP_GE_IF):
886                                 OPC->_float = (prvm_vec_t)OPA->_int >= OPB->_float;
887                                 DISPATCH_OPCODE();
888                         HANDLE_OPCODE(OP_LE_IF):
889                                 OPC->_float = (prvm_vec_t)OPA->_int <= OPB->_float;
890                                 DISPATCH_OPCODE();
891                         HANDLE_OPCODE(OP_GT_IF):
892                                 OPC->_float = (prvm_vec_t)OPA->_int > OPB->_float;
893                                 DISPATCH_OPCODE();
894                         HANDLE_OPCODE(OP_LT_IF):
895                                 OPC->_float = (prvm_vec_t)OPA->_int < OPB->_float;
896                                 DISPATCH_OPCODE();
897                         HANDLE_OPCODE(OP_AND_IF):
898                                 OPC->_float = (prvm_vec_t)OPA->_int && OPB->_float;
899                                 DISPATCH_OPCODE();
900                         HANDLE_OPCODE(OP_OR_IF):
901                                 OPC->_float = (prvm_vec_t)OPA->_int || OPB->_float;
902                                 DISPATCH_OPCODE();
903                         HANDLE_OPCODE(OP_GE_FI):
904                                 OPC->_float = OPA->_float >= (prvm_vec_t)OPB->_int;
905                                 DISPATCH_OPCODE();
906                         HANDLE_OPCODE(OP_LE_FI):
907                                 OPC->_float = OPA->_float <= (prvm_vec_t)OPB->_int;
908                                 DISPATCH_OPCODE();
909                         HANDLE_OPCODE(OP_GT_FI):
910                                 OPC->_float = OPA->_float > (prvm_vec_t)OPB->_int;
911                                 DISPATCH_OPCODE();
912                         HANDLE_OPCODE(OP_LT_FI):
913                                 OPC->_float = OPA->_float < (prvm_vec_t)OPB->_int;
914                                 DISPATCH_OPCODE();
915                         HANDLE_OPCODE(OP_AND_FI):
916                                 OPC->_float = OPA->_float && (prvm_vec_t)OPB->_int;
917                                 DISPATCH_OPCODE();
918                         HANDLE_OPCODE(OP_OR_FI):
919                                 OPC->_float = OPA->_float || (prvm_vec_t)OPB->_int;
920                                 DISPATCH_OPCODE();
921                         HANDLE_OPCODE(OP_NOT_I):
922                                 OPC->_float = !OPA->_int;
923                                 DISPATCH_OPCODE();
924                         HANDLE_OPCODE(OP_EQ_I):
925                                 OPC->_float = OPA->_int == OPB->_int;
926                                 DISPATCH_OPCODE();
927                         HANDLE_OPCODE(OP_EQ_IF):
928                                 OPC->_float = (prvm_vec_t)OPA->_int == OPB->_float;
929                                 DISPATCH_OPCODE();
930                         HANDLE_OPCODE(OP_EQ_FI):
931                                 OPC->_float = OPA->_float == (prvm_vec_t)OPB->_int;
932                                 DISPATCH_OPCODE();
933                         HANDLE_OPCODE(OP_NE_I):
934                                 OPC->_float = OPA->_int != OPB->_int;
935                                 DISPATCH_OPCODE();
936                         HANDLE_OPCODE(OP_NE_IF):
937                                 OPC->_float = (prvm_vec_t)OPA->_int != OPB->_float;
938                                 DISPATCH_OPCODE();
939                         HANDLE_OPCODE(OP_NE_FI):
940                                 OPC->_float = OPA->_float != (prvm_vec_t)OPB->_int;
941                                 DISPATCH_OPCODE();
942                         HANDLE_OPCODE(OP_STORE_I):
943                         HANDLE_OPCODE(OP_STORE_P):
944                                 OPB->_int = OPA->_int;
945                                 DISPATCH_OPCODE();
946                         HANDLE_OPCODE(OP_STOREP_I):
947 #if PRBOUNDSCHECK
948                                 if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
949                                 {
950                                         PRE_ERROR();
951                                         prog->error_cmd("%s Progs attempted to write to an out of bounds edict", prog->name);
952                                         goto cleanup;
953                                 }
954 #endif
955                                 ptr = (prvm_eval_t *)(prog->edictsfields.ip + OPB->_int);
956                                 ptr->_int = OPA->_int;
957                                 DISPATCH_OPCODE();
958                         HANDLE_OPCODE(OP_LOAD_I):
959 #if PRBOUNDSCHECK
960                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
961                                 {
962                                         PRE_ERROR();
963                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
964                                         goto cleanup;
965                                 }
966                                 if (OPB->_int < 0 || OPB->_int >= progs->entityfields.ip)
967                                 {
968                                         PRE_ERROR();
969                                         prog->error_cmd("%s Progs attempted to read an invalid field in an edict", prog->name);
970                                         goto cleanup;
971                                 }
972 #endif
973                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
974                                 OPC->_int = ((prvm_eval_t *)((int *)ed->fields.ip + OPB->_int))->_int;
975                                 DISPATCH_OPCODE();
976
977                         HANDLE_OPCODE(OP_GSTOREP_I):
978                         HANDLE_OPCODE(OP_GSTOREP_F):
979                         HANDLE_OPCODE(OP_GSTOREP_ENT):
980                         HANDLE_OPCODE(OP_GSTOREP_FLD):          // integers
981                         HANDLE_OPCODE(OP_GSTOREP_S):
982                         HANDLE_OPCODE(OP_GSTOREP_FNC):          // pointers
983                                 if (OPB->_int < 0 || OPB->_int >= prog->numglobaldefs)
984                                 {
985                                         PRE_ERROR();
986                                         prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
987                                         goto cleanup;
988                                 }
989                                 prog->globals.ip[OPB->_int] = OPA->_int;
990                                 DISPATCH_OPCODE();
991                         HANDLE_OPCODE(OP_GSTOREP_V):
992                                 if (OPB->_int < 0 || OPB->_int + 2 >= prog->numglobaldefs)
993                                 {
994                                         PRE_ERROR();
995                                         prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
996                                         goto cleanup;
997                                 }
998                                 prog->globals.ip[OPB->_int  ] = OPA->ivector[0];
999                                 prog->globals.ip[OPB->_int+1] = OPA->ivector[1];
1000                                 prog->globals.ip[OPB->_int+2] = OPA->ivector[2];
1001                                 DISPATCH_OPCODE();
1002
1003                         HANDLE_OPCODE(OP_GADDRESS):
1004                                 i = OPA->_int + (prvm_int_t) OPB->_float;
1005                                 if (i < 0 || i >= prog->numglobaldefs)
1006                                 {
1007                                         PRE_ERROR();
1008                                         prog->error_cmd("%s Progs attempted to address an out of bounds global", prog->name);
1009                                         goto cleanup;
1010                                 }
1011                                 OPC->_int = prog->globals.ip[i];
1012                                 DISPATCH_OPCODE();
1013
1014                         HANDLE_OPCODE(OP_GLOAD_I):
1015                         HANDLE_OPCODE(OP_GLOAD_F):
1016                         HANDLE_OPCODE(OP_GLOAD_FLD):
1017                         HANDLE_OPCODE(OP_GLOAD_ENT):
1018                         HANDLE_OPCODE(OP_GLOAD_S):
1019                         HANDLE_OPCODE(OP_GLOAD_FNC):
1020                                 // FIXME?: Is this correct?             vvvvvvvvvvvvv
1021                                 if (OPA->_int < 0 || OPA->_int >= prog->numglobaldefs)
1022                                 {
1023                                         PRE_ERROR();
1024                                         prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
1025                                         goto cleanup;
1026                                 }
1027                                 OPC->_int = prog->globals.ip[OPA->_int];
1028                                 DISPATCH_OPCODE();
1029
1030                         HANDLE_OPCODE(OP_GLOAD_V):
1031                                 // FIXME?: Is this correct?                 vvvvvvvvvvvvv
1032                                 if (OPA->_int < 0 || OPA->_int + 2 >= prog->numglobaldefs)
1033                                 {
1034                                         PRE_ERROR();
1035                                         prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
1036                                         goto cleanup;
1037                                 }
1038                                 OPC->ivector[0] = prog->globals.ip[OPA->_int  ];
1039                                 OPC->ivector[1] = prog->globals.ip[OPA->_int+1];
1040                                 OPC->ivector[2] = prog->globals.ip[OPA->_int+2];
1041                                 DISPATCH_OPCODE();
1042
1043                         HANDLE_OPCODE(OP_BOUNDCHECK):
1044                                 if (OPA->_int < 0 || OPA->_int >= OPB->_int)
1045                                 {
1046                                         PRE_ERROR();
1047                                         prog->error_cmd("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", prog->name, OPB->_int, OPC->_int);
1048                                         goto cleanup;
1049                                 }
1050                                 DISPATCH_OPCODE();
1051
1052 #if !USE_COMPUTED_GOTOS
1053                         default:
1054                                 PRE_ERROR();
1055                                 prog->error_cmd("Bad opcode %i in %s", st->op, prog->name);
1056                                 goto cleanup;
1057                         }
1058 #if PRVMSLOWINTERPRETER
1059                         {
1060                                 if (prog->watch_global_type != ev_void)
1061                                 {
1062                                         prvm_eval_t *g = PRVM_GLOBALFIELDVALUE(prog->watch_global);
1063                                         prog->xstatement = st - cached_statements;
1064                                         PRVM_Watchpoint(prog, 0, "Global watchpoint hit", prog->watch_global_type, &prog->watch_global_value, g);
1065                                 }
1066                                 if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
1067                                 {
1068                                         prvm_eval_t *g = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
1069                                         prog->xstatement = st - cached_statements;
1070                                         PRVM_Watchpoint(prog, 0, "Entityfield watchpoint hit", prog->watch_field_type, &prog->watch_edictfield_value, g);
1071                                 }
1072                         }
1073 #endif
1074                 }
1075 #endif // !USE_COMPUTED_GOTOS
1076
1077 #undef DISPATCH_OPCODE
1078 #undef HANDLE_OPCODE
1079 #undef USE_COMPUTED_GOTOS
1080 #undef PRE_ERROR
1081 #undef ADVANCE_PROFILE_BEFORE_JUMP