1 /* $Header: d:/cvsroot/tads/tads3/vmglob.h,v 1.2 1999/05/17 02:52:29 MJRoberts Exp $ */
2 
3 /*
4  *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
5  *
6  *   Please see the accompanying license file, LICENSE.TXT, for information
7  *   on using and copying this software.
8  */
9 /*
10 Name
11   vmglob.h - T3 VM globals
12 Function
13   The T3 VM requires a number of static variables that are shared
14   by several subsystems.  This file defines the globals and a scheme
15   for accessing them.
16 
17   The globals can be configured in four different ways, depending on
18   how the T3 VM is to be used:
19 
20     1. As individual external variables.  This is the most efficient
21        way to configure the globals, but this can't be used when
22        multiple independent VM instances are needed in a single process,
23        because each VM would need its own copy of the globals.  This
24        is the fastest way to lay out the globals, because it allows
25        the compiler to generate code that accesses internal members of
26        performance-critical global objects directly, without any pointer
27        dereferences.
28 
29     2. As members of a static global structure.  This is the second
30        most efficient way to configure the globals, but this can't be
31        used when multiple independent VM instances are needed,
32        because each VM would need its own copy of the globals, which
33        isn't possible in this configuration.  (Note that accessing
34        members of a global static structure is identical to accessing
35        global variables, since the compiler can compute the relative
36        address of a structure member at compile time and hence does
37        not need to perform any run-time pointer arithmetic or any other
38        computation beyond what it would normally use for global variable
39        access.  However, in this configuration, it's not possible to
40        allocate any of the global objects in-line within the master
41        global structure, so each global object's internal members must
42        be accessed through one pointer dereference.)
43 
44     3. As members of an allocated structure whose address is contained
45        in a global static variable.  This is slightly less efficient
46        than method 1, in that the global pointer must be dereferenced
47        on each global variable access.  This method allows multiple VM
48        instances to be used, as long as the host application specifically
49        stores the correct structure pointer in the global static variable
50        before each call to the VM; this can be used when the host system
51        uses the VM in only one thread.
52 
53     4. As members of an allocated structure whose address is passed as
54        a parameter to each function that needs global variable access.
55        As with method 2, the host application creates a structure per
56        VM instance it requires, and then passes a pointer to the correct
57        structure on each call to a VM function; the VM internally passes
58        this pointer in its own function calls where needed.  This is the
59        most flexible method, in that the VM can be used in multiple
60        thread simultaneously (as long as each thread has a separate VM
61        global structure instance), but is the least efficient, because
62        the structure pointer must be passed around on all calls.
63 
64   To select a configuration, define one of the following preprocessor
65   symbols in the makefile:
66 
67      VMGLOB_VARS    - method 1 - individual global variables
68      VMGLOB_STRUCT  - method 2 - global static structure
69      VMGLOB_POINTER - method 3 - global static pointer to allocated structure
70      VMGLOB_PARAM   - method 4 - pointer to structure passed as parameter
71 
72   We provide all of these different possible configurations because of
73   the trade-offs involved in selecting one.  The host application's needs
74   should be determined, and the most efficient configuration that meets
75   those needs should be chosen.
76 Notes
77 
78 Modified
79   11/28/98 MJRoberts  - Creation
80 */
81 
82 #ifndef VMGLOB_H
83 #define VMGLOB_H
84 
85 #include <stddef.h>
86 
87 #include "vmpoolsl.h"
88 
89 
90 /* ------------------------------------------------------------------------ */
91 /*
92  *   HOST SYSTEM GLOBAL INITIALIZATION
93  *
94  *   The host system should declare a local variable as follows:
95  *
96  *   vm_globals *vmg__; // two underscores
97  *
98  *   The program must call vmglob_alloc() each time it wants to initialize a
99  *   global variable context.  This routine must always be called at least
100  *   once.  (In the VMGLOB_STRUCT or VMGLOB_VARS configuration, this routine
101  *   has no effect, but should still be called so that the code will work
102  *   unchanged in other configurations.)  Calling this routine will overwrite
103  *   the current static global variable pointer in the VMGLOB_POINTER
104  *   configuration, so the caller must take care to keep track of each set of
105  *   globals it allocates for later restoration.
106  *
107  *   When calling vmglob_alloc(), assign the return value to vmg__.
108  */
109 
110 /*
111  *   HOST SYSTEM GLOBAL TERMINATION
112  *
113  *   The caller should invoke vmglob_delete() for each set of globals it
114  *   allocated.
115  */
116 
117 /*
118  *   HOST SYSTEM VM FUNCTION CALLS
119  *
120  *   In each call to a VM function, the host system should include the
121  *   macro "vmg_" (one underscore) at the start of each parameter list; do
122  *   not put a comma after vmg_.  Call functions that take no other
123  *   parameters with vmg0_ instead of vmg_.
124  */
125 
126 /* ------------------------------------------------------------------------ */
127 /*
128  *   INTERNAL FUNCTION DECLARATION AND CALLING
129  *
130  *   Every function that requires global access, or which calls a function
131  *   that requires global access, must put "VMG_" at the very start of its
132  *   formal parameters declaration.  Do not put a comma after VMG_, but
133  *   simply list the first parameter.  If the function has no parameters
134  *   at all, use VMG0_ instead of VMG_.  For example:
135  *
136  *   void CVmClass::func1(VMG_ const textchar_t *str, size_t len) { ... }
137  *.  void CVmClass::func2(VMG0_) { ... }
138  *
139  *   In each call to a function that uses global variables or calls
140  *   functions that use global variables, put "vmg_" at the very start of
141  *   the actual parmaeters list in the call; do not put a comma after the
142  *   vmg_.  If the function takes no parameters at all, use vmg0_ instead
143  *   of vmg_.
144  *
145  *   func1(vmg_ "test", 4);
146  *.  func2(vmg0_);
147  */
148 
149 
150 /* ------------------------------------------------------------------------ */
151 /*
152  *   Functions that themselves can't participate in the prototype
153  *   mechanism, because they present an external API to other subsystems,
154  *   must keep track of the globals on their own.  To do this, they must
155  *   stash the global pointer in their own context structure - use
156  *   VMGLOB_ADDR to get the address of the global structure.  When passing
157  *   this stashed pointer back to function calls, use vmg_var(x) (for the
158  *   first argument to a function with multiple arguments) or vmg_var0(x)
159  *   (for a single-argument call), as appropriate, where x is the local
160  *   copy.
161  *
162  *   To access globals from this type of routine, put the VMGLOB_PTR(x)
163  *   macro in with the local variable decalarations for the function,
164  *   passing as the argument the stashed address of the global structure.
165  *   This will set things up so that the G_xxx variables are accessible
166  *   through a local pointer, when necessary, and will also make the vmg_
167  *   and vmg0_ argument macros work properly.  See the examples below.
168  */
169 #if 0
170 /* EXAMPLES ONLY - THIS CODE IS FOR DOCUMENTATION ONLY */
171 
172 struct my_context_def
173 {
174     /* holder for VM globals structure pointer */
175     vm_globals *vmg;
176 };
177 
178 int func_calling_external_interfaces(VMG_ int x, int y, int z)
179 {
180     my_context_def ctx;
181 
182     /* stash the address of the VM globals in my private context */
183     ctx.vmg = VMGLOB_ADDR;
184 
185     /* call my external API function */
186     external_api_func(&ctx);
187 }
188 
189 int func_called_from_external_interface(my_context_def *ctx, int x, int y)
190 {
191     /* set up access to the VM globals through my stashed context */
192     VMGLOB_PTR(ctx->vmg);
193 
194     /* access a global variable */
195     G_myvar->do_something();
196 
197     /* call a function using a VMG_ prototype */
198     G_myvar->do_something_else(vmg_ x, y);
199 }
200 
201 #endif /* 0 */
202 
203 
204 /* ------------------------------------------------------------------------ */
205 /*
206  *   Set up to define the global variables.  For the POINTER and PARAM
207  *   configurations, put pointers to the global structures in a structure.
208  *   For the static STRUCT configuration, actually allocate all of the
209  *   objects statically.
210  *
211  *   Use VM_GLOBAL_OBJDEF() to define the entry for an object (struct or
212  *   class) type.  The global variable will be a pointer to this type.
213  *
214  *   Use VM_GLOBAL_PREOBJDEF to define the entry for an object type that's to
215  *   be defined as pre-allocated static objects in the VARS configuration.
216  *   This can be used for objects that (1) have very frequent access and thus
217  *   should have their fields reachable directly as statics rather than via
218  *   static pointers, and (2) need no constructor parameters and thus can be
219  *   pre-allocated at compile-time.  In the VARS configuration, these
220  *   variables can be allocated at compile-time, which allows the compiler to
221  *   generate code that accesses the objects' internal members without any
222  *   pointer dereferences.
223  *
224  *   Any variable defined with VM_GLOBAL_PREOBJDEF MUST have its accessor
225  *   defined through VMGLOB_PREACCESS() rather than VMGLOB_ACCESS().
226  *
227  *   Use VM_GLOBAL_VARDEF to define a scalar variable.
228  */
229 #if defined(VMGLOB_POINTER) || defined(VMGLOB_PARAM) || defined(VMGLOB_STRUCT)
230 #define VM_GLOBALS_BEGIN  struct vm_globals {
231 #define VM_GLOBAL_OBJDEF(typ, var) typ *var;
232 #define VM_GLOBAL_PREOBJDEF(typ, var) typ *var;
233 #define VM_GLOBAL_PRECOBJDEF(typ, var, ctor_args) typ *var;
234 #define VM_GLOBAL_VARDEF(typ, var) typ var;
235 #define VM_GLOBALS_END    };
236 
237 /*
238  *   we do allocate all global objects, including external objects; hence
239  *   external globals are non-static
240  */
241 #define VM_IF_ALLOC_PRE_GLOBAL(x)          x
242 #define VM_IFELSE_ALLOC_PRE_GLOBAL(x, y)   x
243 #define VM_PRE_GLOBALS_ARE_STATIC   FALSE
244 #endif
245 
246 #if defined(VMGLOB_VARS)
247 #define VM_GLOBALS_BEGIN
248 
249 #define VM_GLOBAL_OBJDEF(typ, var) extern typ *G_##var##_X;
250 #define VM_GLOBAL_PREOBJDEF(typ, var) extern typ G_##var##_X;
251 #define VM_GLOBAL_PRECOBJDEF(typ, var, ctor_args) extern typ G_##var##_X;
252 #define VM_GLOBAL_VARDEF(typ, var) extern typ G_##var##_X;
253 
254 #define VM_GLOBALS_END
255 
256 /* we don't actually need a structure for the globals; use a dummy */
257 struct vm_globals { int x; };
258 
259 /* external global objects are statically allocated */
260 #define VM_IF_ALLOC_PRE_GLOBAL(x)
261 #define VM_IFELSE_ALLOC_PRE_GLOBAL(x, y)   y
262 #define VM_PRE_GLOBALS_ARE_STATIC  TRUE
263 #endif
264 
265 
266 /* define the globals */
267 #include "vmglobv.h"
268 
269 /* ------------------------------------------------------------------------ */
270 /*
271  *   If we're not including from the global-defining source file, merely
272  *   declare the globals.
273  */
274 #ifndef VMGLOB_DECLARE
275 #define VMGLOB_DECLARE extern
276 #endif
277 
278 
279 /* ------------------------------------------------------------------------ */
280 /*
281  *   INDIVIDUAL STATIC GLOBAL VARIABLES configuration.  In this
282  *   configuration, the globals are defined as individual global variables.
283  *   This is the most efficient configuration, but it only allows one VM
284  *   instance in a given process.
285  */
286 #ifdef VMGLOB_VARS
287 
288 /* initialization - this has no effect in this mode */
vmglob_alloc()289 inline vm_globals *vmglob_alloc() { return 0; }
290 
291 /* termination - this has no effect in this mode */
vmglob_delete(vm_globals *)292 inline void vmglob_delete(vm_globals *) { }
293 
294 /*
295  *   we don't require anything for the parameter declaration or usage, since
296  *   we don't use the local parameter mechanism at all
297  */
298 #define VMG_
299 #define VMG0_
300 #define vmg_
301 #define vmg0_
302 
303 /*
304  *   get the address of the globals - this doesn't do anything in this
305  *   configuration, as there's not really a global variables structure
306  */
307 #define VMGLOB_ADDR   0
308 
309 /* pass a stashed copy of the global pointer, if necessary */
310 #define vmg_var(x)
311 #define vmg_var0(x)
312 
313 /* declare a local variable to access the globals */
314 #define VMGLOB_PTR(x)
315 
316 /* we access globals directly as individual statics */
317 #define VMGLOB_ACCESS(var) (G_##var##_X)
318 #define VMGLOB_PREACCESS(var) (&G_##var##_X)
319 
320 #endif /* VMGLOB_VARS */
321 
322 /* ------------------------------------------------------------------------ */
323 /*
324  *   STATIC GLOBAL STRUCTURE configuration.  In this configuration, the
325  *   globals are defined in a single static global structure.  This is the
326  *   second most efficient configuration, but it only allows one VM instance
327  *   per process.
328  */
329 #ifdef VMGLOB_STRUCT
330 
331 /* define the global variables structure */
332 VMGLOB_DECLARE vm_globals G_vmglobals;
333 
334 /* initialization - this has no effect in this mode */
vmglob_alloc()335 inline vm_globals *vmglob_alloc()
336 {
337     return &G_vmglobals;
338 }
339 
340 /* termination - this has no effect in this mode */
vmglob_delete(vm_globals *)341 inline void vmglob_delete(vm_globals *) { }
342 
343 /*
344  *   we don't require anything for the parameter declaration or usage,
345  *   since we don't use the local parameter mechanism at all
346  */
347 #define VMG_
348 #define VMG0_
349 #define vmg_
350 #define vmg0_
351 
352 /* get the address of the globals */
353 #define VMGLOB_ADDR   (&G_vmglobals)
354 
355 /* pass a stashed copy of the global pointer, if necessary */
356 #define vmg_var(x)
357 #define vmg_var0(x)
358 
359 /* declare a local variable to access the globals */
360 #define VMGLOB_PTR(x)
361 
362 /* we access globals directly as individual statics */
363 #define VMGLOB_ACCESS(var)    (G_vmglobals.var)
364 #define VMGLOB_PREACCESS(var) (G_vmglobals.var)
365 
366 #endif /* VMGLOB_STRUCT */
367 
368 /* ------------------------------------------------------------------------ */
369 /*
370  *   STATIC GLOBAL POINTER configuration.  In this configuration, the
371  *   globals are stored in an allocated structure whose address is stored
372  *   in a global static pointer variable.
373  */
374 #ifdef VMGLOB_POINTER
375 
376 /* define our global static pointer to the global variables */
377 VMGLOB_DECLARE vm_globals *G_vmglobals;
378 
379 /* initialization - allocate a new set of globals */
vmglob_alloc()380 inline vm_globals *vmglob_alloc()
381 {
382     G_vmglobals = new vm_globals();
383     return G_vmglobals;
384 }
385 
386 /* termination - delete a set of globals */
vmglob_delete(vm_globals * glob)387 inline void vmglob_delete(vm_globals *glob) { delete glob; }
388 
389 /*
390  *   we don't require anything for the parameter declaration or usage,
391  *   since we don't use the local parameter mechanism at all
392  */
393 #define VMG_
394 #define VMG0_
395 #define vmg_
396 #define vmg0_
397 
398 /* get the address of the globals */
399 #define VMGLOB_ADDR   G_vmglobals
400 
401 /* pass a stashed copy of the global pointer, if necessary */
402 #define vmg_var(x)
403 #define vmg_var0(x)
404 
405 /* declare a local variable to access the globals */
406 #define VMGLOB_PTR(x)
407 
408 /* accessing a global requires dereferencing the global pointer */
409 #define VMGLOB_ACCESS(var) (G_vmglobals->var)
410 #define VMGLOB_PREACCESS(var) (G_vmglobals_var)
411 
412 #endif /* VMGLOB_POINTER */
413 
414 /* ------------------------------------------------------------------------ */
415 /*
416  *   PARAMETER configuration.  In this configuration, the globals are
417  *   stored in an allocated structure whose address is passed to each VM
418  *   function as a parameter.
419  */
420 #ifdef VMGLOB_PARAM
421 
422 /* initialization - allocate a new set of globals */
vmglob_alloc()423 inline vm_globals *vmglob_alloc() { return new vm_globals(); }
424 
425 /* termination - delete a set of globals */
vmglob_delete(vm_globals * glob)426 inline void vmglob_delete(vm_globals *glob) { delete glob; }
427 
428 /* function declaration for the global pointer parameter */
429 #define VMG_   vm_globals *vmg__,
430 #define VMG0_  vm_globals *vmg__
431 
432 /* parameter reference for passing to a function */
433 #define vmg_   vmg__,
434 #define vmg0_  vmg__
435 
436 /* get the address of the globals */
437 #define VMGLOB_ADDR   vmg__
438 
439 /* pass a stashed copy of the global pointer, if necessary */
440 #define vmg_var(x)         x,
441 #define vmg_var0(x)        x
442 
443 /* declare a local variable to access the globals */
444 #define VMGLOB_PTR(x) vm_globals *vmg__ = x
445 
446 /* accessing a global variable requires dereferencing the parameter */
447 #define VMGLOB_ACCESS(var) (vmg__->var)
448 #define VMGLOB_PREACCESS(var) (vmg__->var)
449 
450 #endif /* VMGLOB_PARAM */
451 
452 /* ------------------------------------------------------------------------ */
453 /*
454  *   Global variable accessors.  For convenience, we define these cover
455  *   macros that access the global variables in the appropriate manner for
456  *   our configuration.  Code can use these G_xxx symbols syntactically as
457  *   though they were normal global variables.
458  */
459 #define G_mem         VMGLOB_ACCESS(mem)
460 #define G_undo        VMGLOB_ACCESS(undo)
461 #define G_meta_table  VMGLOB_ACCESS(meta_table)
462 #define G_bif_table   VMGLOB_ACCESS(bif_table)
463 #define G_varheap     VMGLOB_ACCESS(varheap)
464 #define G_preinit_mode VMGLOB_ACCESS(preinit_mode)
465 #define G_rand_seed   VMGLOB_ACCESS(rand_seed)
466 #define G_bif_tads_globals VMGLOB_ACCESS(bif_tads_globals)
467 #define G_res_loader  VMGLOB_ACCESS(res_loader)
468 #define G_host_ifc    VMGLOB_ACCESS(host_ifc)
469 #define G_image_loader VMGLOB_ACCESS(image_loader)
470 #define G_disp_cset_name  VMGLOB_ACCESS(disp_cset_name)
471 #define G_cmap_from_fname VMGLOB_ACCESS(cmap_from_fname)
472 #define G_cmap_to_fname VMGLOB_ACCESS(cmap_to_fname)
473 #define G_cmap_from_ui VMGLOB_ACCESS(cmap_from_ui)
474 #define G_cmap_to_ui  VMGLOB_ACCESS(cmap_to_ui)
475 #define G_cmap_from_file VMGLOB_ACCESS(cmap_from_file)
476 #define G_cmap_to_file VMGLOB_ACCESS(cmap_to_file)
477 #define G_console     VMGLOB_ACCESS(console)
478 #define G_debugger    VMGLOB_ACCESS(debugger)
479 #define G_exc_entry_size VMGLOB_ACCESS(exc_entry_size)
480 #define G_line_entry_size VMGLOB_ACCESS(line_entry_size)
481 #define G_dbg_hdr_size VMGLOB_ACCESS(dbg_hdr_size)
482 #define G_srcf_table  VMGLOB_ACCESS(srcf_table)
483 #define G_dbg_lclsym_hdr_size VMGLOB_ACCESS(dbg_lclsym_hdr_size)
484 #define G_dbg_fmt_vsn VMGLOB_ACCESS(dbg_fmt_vsn)
485 #define G_bignum_cache VMGLOB_ACCESS(bignum_cache)
486 #define G_tadsobj_queue VMGLOB_ACCESS(tadsobj_queue)
487 #define G_predef      VMGLOB_PREACCESS(predef)
488 #define G_stk         VMGLOB_PREACCESS(stk)
489 #define G_interpreter VMGLOB_PREACCESS(interpreter)
490 #define G_const_pool  VMGLOB_PREACCESS(const_pool)
491 #define G_code_pool   VMGLOB_PREACCESS(code_pool)
492 #define G_obj_table   VMGLOB_PREACCESS(obj_table)
493 
494 #endif /* VMGLOB_H */
495 
496