1 /******************************** -*- C -*- ****************************
2  *
3  *	Byte Code interpreter declarations.
4  *
5  *
6  ***********************************************************************/
7 
8 /***********************************************************************
9  *
10  * Copyright 1988,89,90,91,92,94,95,99,2000,2001,2002,2006,2007,2008,2009
11  * Free Software Foundation, Inc.
12  * Written by Steve Byrne.
13  *
14  * This file is part of GNU Smalltalk.
15  *
16  * GNU Smalltalk is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the Free
18  * Software Foundation; either version 2, or (at your option) any later
19  * version.
20  *
21  * Linking GNU Smalltalk statically or dynamically with other modules is
22  * making a combined work based on GNU Smalltalk.  Thus, the terms and
23  * conditions of the GNU General Public License cover the whole
24  * combination.
25  *
26  * In addition, as a special exception, the Free Software Foundation
27  * give you permission to combine GNU Smalltalk with free software
28  * programs or libraries that are released under the GNU LGPL and with
29  * independent programs running under the GNU Smalltalk virtual machine.
30  *
31  * You may copy and distribute such a system following the terms of the
32  * GNU GPL for GNU Smalltalk and the licenses of the other code
33  * concerned, provided that you include the source code of that other
34  * code when and as the GNU GPL requires distribution of source code.
35  *
36  * Note that people who make modified versions of GNU Smalltalk are not
37  * obligated to grant this special exception for their modified
38  * versions; it is their choice whether to do so.  The GNU General
39  * Public License gives permission to release a modified version without
40  * this exception; this exception also makes it possible to release a
41  * modified version which carries forward this exception.
42  *
43  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
44  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
45  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
46  * more details.
47  *
48  * You should have received a copy of the GNU General Public License along with
49  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
50  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
51  *
52  ***********************************************************************/
53 
54 
55 #ifndef GST_INTERP_H
56 #define GST_INTERP_H
57 
58 /* The number of available process priorities */
59 #define NUM_PRIORITIES		 9
60 #define USER_SCHEDULING_PRIORITY 4
61 
62 /* Ordering of file operations must match that used in
63    FileStream.st */
64 enum
65 {
66   PRIM_OPEN_FILE,               /* open:mode: */
67   PRIM_CLOSE_FILE,              /* no args */
68   PRIM_PUT_CHARS,               /* data:from:to: */
69   PRIM_GET_CHARS,               /* data:from:to: */
70   PRIM_FSEEK_SET,               /* position: */
71   PRIM_FTELL,                   /* no args */
72   PRIM_FEOF,                    /* no args */
73   PRIM_OPEN_PIPE,               /* open:mode: */
74   PRIM_FSEEK_CUR,               /* skip: */
75   PRIM_FSIZE,                   /* no args */
76   PRIM_FTRUNCATE,               /* no args */
77   PRIM_FILEIN,                  /* no args */
78   PRIM_FILEIN_AT,               /* line:file:charPos: */
79   PRIM_SYNC_POLL,               /* read/write/exception */
80   PRIM_ASYNC_POLL,              /* operation:semaphore: */
81   PRIM_IS_PIPE,                 /* no args */
82   PRIM_MK_TEMP,                 /* base: */
83   PRIM_GET_CHARS_AT,            /* data:from:to:absOfs: */
84   PRIM_PUT_CHARS_AT,            /* data:from:to:absOfs: */
85   PRIM_SHUTDOWN_WRITE           /* shutdown */
86 };
87 
88 /* These macros are used to quickly compute the number of words needed
89    for a context with a maximum allowable stack depth of DEPTH.  */
90 #define FIXED_CTX_SIZE	(sizeof(struct gst_method_context) / sizeof(PTR) - 1)
91 #define CTX_SIZE(depth) (((depth) << DEPTH_SCALE) + FIXED_CTX_SIZE)
92 
93 #define DUMMY_NATIVE_IP FROM_INT(0)
94 
95 /* The structure of execution context objects.  */
96 typedef struct gst_context_part
97 {
98   OBJ_HEADER;
99   OOP parentContext;
100   OOP native_ip;		/* used by JIT */
101   OOP ipOffset;			/* an integer byte index into method */
102   OOP spOffset;			/* an integer index into cur context
103 				   stack */
104   OOP receiver;			/* the receiver OOP */
105   OOP method;			/* the method that we're executing */
106   OOP x;			/* depends on the subclass */
107   OOP contextStack[1];
108 } *gst_context_part;
109 
110 typedef struct gst_method_context
111 {
112   OBJ_HEADER;
113   OOP parentContext;
114   OOP native_ip;		/* used by JIT */
115   OOP ipOffset;			/* an integer byte index into method */
116   OOP spOffset;			/* an integer index into cur context
117 				   stack */
118   OOP receiver;			/* the receiver OOP */
119   OOP method;			/* the method that we're executing */
120   intptr_t flags;		/* must be an int to distinguish
121 				   gst_compiled_block/gst_method_context
122 				 */
123   OOP contextStack[1];
124 } *gst_method_context;
125 
126 /* CompiledMethod cache (see descriptions in interp-bc.inl and
127    interp-jit.inl) */
128 typedef struct method_cache_entry
129 {
130   OOP selectorOOP;
131   OOP startingClassOOP;
132   OOP methodOOP;
133   OOP methodClassOOP;
134   method_header methodHeader;
135 #ifdef ENABLE_JIT_TRANSLATION
136   OOP receiverClass;
137   PTR nativeCode;
138   PTR dummy;                    /* 32 bytes are usually a sweet spot */
139 #endif
140 } method_cache_entry;
141 
142 
143 /* MCF stands for MethodContext Flag.  */
144 
145 /* This is always set so that Smalltalk sees the flags member as
146    a SmallInteger.  BlockContexts store the outer context there,
147    so it is never a SmallInteger.  */
148 #define MCF_IS_METHOD_CONTEXT         1
149 
150 /* Answer whether this context must be skipped when doing a local
151    method return.  Contexts are marked this way when an exception
152    occurs or if there is a non-local method return and there are
153    active #ensure: calls.  */
154 #define MCF_IS_DISABLED_CONTEXT       2
155 
156 /* Answer whether this context must not be discarded upon a non-local
157    method return.  Contexts evaluating #ensure: and/or #ifCurtailed:
158    are marked this way.  */
159 #define MCF_IS_UNWIND_CONTEXT         4
160 
161 /* Answer whether execution started from this context (this kind
162    of MethodContext is used to mark call-ins from C to Smalltalk
163    and is placed on top of the context that was executing at the
164    time of the call-in, and is the parent of the called-in method).  */
165 #define MCF_IS_EXECUTION_ENVIRONMENT  8
166 
167 
168 typedef struct gst_block_context
169 {
170   OBJ_HEADER;
171   OOP parentContext;
172   OOP native_ip;		/* used by JIT */
173   OOP ipOffset;			/* an integer byte index into method */
174   OOP spOffset;			/* an integer index into cur context
175 				   stack */
176   OOP receiver;			/* the receiver OOP */
177   OOP method;			/* the method that we're executing */
178   OOP outerContext;		/* the parent gst_block_context or
179 				   gst_method_context */
180   OOP contextStack[1];
181 }
182  *gst_block_context;
183 
184 typedef struct gst_continuation
185 {
186   OBJ_HEADER;
187   OOP stack;
188 }
189  *gst_continuation;
190 
191 /* The structure of various objects related to the process system.  */
192 typedef struct gst_semaphore
193 {
194   OBJ_HEADER;
195   OOP firstLink;
196   OOP lastLink;
197   OOP signals;
198   OOP name;
199 }
200  *gst_semaphore;
201 
202 #define PROCESS_HEADER \
203   OBJ_HEADER; \
204   OOP nextLink; \
205   OOP suspendedContext; \
206   OOP priority; \
207   OOP myList; \
208   OOP name; \
209   OOP unwindPoints; \
210   OOP interrupts; \
211   OOP interruptLock
212 
213 typedef struct gst_process
214 {
215   PROCESS_HEADER;
216 }
217  *gst_process;
218 
219 typedef struct gst_callin_process
220 {
221   PROCESS_HEADER;
222   OOP returnedValue;
223 }
224  *gst_callin_process;
225 
226 typedef struct gst_processor_scheduler
227 {
228   OBJ_HEADER;
229   OOP processLists;
230   OOP activeProcess;
231   OOP idleTasks;
232   OOP processTimeslice;
233   OOP gcSemaphore;
234   OOP gcArray;
235 }
236  *gst_processor_scheduler;
237 
238 /* Some performance counters from the interpreter: these
239    count the number of special returns.  */
240 extern unsigned long _gst_literal_returns
241   ATTRIBUTE_HIDDEN, _gst_inst_var_returns
242   ATTRIBUTE_HIDDEN,
243   _gst_self_returns
244   ATTRIBUTE_HIDDEN;
245 
246 /* The number of primitives executed.  */
247 extern unsigned long _gst_primitives_executed
248   ATTRIBUTE_HIDDEN;
249 
250 /* The number of bytecodes executed.  */
251 extern unsigned long _gst_bytecode_counter
252   ATTRIBUTE_HIDDEN;
253 
254 /* The number of method cache misses */
255 extern unsigned long _gst_cache_misses
256   ATTRIBUTE_HIDDEN;
257 
258 /* The number of cache lookups - either hits or misses */
259 extern unsigned long _gst_sample_counter
260   ATTRIBUTE_HIDDEN;
261 
262 /* If this is true, for each byte code that is executed, we print on
263    stdout the byte index within the current gst_compiled_method and a
264    decoded interpretation of the byte code.  If > 1, it applies also
265    to code not invoked by the user.  */
266 extern int _gst_execution_tracing
267   ATTRIBUTE_HIDDEN;
268 
269 /* When this is true, and an interrupt occurs (such as SIGSEGV),
270    Smalltalk will terminate itself by making a core dump (normally it
271    produces a backtrace).  */
272 extern mst_Boolean _gst_make_core_file
273   ATTRIBUTE_HIDDEN;
274 
275 /* When true, this indicates that there is no top level loop for
276    control to return to, so it causes the system to exit.  */
277 extern mst_Boolean _gst_non_interactive
278   ATTRIBUTE_HIDDEN;
279 
280 /* The OOP for a gst_compiled_method or gst_compiled_block that is the
281    currently executing method.  */
282 extern OOP _gst_this_method
283   ATTRIBUTE_HIDDEN;
284 
285 /* Physical address of the base of the method temporary variables.
286    Typically a small number of bytes (multiple of 4 since it points to
287    OOPs) lower than sp.  */
288 extern OOP *_gst_temporaries
289   ATTRIBUTE_HIDDEN;
290 
291 /* Physical address of the base of the method literals.  */
292 extern OOP *_gst_literals
293   ATTRIBUTE_HIDDEN;
294 
295 /* An OOP that is the current receiver of the current message.  */
296 extern OOP _gst_self
297   ATTRIBUTE_HIDDEN;
298 
299 /* A gst_block_context or gst_method_context that indicates the
300    context that the interpreter is currently running in.  */
301 extern OOP _gst_this_context_oop
302   ATTRIBUTE_HIDDEN;
303 
304 /* The OOP for an IdentityDictionary that stores the raw profile. */
305 extern OOP _gst_raw_profile
306   ATTRIBUTE_HIDDEN;
307 
308 /* A bytecode counter value used while profiling. */
309 extern unsigned long _gst_saved_bytecode_counter
310   ATTRIBUTE_HIDDEN;
311 
312 /* The type used to hold the instruction pointer.  For the JIT, this
313    is an offset from a location which is deemed the `base' of
314    native-compiled methods (because this way it will fit in a
315    SmallInteger and can be stored in the returnIP field of the context
316    objects); for the interpreter, this is the physical address of the
317    next executed bytecode (note: the global is usually synchronized at
318    sequence points only).  */
319 #ifdef ENABLE_JIT_TRANSLATION
320 typedef int ip_type;
321 extern char *native_ip;
322 #else /* plain bytecode interpreter */
323 typedef gst_uchar *ip_type;
324 #endif
325 #define ip			_gst_ip
326 
327 extern ip_type ip
328   ATTRIBUTE_HIDDEN;
329 
330 typedef struct async_queue_entry
331 {
332   void (*func) (OOP);
333   OOP data;
334   struct async_queue_entry *next;
335 }
336 async_queue_entry;
337 
338 /* When not NULL, this causes the byte code interpreter to immediately
339    send the message whose selector is here to the current stack
340    top.  */
341 extern const char *_gst_abort_execution
342   ATTRIBUTE_HIDDEN;
343 
344 
345 /* Set to true when some special action must be done at the next
346    sequence point.  */
347 #ifdef ENABLE_JIT_TRANSLATION
348 extern mst_Boolean _gst_except_flag
349   ATTRIBUTE_HIDDEN;
350 #endif
351 
352 /* Create a new Process on the top of the stack, which is specially
353    marked so that it stops the interpreter's execution.  This kind
354    of MethodContext is used to mark call-ins from C to Smalltalk
355    and is the parent of the called-in method.  Return the Process.  */
356 extern OOP _gst_prepare_execution_environment (void)
357   ATTRIBUTE_HIDDEN;
358 
359 /* Sends SELECTOR (which should be a Symbol, otherwise _gst_nil_oop is
360    returned) to RECEIVER.  The message arguments should also be OOPs
361    (otherwise, an access violation exception is pretty likely) and are
362    passed in an array ARGS of size NARGS.  The value returned from the
363    method is passed back as an OOP to the C program as the result of
364    the function, or _gst_nil_oop if the number of arguments is wrong.  */
365 extern OOP _gst_nvmsg_send (OOP receiver,
366 			    OOP selector,
367 			    OOP *args,
368 			    int nArgs)
369   ATTRIBUTE_HIDDEN;
370 
371 /* Start the interpreter, and go on until we terminate PROCESSOOP.  */
372 extern OOP _gst_interpret (OOP processOOP)
373   ATTRIBUTE_HIDDEN;
374 
375 /* Internal function for SEND_MESSAGE and for sends to super; send
376    SENDSELECTOR, with SENDARGS arguments, to RECEIVER.  Start looking
377    for the method in METHOD_CLASS.
378 
379    On entry to this routine, the stack should have the receiver and
380    the arguments pushed on the stack.  We need to get a new context,
381    setup things like the IP, SP, and Temporary pointers, and then
382    return.  Note that this routine DOES NOT invoke the interpreter; it
383    merely sets up a new context so that calling (or, more typically,
384    returning to) the interpreter will operate properly.  This kind of
385    sending is for normal messages only.  Things like sending a "value"
386    message to a block context are handled by primitives which do
387    similar things, but they use information from gst_block_closure
388    objects that we don't have available (nor need) here.  */
389 extern void _gst_send_message_internal (OOP sendSelector,
390 			      int sendArgs,
391 			      OOP receiver,
392 			      OOP method_class)
393   ATTRIBUTE_HIDDEN;
394 
395 /* Prepare the data structures held by the interpreter.  */
396 extern void _gst_init_interpreter (void)
397   ATTRIBUTE_HIDDEN;
398 
399 /* Reset the fast allocator for context objects, telling it that
400    all contexts living there have been tenured and thus the space
401    can be reused.  */
402 extern void _gst_empty_context_pool (void)
403   ATTRIBUTE_HIDDEN;
404 
405 /* Return whether there are pending asynchronous calls.  */
406 extern mst_Boolean _gst_have_pending_async_calls (void)
407   ATTRIBUTE_HIDDEN;
408 
409 /* Set up so that FUNC will be called, with ARGOOP as its argument,
410    as soon as the next sequence point is reached.  */
411 extern void _gst_async_call (void (*func) (OOP),
412                              OOP argOOP)
413   ATTRIBUTE_HIDDEN;
414 
415 /* Worker functions for _gst_async_call_internal.  */;
416 extern void _gst_do_async_signal (OOP semaphoreOOP)
417   ATTRIBUTE_HIDDEN;
418 extern void _gst_do_async_signal_and_unregister (OOP semaphoreOOP)
419   ATTRIBUTE_HIDDEN;
420 
421 /* Set up so that ENTRY->FUNC will be called, with ENTRY->DATA as its
422    argument, as soon as the next sequence point is reached.  Async-signal
423    safe version.  */
424 extern void _gst_async_call_internal (async_queue_entry *entry)
425   ATTRIBUTE_HIDDEN;
426 
427 /* Signal SEMAPHOREOOP so that one of the processes waiting on that
428    semaphore is waken up.  Since a Smalltalk call-in is not an atomic
429    operation, the correct way to signal a semaphore is not to send
430    #signal to the object but, rather, to use this function.  The
431    signal request will be processed as soon as the next sequence point
432    is reached.  */
433 extern void _gst_async_signal (OOP semaphoreOOP)
434   ATTRIBUTE_HIDDEN;
435 
436 /* Signal SEMAPHOREOOP so that one of the processes waiting on that
437    semaphore is waken up, and remove it from the registry.  Since a
438    Smalltalk call-in is not an atomic operation, the correct way to
439    signal a semaphore is not to send #signal to the object but,
440    rather, to use this function.  The signal request will be processed
441    as soon as the next sequence point is reached.  */
442 extern void _gst_async_signal_and_unregister (OOP semaphoreOOP)
443   ATTRIBUTE_HIDDEN;
444 
445 /* Invalidate all the cached CompiledMethod lookups.  This does NOT
446    include inline caches when the JIT compiler is active.  */
447 extern void _gst_invalidate_method_cache (void)
448   ATTRIBUTE_HIDDEN;
449 
450 /* Show a backtrace of the current state of the stack of execution
451    contexts.  */
452 extern void _gst_show_backtrace (FILE *)
453   ATTRIBUTE_HIDDEN;
454 
455 /* Trap the signals that we care about, basically SIGBUS and
456    SIGSEGV.  */
457 extern void _gst_init_signals (void)
458   ATTRIBUTE_HIDDEN;
459 
460 /* Store the context of the VM registers into the currently executing
461    contexts.  Since the contexts store relative addresses, these are
462    valid across GCs and we can count on them and on the OOPs (which do
463    not move) to adjust the interior pointers that the VM uses.  Note
464    that normally fields such as SP or IP are not valid for the
465    currently executing contexts (they are only used after a message
466    send) so we need a special function to ensure that even that
467    context has the information saved in it.  */
468 extern void _gst_fixup_object_pointers (void)
469   ATTRIBUTE_HIDDEN;
470 
471 /* Complementary to _gst_fixup_object_pointers, this function picks
472    the relative addresses stored in the current context and uses
473    them to adjust the VM registers after the heap is compacted or
474    grown.  */
475 extern void _gst_restore_object_pointers (void)
476   ATTRIBUTE_HIDDEN;
477 
478 /* This runs before every evaluation and before GC turned on.  It creates an
479    initial process if no process is ready to run or if no process has been
480    created yet.  */
481 extern void _gst_init_process_system (void)
482   ATTRIBUTE_HIDDEN;
483 
484 /* These function mark or copy all the objects that the interpreter keeps in
485    the root set.  These are the semaphores that are held to be
486    signaled by an asynchronous event (note that they *are* in the root
487    set because they could be the only way from which we can get to the
488    suspended process!), the semaphores that are queued to be signaled
489    at the next sequence point (_gst_async_signals queues them) and the
490    currently executing context.  Everything else is supposedly
491    reachable from the current context (including the current method,
492    the receiver, the receiver class even if it does not live in a
493    namespace, and all the context on the execution stack) or from
494    Processor (including the current process and the other active
495    processes).  Processor itself is reachable from the Smalltalk
496    dictionary.  */
497 extern void _gst_mark_processor_registers (void)
498   ATTRIBUTE_HIDDEN;
499 extern void _gst_copy_processor_registers (void)
500   ATTRIBUTE_HIDDEN;
501 
502 /* Print the current state of the lists of ready to run processes for
503    each priority, for debugging purposes.  */
504 extern void _gst_print_process_state (void)
505   ATTRIBUTE_HIDDEN;
506 
507 /* Sanity check the process lists that the sole instance of ProcessorScheduler
508    holds.  */
509 extern void _gst_check_process_state (void)
510   ATTRIBUTE_HIDDEN;
511 
512 /* Print the objects currently on the stack, for debugging
513    purposes.  */
514 extern void _gst_show_stack_contents (void)
515   ATTRIBUTE_HIDDEN;
516 
517 /* Called after the mark phase, but before the sweep phase, so that if
518    a method cache entry is not valid anymore it is cleared.  This is
519    because in the JIT case a method cache entry is invalidated not
520    only if the related method does not exist anymore (and this is done
521    by the Smalltalk implementation of the MethodDictionary class) but
522    also if the translation to native code for the method is garbage
523    collected.  In particular, this function is called *after* the
524    unused method translations are marked as such, and *before* they
525    are actually freed.  */
526 extern void _gst_validate_method_cache_entries (void)
527   ATTRIBUTE_HIDDEN;
528 
529 /* Terminate execution of the given PROCESSOOP.  */
530 extern void _gst_terminate_process (OOP processOOP)
531   ATTRIBUTE_HIDDEN;
532 
533 /* This is a further simplified lookup_method which does not care
534    about preparing for #doesNotUnderstand:.  */
535 extern mst_Boolean _gst_find_method (OOP classOOP, OOP sendSelector,
536 				     method_cache_entry *mce)
537   ATTRIBUTE_HIDDEN;
538 
539 /* Similar to _gst_send_message_internal, but forces the specified
540    CompiledMethod to be sent.  If it is not valid for the current
541    receiver, well, you are looking for trouble and well deserve it.
542    The number of arguments is looked in METHODOOP.  */
543 extern void _gst_send_method (OOP methodOOP)
544   ATTRIBUTE_HIDDEN;
545 
546 /* This functions accepts an OOP for a Semaphore object and puts the
547    current process to sleep, unless the semaphore has excess signals
548    on it.  Since a Smalltalk call-in is not an atomic operation, the
549    correct way to signal a semaphore is not to send the wait method to
550    the object but, rather, to use _gst_sync_wait.  The `sync' in the
551    name of this function distinguishes it from _gst_async_signal, in
552    that it cannot be called from within a signal handler.  */
553 extern void _gst_sync_wait (OOP semaphoreOOP)
554   ATTRIBUTE_HIDDEN;
555 
556 /* Signal the given SEMAPHOREOOP and if processes were queued on it
557    resume the one that has waited for the longest time and is still
558    alive.  If INCR is true, increment its value if no processes were
559    queued.  Return true if a process was woken.
560 
561    This functions also cannot be called from within a signal handler.
562    It can be called from a function that is registered with
563    _gst_async_call, though.  */
564 extern mst_Boolean _gst_sync_signal (OOP semaphoreOOP,
565 			      mst_Boolean incr_if_empty)
566   ATTRIBUTE_HIDDEN;
567 
568 /* Take a CompiledBlock and turn it into a BlockClosure that references
569    thisContext as its static link.  */
570 extern OOP _gst_make_block_closure (OOP blockOOP)
571   ATTRIBUTE_HIDDEN;
572 
573 /************************************************* PRIMITIVES ****************/
574 
575 /* The type for a routine providing the definition for one or more
576    primitive methods in the GNU Smalltalk system.  They normally
577    remove the arguments to the primitive methods from the stack, but
578    if the primitive fails, the arguments are put back onto the stack
579    and the routine returns true (-1 for the JIT), indicating failure
580    to invoke the primitive.  Such a function must execute a primitive,
581    aided in the choice of which by the user-defined parameter ID,
582    popping NUMARGS methods off the stack if they succeed.  */
583 typedef intptr_t (*primitive_func) (int primitive,
584 				    volatile int numArgs);
585 
586 /* Table of primitives, including a primitive and its attributes.  */
587 typedef struct prim_table_entry
588 {
589   const char *name;
590   primitive_func func;
591   int attributes;
592   int id;
593 }
594 prim_table_entry;
595 
596 #define PRIM_SUCCEED			0x0001
597 #define PRIM_FAIL			0x0002
598 #define PRIM_RELOAD_IP			0x0004
599 #define PRIM_OUTCOMES			0x0007
600 #define PRIM_CACHE_NEW_IP		0x0008
601 #define PRIM_INLINED			0x0010
602 #define PRIM_CHECK_INTERRUPT		0x0020
603 #define PRIM_RETURN_SMALL_INTEGER	0x0100	/* 31 or 63 bits */
604 #define PRIM_RETURN_SMALL_SMALLINTEGER	0x0300	/* 30 or 62 bits */
605 
606 /* The checksum of the table of primitive numbers.  Right now it is an MD5,
607    computed from part of the C source code of prims.inl.  We compare it when
608    loading an image, to avoid having to reload the primitive table.  */
609 extern unsigned char _gst_primitives_md5[16];
610 
611 /* The table of functions that implement the primitives.  */
612 extern prim_table_entry _gst_primitive_table[NUM_PRIMITIVES];
613 extern prim_table_entry _gst_default_primitive_table[NUM_PRIMITIVES];
614 
615 /* This can be used to obtain information on a particular primitive
616    operations in the GNU Smalltalk system.  */
617 extern prim_table_entry * _gst_get_primitive_attributes (int primitive)
618   ATTRIBUTE_PURE
619   ATTRIBUTE_HIDDEN;
620 
621 /* Dually, this maps the primitive number that will be used for running
622    the image, to the entry which was returned by _gst_get_primitive_attributes.
623    If PTE is NULL, the primitive will be invalid.  */
624 extern void _gst_set_primitive_attributes (int primitive,
625 					   prim_table_entry *pte)
626   ATTRIBUTE_HIDDEN;
627 
628 /* Initialize the table of primitives.  */
629 extern void _gst_init_primitives ()
630   ATTRIBUTE_HIDDEN;
631 
632 /* Get the value of internal variable whose number is INDEX; the
633    list of valid variables is in gstpub.h.  Return -1 if the index
634    is invalid.  */
635 extern int _gst_get_var (enum gst_var_index index)
636   ATTRIBUTE_HIDDEN;
637 
638 /* Set the value of internal variable whose number is INDEX; the
639    list of valid variables is in gstpub.h.  Return -1 if the index
640    is invalid or the value is negative, otherwise return the previous
641    value.  */
642 extern int _gst_set_var (enum gst_var_index index, int value)
643   ATTRIBUTE_HIDDEN;
644 
645 #endif /* GST_INTERP_H */
646