~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/vmobj.h

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Header: d:/cvsroot/tads/tads3/VMOBJ.H,v 1.3 1999/07/11 00:46:58 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
  vmobj.h - VM object memory manager
 
12
Function
 
13
  
 
14
Notes
 
15
  
 
16
Modified
 
17
  10/20/98 MJRoberts  - Creation
 
18
*/
 
19
 
 
20
#ifndef VMOBJ_H
 
21
#define VMOBJ_H
 
22
 
 
23
#include <stdlib.h>
 
24
#include <memory.h>
 
25
 
 
26
#include "vmglob.h"
 
27
#include "vmtype.h"
 
28
#include "vmerr.h"
 
29
#include "vmerrnum.h"
 
30
 
 
31
 
 
32
/* ------------------------------------------------------------------------ */
 
33
/*
 
34
 *   If the VM_REGISTER_METACLASS macro hasn't been defined, define it
 
35
 *   now.  This macro is defined different ways on different inclusions,
 
36
 *   but when it's not defined, it should always be defined to do nothing.
 
37
 */
 
38
#ifndef VM_REGISTER_METACLASS
 
39
# define VM_REGISTER_METACLASS(metaclass)
 
40
#endif
 
41
 
 
42
/* ------------------------------------------------------------------------ */
 
43
/*
 
44
 *   NOTE TO METACLASS IMPLEMENTORS - each final concrete class derived
 
45
 *   from CVmObject that is to be available to VM programs for static
 
46
 *   image file loading and/or dynamic creation (via the "NEW"
 
47
 *   instructions) must specify a VM_REGISTER_METACLASS declaration to
 
48
 *   register the metaclass.  This declaration must occur in the
 
49
 *   metaclass's header file, and must be OUTSIDE of the region protected
 
50
 *   against multiple inclusion.  The definition should look like this:
 
51
 *   
 
52
 *   VM_REGISTER_METACLASS("metaclass-string-name", CVmClassName)
 
53
 *   
 
54
 *   The string name must be the universally unique metaclass identifier
 
55
 *   string registered with the T3 VM Specification Maintainer.  The class
 
56
 *   name is the C++ class (derived from CVmObject).
 
57
 *   
 
58
 *   Each CVmObject subclass must define certain static construction
 
59
 *   methods in addition to the virtual methods defined as abstract in
 
60
 *   CVmObject.  See the comments on CVmObject for details.
 
61
 */
 
62
 
 
63
 
 
64
/* ------------------------------------------------------------------------ */
 
65
/*
 
66
 *   To get a pointer to an object (CVmObject *) given an object ID
 
67
 *   (vm_obj_id_t), use this:
 
68
 *   
 
69
 *   CVmObject *obj = vm_objp(vmg_ id);
 
70
 *   
 
71
 *   To allocate a new object:
 
72
 *   
 
73
 *   vm_obj_id_t id = vm_newid(vmg_ in_root_set);
 
74
 *.  CVmObject *obj = new (vmg_ id) CVmObjXxx(constructor params);
 
75
 *   
 
76
 *   The functions vm_objp() and vm_newid() are defined later in this
 
77
 *   file.  
 
78
 */
 
79
 
 
80
 
 
81
/* ------------------------------------------------------------------------ */
 
82
/*
 
83
 *   Garbage collector work increment.  This is the number of objects that
 
84
 *   the GC will process on each call to gc_pass_queue().
 
85
 *   
 
86
 *   The point of running the GC incrementally is to allow GC work to be
 
87
 *   interleaved with long-running user I/O operations (such as reading a
 
88
 *   line of text from the keyboard) in the foreground thread, so the work
 
89
 *   increment should be chosen so that each call to this routine
 
90
 *   completes quickly enough that the user will perceive no delay.
 
91
 *   However, making this number too small will introduce additional
 
92
 *   overhead by making an excessive number of function calls.  
 
93
 */
 
94
const int VM_GC_WORK_INCREMENT = 500;
 
95
 
 
96
 
 
97
 
 
98
/* ------------------------------------------------------------------------ */
 
99
/* 
 
100
 *   flag values for propDefined 
 
101
 */
 
102
#define VMOBJ_PROPDEF_ANY           1
 
103
#define VMOBJ_PROPDEF_DIRECTLY      2
 
104
#define VMOBJ_PROPDEF_INHERITS      3
 
105
#define VMOBJ_PROPDEF_GET_CLASS     4
 
106
 
 
107
 
 
108
/* ------------------------------------------------------------------------ */
 
109
/*
 
110
 *   Objects are composed of two parts.  The first is a fixed-size
 
111
 *   portion, or header, which consists of an abstract interface (in terms
 
112
 *   of stored data, this is simply a vtable pointer) and an extension
 
113
 *   pointer.  The extension pointer points to the variable-size second
 
114
 *   part of the object, which contains all of the additional instance
 
115
 *   data for the object.  
 
116
 */
 
117
 
 
118
/* ------------------------------------------------------------------------ */
 
119
/*
 
120
 *   
 
121
 *   The fixed-size parts, or object headers, are allocated from a set of
 
122
 *   arrays.  A master array has a pointer to the sub-arrays, and each
 
123
 *   sub-array has a fixed number of slots for the fixed-size parts.
 
124
 *   Thus, it's very fast to find an object header given an object ID.
 
125
 *   
 
126
 *   Because each fixed-size part has an abstract interface, we can have
 
127
 *   multiple implementations for the objects.  This would allow us, for
 
128
 *   example, to include native objects (with an appropriate interface) as
 
129
 *   though they were normal VM objects.  It also allows us to have
 
130
 *   different types of implementations for VM objects.
 
131
 *   
 
132
 *   The fixed-size object parts never move in memory, so we can refer to
 
133
 *   them with pointers.  We can efficiently re-use space as object
 
134
 *   headers are allocated and deleted, because a new object will always
 
135
 *   take up exactly the same size as a previous object whose space was
 
136
 *   freed.
 
137
 *   
 
138
 *   The fixed-size objects are always allocated within the page table,
 
139
 *   thus operator new is overridden to allocate memory within the page
 
140
 *   table.  
 
141
 */
 
142
/*
 
143
 *   In addition to the virtual methods listed, every object must define a
 
144
 *   data member as follows:
 
145
 *   
 
146
 *   public: static class CVmMetaclass *metaclass_reg_;
 
147
 *   
 
148
 *   This must be a static singleton instance of the CVmMetaclass subclass
 
149
 *   (see below) for the CVmObject subclass.  Each CVmObject subclass must
 
150
 *   have a corresponding CVmMetaclass subclass; the singleton member
 
151
 *   variable metaclass_reg_ provides the registration table entry that
 
152
 *   allows instances of this object to be dynamically linked from the
 
153
 *   image file.  
 
154
 */
 
155
class CVmObject
 
156
{
 
157
    friend class CVmVarHeap;
 
158
    
 
159
public:
 
160
    /* metaclass registration object (for the root object implementation) */
 
161
    static class CVmMetaclass *metaclass_reg_;
 
162
 
 
163
    /*
 
164
     *   Default implementation for calling a static property.  We don't
 
165
     *   have any static properties at this level, so we'll simply return
 
166
     *   false to indicate that the property wasn't evaluated.  
 
167
     */
 
168
    static int call_stat_prop(VMG_ vm_val_t *retval, const uchar **pc_ptr,
 
169
                              uint *argc, vm_prop_id_t);
 
170
 
 
171
    /* get the registration object for this metaclass */
 
172
    virtual class CVmMetaclass *get_metaclass_reg() const
 
173
        { return metaclass_reg_; }
 
174
 
 
175
    /* 
 
176
     *   Is this object of the given metaclass?  Returns true if the
 
177
     *   object is an instance of 'meta' or inherits from the metaclass.
 
178
     *   Each object class must override this.  
 
179
     */
 
180
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
 
181
        { return (meta == metaclass_reg_); }
 
182
 
 
183
    /* 
 
184
     *   Receive notification that this object is being deleted - the
 
185
     *   garbage collector calls this function when the object is
 
186
     *   unreachable.
 
187
     *   
 
188
     *   Note that we don't use the real destructor, since we use our own
 
189
     *   memory management; instead, we have this virtual finalizer that
 
190
     *   we explicitly call when it's time to delete the object.  (This
 
191
     *   isn't entirely symmetrical with the overridden operator new, but
 
192
     *   the GC is the only code that can delete objects, and this saves
 
193
     *   us the trouble of overriding operator delete for the object.)  
 
194
     */
 
195
    virtual void notify_delete(VMG_ int in_root_set) = 0;
 
196
 
 
197
    /*
 
198
     *   Create an instance of this class.  If this object does not
 
199
     *   represent a class, or cannot be instanced, throw an error.  By
 
200
     *   default, objects cannot be instanced, so we'll simply throw an
 
201
     *   error.  If successful, leaves the new object in register R0.
 
202
     *   
 
203
     *   Parameters to the constructor are passed on the VM stack; 'argc'
 
204
     *   gives the number of arguments on the stack.  This routine will
 
205
     *   remove the arguments from the stack before returning.  
 
206
     */
 
207
    virtual void create_instance(VMG_ vm_obj_id_t self,
 
208
                                 const uchar **pc_ptr, uint argc)
 
209
    {
 
210
        /* throw the error */
 
211
        err_throw(VMERR_CANNOT_CREATE_INST);
 
212
    }
 
213
 
 
214
    /*
 
215
     *   Determine if the object has a non-trivial finalizer.  Returns
 
216
     *   true if the object has a non-trivial finalizer, false if it has
 
217
     *   no finalizer or the finalizer is trivial and hence can be
 
218
     *   ignored.  We'll return false by default.  
 
219
     */
 
220
    virtual int has_finalizer(VMG_ vm_obj_id_t /*self*/)
 
221
        { return FALSE; }
 
222
 
 
223
    /*
 
224
     *   Invoke the object's finalizer.  This need do nothing if the
 
225
     *   object does not define or inherit a finalizer method.  Any
 
226
     *   exceptions thrown in the course of executing the finalizer should
 
227
     *   be caught and discarded.  By default, we'll do nothing at all.
 
228
     */
 
229
    virtual void invoke_finalizer(VMG_ vm_obj_id_t /*self*/) { }
 
230
 
 
231
    /*
 
232
     *   Determine if this is a class object.  This returns true if this
 
233
     *   object is a class, false if it's an instance.  
 
234
     */
 
235
    virtual int is_class_object(VMG_ vm_obj_id_t /*self*/) const
 
236
        { return FALSE; }
 
237
 
 
238
    /*
 
239
     *   Determine if this object is an instance of another object.
 
240
     *   Returns true if this object derives from the other object,
 
241
     *   directly or indirectly.  If this object derives from an object
 
242
     *   which in turn derives from the given object, then this object
 
243
     *   derives (indirectly) from the given object.  
 
244
     */
 
245
    virtual int is_instance_of(VMG_ vm_obj_id_t obj);
 
246
 
 
247
    /* 
 
248
     *   Get the number of superclasses of the object, and get the nth
 
249
     *   superclass.  By default, we have one superclass, which is the
 
250
     *   IntrinsicClass object that represents this metaclass.  
 
251
     */
 
252
    virtual int get_superclass_count(VMG_ vm_obj_id_t /*self*/) const
 
253
        { return 1; }
 
254
    virtual vm_obj_id_t get_superclass(VMG_ vm_obj_id_t /*self*/,
 
255
                                       int /*superclass_index*/) const;
 
256
 
 
257
    /*
 
258
     *   Determine if the object has properties that can be enumerated.
 
259
     *   Returns true if so, false if not.  Note that this should return
 
260
     *   true for an object of a type that provides properties, even if
 
261
     *   the instance happens to have zero properties.  
 
262
     */
 
263
    virtual int provides_props(VMG0_) const { return FALSE; }
 
264
 
 
265
    /*
 
266
     *   Enumerate properties of the object.  Invoke the callback for each
 
267
     *   property.  The callback is not permitted to make any changes to
 
268
     *   the object or its properties and should not invoke garbage
 
269
     *   collection.  
 
270
     */
 
271
    virtual void enum_props(VMG_ vm_obj_id_t self,
 
272
                            void (*cb)(VMG_ void *ctx,
 
273
                                       vm_obj_id_t self, vm_prop_id_t prop,
 
274
                                       const vm_val_t *val),
 
275
                            void *cbctx)
 
276
    {
 
277
        /* by default, assume we have nothing to enumerate */
 
278
    }
 
279
 
 
280
    /* set a property value */
 
281
    virtual void set_prop(VMG_ class CVmUndo *undo,
 
282
                          vm_obj_id_t self, vm_prop_id_t prop,
 
283
                          const vm_val_t *val) = 0;
 
284
 
 
285
    /* 
 
286
     *   Get a property value.  We do not evaluate the property, but
 
287
     *   merely get the raw value; thus, if the property value is of type
 
288
     *   code, we simply retrieve the code offset pointer.  Returns true
 
289
     *   if the property was found, false if not.
 
290
     *   
 
291
     *   If we find the object, we'll set *source_obj to the ID of the
 
292
     *   object in which we found the object.  If the property was
 
293
     *   supplied by this object directly, we'll simply set source_id to
 
294
     *   self; if we inherited the property from a superclass, we'll set
 
295
     *   *source_id to the ID of the superclass object that actually
 
296
     *   supplied the value.
 
297
     *   
 
298
     *   If 'argc' is not null, this function can consume arguments from
 
299
     *   the run-time stack, and set *argc to zero to indicate that the
 
300
     *   arguments have been consumed.
 
301
     *   
 
302
     *   If 'argc' is null, and evaluating the property would involve
 
303
     *   running system code (with or without consuming arguments), this
 
304
     *   function should return TRUE, but should NOT run the system code -
 
305
     *   instead, set val->typ to VM_NATIVE_CODE to indicate that the
 
306
     *   value is a "native code" value (i.e., evaluating it requires
 
307
     *   executing system code).  
 
308
     */
 
309
    virtual int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
 
310
                         vm_obj_id_t self, vm_obj_id_t *source_obj,
 
311
                         uint *argc);
 
312
 
 
313
    /*
 
314
     *   Inherit a property value.  This works similarly to get_prop, but
 
315
     *   finds an inherited definition of the property, as though
 
316
     *   orig_target_obj.prop (and anything overriding orig_target_obj.prop)
 
317
     *   were undefined.
 
318
     *   
 
319
     *   In broad terms, the algorithm for this method is to do the same
 
320
     *   thing as get_prop(), but to ignore every definition of the property
 
321
     *   found in the class tree until after reaching and skipping
 
322
     *   orig_target_obj.prop.  Once orig_target_obj.prop is found, this
 
323
     *   method simply continues searching in the same manner as get_prop()
 
324
     *   and returns the next definition it finds.
 
325
     *   
 
326
     *   'defining_obj' is the object containing the method currently
 
327
     *   running.  This is not necessarily 'self', because the method
 
328
     *   currently running might already have been inherited from a
 
329
     *   superclass of 'self'.
 
330
     *   
 
331
     *   'orig_target_obj' is the object that was originally targeted for the
 
332
     *   get_prop() operation that invoked the calling method (or invoked the
 
333
     *   method that inherited the calling method, or so on).  This gives us
 
334
     *   the starting point in the search, so that we can continue the
 
335
     *   original inheritance tree search that started with get_prop().
 
336
     *   
 
337
     *   'argc' has the same meaning as for get_prop().  
 
338
     *   
 
339
     *   Objects that cannot be subclassed via byte-code can ignore this
 
340
     *   method.  The base class implementation follows the inheritance chain
 
341
     *   of "modifier" objects, which allow byte-code methods to be plugged
 
342
     *   in under the native code class tree.  
 
343
     */
 
344
    virtual int inh_prop(VMG_ vm_prop_id_t prop, vm_val_t *retval,
 
345
                         vm_obj_id_t self, vm_obj_id_t orig_target_obj,
 
346
                         vm_obj_id_t defining_obj, vm_obj_id_t *source_obj,
 
347
                         uint *argc);
 
348
 
 
349
    /*
 
350
     *   Build a list of the properties directly defined on this object
 
351
     *   instance.  On return, retval must be filled in with the new list
 
352
     *   object.
 
353
     *   
 
354
     *   Note that a self-reference must be pushed by the caller to protect
 
355
     *   against garbage collection of self while this routine is running.
 
356
     *   
 
357
     *   Most object types do not define any properties in the instance, so
 
358
     *   this default implementation will simply return an empty list.
 
359
     *   Classes that can define properties in instances (such as
 
360
     *   TadsObjects), and the "intrinsic class" class that represents
 
361
     *   classes, must override this to build their lists.  
 
362
     */
 
363
    virtual void build_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval);
 
364
 
 
365
    /* 
 
366
     *   Mark all strongly-referenced objects.  Calls
 
367
     *   obj_table->mark_refs() for each referenced object.  
 
368
     */
 
369
    virtual void mark_refs(VMG_ uint state) = 0;
 
370
 
 
371
    /* 
 
372
     *   Remove stale weak references.  For each weakly-referenced object,
 
373
     *   check to see if the object is marked as reachable; if not, it's
 
374
     *   about to be deleted, so forget the weak reference. 
 
375
     */
 
376
    virtual void remove_stale_weak_refs(VMG0_) = 0;
 
377
 
 
378
    /*
 
379
     *   Receive notification that the undo manager is creating a new
 
380
     *   savepoint.  
 
381
     */
 
382
    virtual void notify_new_savept() = 0;
 
383
 
 
384
    /* 
 
385
     *   apply an undo record created by this object; if the record has
 
386
     *   any additional data associated with it (allocated by the object
 
387
     *   when the undo record was created), this should also discard the
 
388
     *   additional data 
 
389
     */
 
390
    virtual void apply_undo(VMG_ struct CVmUndoRecord *rec) = 0;
 
391
 
 
392
    /* 
 
393
     *   Discard any extra information associated with this undo record.
 
394
     *   Note that this will not be called if apply_undo() is called,
 
395
     *   since apply_undo() is expected to discard any extra information
 
396
     *   itself after applying the record.  
 
397
     */
 
398
    virtual void discard_undo(VMG_ struct CVmUndoRecord *) { }
 
399
 
 
400
    /*
 
401
     *   Mark an object object reference.  If this object keeps strong
 
402
     *   references, this should mark any object contained in the undo
 
403
     *   record's saved value as referenced; if this object keeps only
 
404
     *   weak references, this doesn't need to do anything. 
 
405
     */
 
406
    virtual void mark_undo_ref(VMG_ struct CVmUndoRecord *rec) = 0;
 
407
 
 
408
    /*
 
409
     *   Remove any stale weak reference contained in an undo record.  For
 
410
     *   objects with ordinary strong references, this doesn't need to do
 
411
     *   anything.  For objects that keep weak references to other
 
412
     *   objects, this should check the object referenced in the undo
 
413
     *   record, if any, to determine if the object is about to be
 
414
     *   deleted, and if so clear the undo record (by setting the object
 
415
     *   in the old value to 'invalid'). 
 
416
     */
 
417
    virtual void remove_stale_undo_weak_ref(VMG_
 
418
                                            struct CVmUndoRecord *rec) = 0;
 
419
 
 
420
    /*
 
421
     *   Post-load initialization.  This routine is called only if the object
 
422
     *   specifically requests this by calling request_post_load_init().
 
423
     *   This routine is called exactly once for each initial program load,
 
424
     *   restart, or restore, and is called after ALL objects are loaded.
 
425
     *   
 
426
     *   The purpose of this routine is to allow an object to perform
 
427
     *   initializations that depend upon other objects.  During the normal
 
428
     *   load/restore/reset methods, an object cannot assume that any other
 
429
     *   objects are already loaded, because the order of loading is
 
430
     *   arbitrary.  When this routine is called, it is guaranteed that all
 
431
     *   objects are already loaded.  
 
432
     */
 
433
    virtual void post_load_init(VMG_ vm_obj_id_t /*self*/)
 
434
    {
 
435
        /* we do nothing by default */
 
436
    }
 
437
 
 
438
    /*
 
439
     *   Load the object from an image file.  The object's data block is
 
440
     *   at the given address and has the given size.
 
441
     *   
 
442
     *   The underlying memory is owned by the image file loader.  The
 
443
     *   object must not attempt to deallocate this memory.  
 
444
     */
 
445
    virtual void load_from_image(VMG_ vm_obj_id_t self,
 
446
                                 const char *ptr, size_t siz) = 0;
 
447
 
 
448
    /*
 
449
     *   Reload the object from an image file.  The object's data block is
 
450
     *   at the given address and has the given size.  Discards any changes
 
451
     *   made since the object was loaded and restores its state as it was
 
452
     *   immediately after it was loaded from the image file.  By default,
 
453
     *   we do nothing.
 
454
     *   
 
455
     *   NOTE 1: this routine can be implemented instead of
 
456
     *   reset_to_image().  If an object doesn't have any other need to
 
457
     *   store a pointer to its image file data in its own extension, but
 
458
     *   the image file data is necessary to effect a reset, then this
 
459
     *   routine should be used, so as to avoid having to enlarge the
 
460
     *   object's extension for non-image instances.
 
461
     *   
 
462
     *   NOTE 2: in order to use this routine, the object MUST call the
 
463
     *   object table's save_image_pointer() routine during the initial
 
464
     *   loading (i.e., in the object's load_from_image()).  During a reset,
 
465
     *   the object table will only call this routine on objects whose image
 
466
     *   pointers were previously saved with save_image_pointer().  
 
467
     */
 
468
    virtual void reload_from_image(VMG_ vm_obj_id_t self,
 
469
                                   const char *ptr, size_t siz) { }
 
470
 
 
471
    /*
 
472
     *   Reset to the image file state.  Discards any changes made since the
 
473
     *   object was loaded and restores its state as it was immediately
 
474
     *   after it was loaded from the image file.  By default, we do nothing.
 
475
     *   
 
476
     *   NOTE: this routine doesn't have to do anything if
 
477
     *   reload_from_image() is implemented for the object.  
 
478
     */
 
479
    virtual void reset_to_image(VMG_ vm_obj_id_t /*self*/) { }
 
480
 
 
481
    /*
 
482
     *   Determine if the object has been changed since it was loaded from
 
483
     *   the image file.  This can only be called for objects that were
 
484
     *   originally loaded from the image file.  Returns true if the
 
485
     *   object's internal state has been changed since loading, false if
 
486
     *   the object is in exactly the same state that's stored in the
 
487
     *   image file.
 
488
     *   
 
489
     *   If this returns false, then it is not necessary to save the
 
490
     *   object to a saved state file, because the object's state can be
 
491
     *   restored simply by resetting to the image file state.  
 
492
     */
 
493
    virtual int is_changed_since_load() const { return FALSE; }
 
494
 
 
495
    /* 
 
496
     *   save this object to a file, so that it can be restored to its
 
497
     *   current state via restore_from_file 
 
498
     */
 
499
    virtual void save_to_file(VMG_ class CVmFile *fp) = 0;
 
500
 
 
501
    /* 
 
502
     *   Restore the state of the object from a file into which state was
 
503
     *   previously stored via save_to_file.  This routine may need
 
504
     *   access to the memory manager because it may need to allocate
 
505
     *   memory to make room for the variable data.  
 
506
     */
 
507
    virtual void restore_from_file(VMG_ vm_obj_id_t self,
 
508
                                   class CVmFile *fp,
 
509
                                   class CVmObjFixup *fixups) = 0;
 
510
 
 
511
    /*
 
512
     *   Compare to another value for equality.  Returns true if the value is
 
513
     *   equal, false if not.  By default, we return true only if the other
 
514
     *   value is an object with the same ID (i.e., a reference to exactly
 
515
     *   the same instance).  However, subclasses can override this to
 
516
     *   provide different behavior; the string class, for example, may
 
517
     *   override this so that it compares equal to any string object or
 
518
     *   constant containing the same string text.
 
519
     *   
 
520
     *   'depth' has the same meaning as in calc_hash().  
 
521
     */
 
522
    virtual int equals(VMG_ vm_obj_id_t self, const vm_val_t *val,
 
523
                       int /*depth*/) const
 
524
    {
 
525
        /* return true if the other value is a reference to this object */
 
526
        return (val->typ == VM_OBJ && val->val.obj == self);
 
527
    }
 
528
 
 
529
    /*
 
530
     *   Compare magnitude of this object and another object.  Returns a
 
531
     *   positive value if this object is greater than the other object, a
 
532
     *   negative value if this object is less than the other object, or
 
533
     *   zero if this object equals the other object.  Throws an error if
 
534
     *   a magnitude comparison is not meaningful between the two objects.
 
535
     *   
 
536
     *   By default, magnitude comparisons between objects are not
 
537
     *   meaningful, so we throw an error. 
 
538
     */
 
539
    virtual int compare_to(VMG_ vm_obj_id_t /*self*/, const vm_val_t *) const
 
540
    {
 
541
        /* by default, magnitude comparisons between objects are illegal */
 
542
        err_throw(VMERR_INVALID_COMPARISON);
 
543
 
 
544
        /* the compiler doesn't know that we'll never get here */
 
545
        AFTER_ERR_THROW(return 0;)
 
546
    }
 
547
 
 
548
    /*
 
549
     *   Calculate a hash value for the object.
 
550
     *   
 
551
     *   'depth' is the recursion depth of the hash calculation.  Objects
 
552
     *   that can potentially contain cyclical references back to themselves,
 
553
     *   and which follow those references to calculate the hash value
 
554
     *   recursively, must check the depth counter to see if it exceeds
 
555
     *   VM_MAX_TREE_DEPTH_EQ, throwing VMERR_TREE_TOO_DEEP_EQ if so; and
 
556
     *   they must increment the depth counter in the recursive traversals.
 
557
     *   Objects that don't traverse into their contents can ignore the depth
 
558
     *   counter.  
 
559
     */
 
560
    virtual uint calc_hash(VMG_ vm_obj_id_t self, int /*depth*/) const
 
561
    {
 
562
        /* 
 
563
         *   by default, use a 16-bit hash of our object ID as the hash
 
564
         *   value 
 
565
         */
 
566
        return (uint)(((ulong)self & 0xffff)
 
567
                      ^ (((ulong)self & 0xffff0000) >> 16));
 
568
    }
 
569
                   
 
570
 
 
571
    /* 
 
572
     *   Add a value to this object, returning the result in *result.
 
573
     *   This may create a new object to hold the result, or may modify
 
574
     *   the existing object in place, depending on the subclass
 
575
     *   implementation.  'self' is the object ID of this object.
 
576
     *   
 
577
     *   By default, we'll throw an error indicating that the value cannot
 
578
     *   be added.  
 
579
     */
 
580
    virtual void add_val(VMG_ vm_val_t * /*result*/,
 
581
                         vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
 
582
    {
 
583
        /* throw an error */
 
584
        err_throw(VMERR_BAD_TYPE_ADD);
 
585
    }
 
586
 
 
587
    /*
 
588
     *   Subtract a value from this object, returning the result in
 
589
     *   *result.  This may create a new object to hold the result, or may
 
590
     *   modify the existing object in place, depending upon the subclass
 
591
     *   implementation.  'self' is the object ID of this object.  
 
592
     */
 
593
    virtual void sub_val(VMG_ vm_val_t * /*result*/,
 
594
                         vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
 
595
    {
 
596
        /* throw an error */
 
597
        err_throw(VMERR_BAD_TYPE_SUB);
 
598
    }
 
599
 
 
600
    /* multiply this object by a value, returning the result in *result */
 
601
    virtual void mul_val(VMG_ vm_val_t * /* result*/,
 
602
                         vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
 
603
    {
 
604
        /* throw an error */
 
605
        err_throw(VMERR_BAD_TYPE_MUL);
 
606
    }
 
607
 
 
608
    /* divide a value into this object, returning the result in *result */
 
609
    virtual void div_val(VMG_ vm_val_t * /* result*/,
 
610
                         vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
 
611
    {
 
612
        /* throw an error */
 
613
        err_throw(VMERR_BAD_TYPE_DIV);
 
614
    }
 
615
 
 
616
    /* negate the value, returning the result in *result */
 
617
    virtual void neg_val(VMG_ vm_val_t * /* result */, vm_obj_id_t self)
 
618
    {
 
619
        /* throw an error */
 
620
        err_throw(VMERR_BAD_TYPE_NEG);
 
621
    }
 
622
 
 
623
    /*
 
624
     *   Get the effective number of values this value contributes when
 
625
     *   used as the right-hand side of a '+' or '-' operator with a
 
626
     *   left-hand type that treats these operators as concatenation/set
 
627
     *   subtraction operators.  By default, a value adds/subtracts only
 
628
     *   itself, but certain collection types (List, Vector, Array)
 
629
     *   add/subtract their elements individually. 
 
630
     */
 
631
    virtual size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const
 
632
    {
 
633
        /* by default, we contribute only 'self', thus only one element */
 
634
        return 1;
 
635
    }
 
636
 
 
637
    /* get the nth element as the rhs of a collection add/subtract */
 
638
    virtual void get_coll_addsub_rhs_ele(VMG_ vm_val_t *retval,
 
639
                                         vm_obj_id_t self, size_t /*idx*/) 
 
640
    {
 
641
        /* by default, we contribute only 'self' */
 
642
        retval->set_obj(self);
 
643
    }
 
644
 
 
645
    /*
 
646
     *   Index the object.  Most object types cannot be indexed, so by
 
647
     *   default we'll throw an error.  Subclasses that can be indexed
 
648
     *   (such as lists) should look up the element given by the index
 
649
     *   value, and store the value at that index in *result.  
 
650
     */
 
651
    virtual void index_val(VMG_ vm_val_t * /*result*/,
 
652
                           vm_obj_id_t /*self*/,
 
653
                           const vm_val_t * /*index_val*/)
 
654
    {
 
655
        /* by default, throw an error */
 
656
        err_throw(VMERR_CANNOT_INDEX_TYPE);
 
657
    }
 
658
 
 
659
    /*
 
660
     *   Set an indexed element of the object, and fill in *new_container
 
661
     *   with the new object that results if an entire new object is
 
662
     *   created to hold the modified contents, or with the original
 
663
     *   object if the contents of the original object are actually
 
664
     *   modified by this operation.  Lists, for example, cannot be
 
665
     *   modified, so always create a new list object when an element is
 
666
     *   set; arrays, in contrast, can be directly modified, so will
 
667
     *   simply return 'self' in *new_container.
 
668
     *   
 
669
     *   By default, we'll throw an error, since default objects cannot be
 
670
     *   indexed.  
 
671
     */
 
672
    virtual void set_index_val(VMG_ vm_val_t * /*new_container*/,
 
673
                               vm_obj_id_t /*self*/,
 
674
                               const vm_val_t * /*index_val*/,
 
675
                               const vm_val_t * /*new_val*/)
 
676
    {
 
677
        /* by default, throw an error */
 
678
        err_throw(VMERR_CANNOT_INDEX_TYPE);
 
679
    }
 
680
 
 
681
    /*
 
682
     *   Get a string representation of the object.  If necessary, this
 
683
     *   can create a new string object to represent the result.
 
684
     *   
 
685
     *   Returns the string representation in portable string format: the
 
686
     *   first two bytes give the byte length of the rest of the string in
 
687
     *   portable UINT2 format, and immediately following the length
 
688
     *   prefix are the bytes of the string's contents.  The length prefix
 
689
     *   does not count the length prefix itself in the length of the
 
690
     *   string.
 
691
     *   
 
692
     *   If a new string object is created, new_str must be set to a
 
693
     *   reference to the new string object.  If a pointer into our data
 
694
     *   is returned, we must set new_str to self.  If no object data are
 
695
     *   involved, new_str can be set to nil.
 
696
     *   
 
697
     *   If it is not possible to create a string representation of the
 
698
     *   object, throw an error (VMERR_NO_STR_CONV).
 
699
     *   
 
700
     *   By default, we'll throw an error indicating that the object
 
701
     *   cannot be converted to a string.  
 
702
     */
 
703
    virtual const char *cast_to_string(VMG_ vm_obj_id_t /*self*/,
 
704
                                       vm_val_t * /*new_str*/) const
 
705
    {
 
706
        /* throw an error */
 
707
        err_throw(VMERR_NO_STR_CONV);
 
708
 
 
709
        /* we can't get here, but the compiler doesn't know that */
 
710
        AFTER_ERR_THROW(return 0;)
 
711
    }
 
712
 
 
713
    /*
 
714
     *   Get the list contained in the object, if possible, or null if
 
715
     *   not.  If the value contained in the object is a list, this
 
716
     *   returns a pointer to the list value in portable format (the first
 
717
     *   two bytes are the length prefix as a portable UINT2, and the
 
718
     *   subsequent bytes form a packed array of data holders in portable
 
719
     *   format).
 
720
     *   
 
721
     *   Most object classes will return null for this, since they do not
 
722
     *   store lists.  By default, we return null.
 
723
     */
 
724
    virtual const char *get_as_list() const { return 0; }
 
725
 
 
726
    /*
 
727
     *   Get the string contained in the object, if possible, or null if
 
728
     *   not.  If the value contained in the object is a string, this
 
729
     *   returns a pointer to the string value in portable format (the
 
730
     *   first two bytes are the string prefix as a portable UINT2, and
 
731
     *   the bytes of the string's text immediately follow in UTF8 format).
 
732
     *   
 
733
     *   Most object classes will return null for this, since they do not
 
734
     *   store strings.  By default, we return null.  
 
735
     */
 
736
    virtual const char *get_as_string(VMG0_) const { return 0; }
 
737
 
 
738
    /*
 
739
     *   Rebuild the image data for the object.  This is used to write the
 
740
     *   program state to a new image file after executing the program for
 
741
     *   a while, such as after a 'preinit' step after compilation.
 
742
     *   
 
743
     *   This should write the complete metaclass-specific record needed
 
744
     *   for an OBJS data block entry, not including the generic header.
 
745
     *   
 
746
     *   On success, return the size in bytes of the data stored to the
 
747
     *   buffer; these bytes must be copied directly to the new image
 
748
     *   file.  If the given buffer isn't big enough, this should return
 
749
     *   the size needed and otherwise leave the buffer empty.  If the
 
750
     *   object doesn't need to be written at all, this should return
 
751
     *   zero.  
 
752
     */
 
753
    virtual ulong rebuild_image(VMG_ char *, ulong)
 
754
        { return 0; }
 
755
 
 
756
    /*
 
757
     *   Allocate space for conversion to constant data for storage in a
 
758
     *   rebuilt image file.  If this object can be stored as constant
 
759
     *   data in a rebuilt image file, this should reserve space in the
 
760
     *   provided constant mapper object for the object's data in
 
761
     *   preparation for conversion.
 
762
     *   
 
763
     *   Most objects cannot be converted to constant data, so the default
 
764
     *   here does nothing.  Those that can, such as strings and lists,
 
765
     *   should override this.  
 
766
     */
 
767
    virtual void reserve_const_data(VMG_ class CVmConstMapper *,
 
768
                                    vm_obj_id_t /*self*/)
 
769
        { /* default does nothing */ }
 
770
 
 
771
    /*
 
772
     *   Convert to constant data.  If this object can be stored as
 
773
     *   constant data in a rebuilt image file, it should override this
 
774
     *   routine to store its data in the provided constant mapper object.
 
775
     *   If this object makes reference to other objects, it must check
 
776
     *   each object that it references to determine if the object has a
 
777
     *   non-zero address in the mapper, and if so must convert its
 
778
     *   reference to the object to a constant data item at the given
 
779
     *   address.  There is no default implementation of this routine,
 
780
     *   because it must be overridden by essentially all objects (at
 
781
     *   least, it must be overridden by objects that can be converted or
 
782
     *   that can refer to objects that can be converted).  
 
783
     */
 
784
    virtual void convert_to_const_data(VMG_ class CVmConstMapper *,
 
785
                                       vm_obj_id_t /*self*/)
 
786
        { /* default does nothing */ }
 
787
 
 
788
    /*
 
789
     *   Get the type that this object uses when converted to constant
 
790
     *   data.  Objects that can be converted to constant data via
 
791
     *   convert_to_const_data() should return the appropriate type
 
792
     *   (VM_SSTRING, VM_LIST, etc); others can return VM_NIL to indicate
 
793
     *   that they have no conversion.  This will be called only when an
 
794
     *   object actually has been converted as indicated in a mapper
 
795
     *   (CVmConstMapper) object.  We'll return NIL by default.  
 
796
     */
 
797
    virtual vm_datatype_t get_convert_to_const_data_type() const
 
798
        { return VM_NIL; }
 
799
    
 
800
 
 
801
    /*
 
802
     *   Allocate memory for the fixed part from a memory manager.  We
 
803
     *   override operator new so that we can provide custom memory
 
804
     *   management for object headers.
 
805
     *   
 
806
     *   To create an object, use a sequence like this:
 
807
     *   
 
808
     *   obj_id = mem_mgr->get_obj_table()->alloc_obj(vmg_ in_root_set);
 
809
     *.  new (vmg_ obj_id) CVmObjString(subclass constructor params)
 
810
     *   
 
811
     *   The caller need not store the result of 'new'; the caller
 
812
     *   identifies the object by the obj_id value.
 
813
     *   
 
814
     *   Each CVmObject subclass should provide static methods that cover
 
815
     *   the above sequence, since it's a bit verbose to sprinkle
 
816
     *   throughout client code.  
 
817
     */
 
818
    void *operator new(size_t siz, VMG_ vm_obj_id_t obj_id);
 
819
 
 
820
protected:
 
821
    /*
 
822
     *   Find a modifier property.  This is an internal service routine that
 
823
     *   we use to traverse the hierarchy of modifier objects associated with
 
824
     *   our intrinsic class hierarchy.  
 
825
     */
 
826
    int find_modifier_prop(VMG_ vm_prop_id_t prop, vm_val_t *retval,
 
827
                           vm_obj_id_t self, vm_obj_id_t orig_target_obj,
 
828
                           vm_obj_id_t defining_obj, vm_obj_id_t *source_obj,
 
829
                           uint *argc);
 
830
 
 
831
    /*
 
832
     *   Service routine - check a get_prop() argument count for executing
 
833
     *   a native code method implementation.  If 'argc' is null, we'll
 
834
     *   set the value to a VM_NATIVE_CODE indication and return true,
 
835
     *   which the caller should do from get_prop() as well.  If 'argc' is
 
836
     *   non-null, we'll check it against the given required argument
 
837
     *   count, and throw an error if it doesn't match.  If 'argc' is
 
838
     *   non-null and it matches the given argument count, we'll set *argc
 
839
     *   to zero to indicate that we've consumed the arguments, and return
 
840
     *   false - get_prop() should in this case execute the native code
 
841
     *   and return the appropriate result value.  
 
842
     */
 
843
    static int get_prop_check_argc(vm_val_t *val, uint *argc,
 
844
                                   const CVmNativeCodeDesc *desc)
 
845
    {
 
846
        /* 
 
847
         *   if there's no 'argc', we can't execute the native code - we're
 
848
         *   simply being asked for a description of the method, not to
 
849
         *   evaluate its result 
 
850
         */
 
851
        if (argc == 0)
 
852
        {
 
853
            /* indicate a native code evaluation is required */
 
854
            val->set_native(desc);
 
855
 
 
856
            /* tell get_prop() to return without further work */
 
857
            return TRUE;
 
858
        }
 
859
 
 
860
        /* check the argument count - throw an error if out of range */
 
861
        if (!desc->args_ok(*argc))
 
862
            err_throw(VMERR_WRONG_NUM_OF_ARGS);
 
863
 
 
864
        /* everything's fine - consume the arguments */
 
865
        *argc = 0;
 
866
 
 
867
        /* tell get_prop() to proceed with the native evaluation */
 
868
        return FALSE;
 
869
    }
 
870
    
 
871
#if 0
 
872
    /*
 
873
     *   Important note:
 
874
     *   
 
875
     *   This function has been removed because we no longer consider it
 
876
     *   likely that we will ever wish to implement a relocating heap
 
877
     *   manager.  Given the large memory sizes of modern computers, and
 
878
     *   recent academic research calling into question the conventional
 
879
     *   wisdom that heap fragmentation is actually a problem in practical
 
880
     *   applications, we no longer feel that maintaining the possibility of
 
881
     *   a relocating heap manager is justified.
 
882
     *   
 
883
     *   Note that some code in the present implementation assumes that the
 
884
     *   heap is non-relocating, so if a relocating heap manager is ever
 
885
     *   implemented, those assumptions will have to be addressed.  For
 
886
     *   example, the CVmObjTads code stores direct object pointers inside
 
887
     *   its objects, which is only possible with a non-relocating heap.  
 
888
     */
 
889
 
 
890
    /* 
 
891
     *   Adjust the extension pointer for a change - this must be called by
 
892
     *   the variable heap page when compacting the heap or when the object
 
893
     *   must be reallocated.
 
894
     *   
 
895
     *   This routine can be called ONLY during garbage collection.  The
 
896
     *   heap manager is not allowed to move variable-size blocks at any
 
897
     *   other time.
 
898
     *   
 
899
     *   This method is virtual because a given object could have more than
 
900
     *   one block allocated in the variable heap.  By default, we'll fix up
 
901
     *   the address of our extension if the block being moved (as
 
902
     *   identified by its old address) matches our existing extension
 
903
     *   pointer.  
 
904
     */
 
905
    virtual void move_var_part(void *old_pos, void *new_pos)
 
906
    {
 
907
        /* if the block being moved is our extension, note the new location */
 
908
        if (ext_ == (char *)old_pos)
 
909
            ext_ = (char *)new_pos;
 
910
    }
 
911
#endif
 
912
 
 
913
    /* 
 
914
     *   Pointer to extension.  This pointer may be used in any way
 
915
     *   desired by the subclassed implementation of the CVmObject
 
916
     *   interface; normally, this pointer will contain the address of the
 
917
     *   data associated with the object.  
 
918
     */
 
919
    char *ext_;
 
920
 
 
921
    /* property evaluator - undefined function */
 
922
    int getp_undef(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc,
 
923
                   vm_prop_id_t prop, vm_obj_id_t *source_obj);
 
924
 
 
925
    /* property evaluator - ofKind */
 
926
    int getp_of_kind(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc,
 
927
                     vm_prop_id_t prop, vm_obj_id_t *source_obj);
 
928
 
 
929
    /* property evaluator - getSuperclassList */
 
930
    int getp_sclist(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc,
 
931
                    vm_prop_id_t prop, vm_obj_id_t *source_obj);
 
932
 
 
933
    /* property evaluator - propDefined */
 
934
    int getp_propdef(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc,
 
935
                     vm_prop_id_t prop, vm_obj_id_t *source_obj);
 
936
 
 
937
    /* property evaluator - propType */
 
938
    int getp_proptype(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc,
 
939
                      vm_prop_id_t prop, vm_obj_id_t *source_obj);
 
940
 
 
941
    /* property evaluator - getPropList */
 
942
    int getp_get_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval,
 
943
                           uint *argc, vm_prop_id_t prop,
 
944
                           vm_obj_id_t *source_obj);
 
945
 
 
946
    /* property evaluator - getPropParams */
 
947
    int getp_get_prop_params(VMG_ vm_obj_id_t self, vm_val_t *retval,
 
948
                             uint *argc, vm_prop_id_t prop,
 
949
                             vm_obj_id_t *source_obj);
 
950
 
 
951
    /* property evaluator - isClass */
 
952
    int getp_is_class(VMG_ vm_obj_id_t self, vm_val_t *retval,
 
953
                      uint *argc, vm_prop_id_t prop,
 
954
                      vm_obj_id_t *source_obj);
 
955
 
 
956
    /* property evaluator - propInherited */
 
957
    int getp_propinh(VMG_ vm_obj_id_t self, vm_val_t *retval,
 
958
                     uint *argc, vm_prop_id_t prop,
 
959
                     vm_obj_id_t *source_obj);
 
960
 
 
961
    /* property evaluator - isTransient */
 
962
    int getp_is_transient(VMG_ vm_obj_id_t self, vm_val_t *retval,
 
963
                          uint *argc, vm_prop_id_t prop,
 
964
                          vm_obj_id_t *source_obj);
 
965
    
 
966
    /* find the intrinsic class for the given modifier object */
 
967
    virtual vm_obj_id_t find_intcls_for_mod(VMG_ vm_obj_id_t self,
 
968
                                            vm_obj_id_t mod_obj);
 
969
 
 
970
    /* property evaluation function table */
 
971
    static int (CVmObject::*func_table_[])(VMG_ vm_obj_id_t self,
 
972
                                           vm_val_t *retval, uint *argc,
 
973
                                           vm_prop_id_t prop,
 
974
                                           vm_obj_id_t *source_obj);
 
975
};
 
976
 
 
977
/*
 
978
 *   Function table indices for 'Object' intrinsic class methods.  Each of
 
979
 *   these gives the index in our function table for the property ID (as
 
980
 *   defined in the image file) corresponding to that method.  
 
981
 */
 
982
const int VMOBJ_IDX_OF_KIND = 1;
 
983
const int VMOBJ_IDX_SCLIST = 2;
 
984
const int VMOBJ_IDX_PROPDEF = 3;
 
985
const int VMOBJ_IDX_PROPTYPE = 4;
 
986
const int VMOBJ_IDX_GET_PROP_LIST = 5;
 
987
const int VMOBJ_IDX_GET_PROP_PARAMS = 6;
 
988
const int VMOBJ_IDX_IS_CLASS = 7;
 
989
const int VMOBJ_IDX_PROPINH = 8;
 
990
const int VMOBJ_IDX_IS_TRANSIENT = 9;
 
991
 
 
992
/* ------------------------------------------------------------------------ */
 
993
/*
 
994
 *   Each CVmObject subclass must define a singleton instance of
 
995
 *   CVmMetaclass that describes the class and instantiates objects of the
 
996
 *   class.  
 
997
 */
 
998
 
 
999
/*
 
1000
 *   The "registration index" is set at startup, when we register the
 
1001
 *   metaclasses.  This is static to the class - it isn't a per-instance
 
1002
 *   value.  The purpose of setting this value is to allow
 
1003
 *   get_registration_index() in the instance to get the class value.
 
1004
 *   This information is used when saving our state to save information on
 
1005
 *   an instance's metaclass, so that the instance can be re-created when
 
1006
 *   the saved state is restored.
 
1007
 *   
 
1008
 *   The registration index is NOT persistent data.  The registration
 
1009
 *   index of a particular metaclass can vary from execution to execution
 
1010
 *   (although it will remain fixed throughout the lifetime of one set of
 
1011
 *   VM globals, hence throughout an image file's execution).  The
 
1012
 *   registration index allows us to find the registration table entry,
 
1013
 *   which in turn will give us the metaclass global ID, which is suitable
 
1014
 *   for persistent storage.  
 
1015
 */
 
1016
 
 
1017
class CVmMetaclass
 
1018
{
 
1019
public:
 
1020
    /*
 
1021
     *   Get the metaclass registration table index.  This gives the index
 
1022
     *   of the metaclass in the system registration table.  This value is
 
1023
     *   fixed during execution; it is set during startup, when the
 
1024
     *   registration table is being built, and never changes after that. 
 
1025
     */
 
1026
    uint get_reg_idx() const { return meta_reg_idx_; }
 
1027
    
 
1028
    /* 
 
1029
     *   Get the metaclass name.  This is the universally unique
 
1030
     *   identifier assigned to the metaclass, and is the name used to
 
1031
     *   dynamically link the image file to the metaclass.  
 
1032
     */
 
1033
    virtual const char *get_meta_name() const = 0;
 
1034
 
 
1035
    /* 
 
1036
     *   Create an instance of the metaclass using arguments from the VM
 
1037
     *   stack.  Returns the ID of the newly-created object.  If the class
 
1038
     *   has a byte-code constructor, invoke the constructor using the
 
1039
     *   normal call-procedure protocol.  Leave the result in register R0. 
 
1040
     */
 
1041
    virtual vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
 
1042
                                          uint argc) = 0;
 
1043
 
 
1044
    /*
 
1045
     *   Create an instance of the metaclass with the given ID.  The
 
1046
     *   object table entry will already be allocated by the caller; this
 
1047
     *   ro utine only needs to invoke the metaclass-specific constructor
 
1048
     *   to initialize the object.  The object must be initialized in such
 
1049
     *   a way that it can subsequently be loaded from the image file with
 
1050
     *   load_from_iamge().  In general, this routine only needs to do
 
1051
     *   something like this:
 
1052
     *   
 
1053
     *   new (vmg_ id) CVmObjXxx(); 
 
1054
     */
 
1055
    virtual void create_for_image_load(VMG_ vm_obj_id_t id) = 0;
 
1056
 
 
1057
    /*
 
1058
     *   Create an instance of the metaclass with the given ID in
 
1059
     *   preparation for restoring the object from a saved state file. 
 
1060
     */
 
1061
    virtual void create_for_restore(VMG_ vm_obj_id_t id) = 0;
 
1062
 
 
1063
    /* 
 
1064
     *   Call a static property of the metaclass 
 
1065
     */
 
1066
    virtual int call_stat_prop(VMG_ vm_val_t *result,
 
1067
                               const uchar **pc_ptr, uint *argc,
 
1068
                               vm_prop_id_t prop) = 0;
 
1069
 
 
1070
    /*
 
1071
     *   Get the number of superclasses of the metaclass, and get the
 
1072
     *   super-metaclass at the given index.  All metaclasses have exactly
 
1073
     *   one super-metaclass, except for the root object metaclass, which
 
1074
     *   has no super-metaclass.  
 
1075
     */
 
1076
    virtual int get_supermeta_count(VMG0_) const { return 1; }
 
1077
    virtual vm_obj_id_t get_supermeta(VMG_ int idx) const;
 
1078
 
 
1079
    /* determine if I'm an instance of the given object */
 
1080
    virtual int is_meta_instance_of(VMG_ vm_obj_id_t obj) const;
 
1081
 
 
1082
    /* 
 
1083
     *   set the metaclass registration table index - this can only be
 
1084
     *   done by vm_register_metaclass() during initialization 
 
1085
     */
 
1086
    void set_metaclass_reg_index(uint idx) { meta_reg_idx_ = idx; }
 
1087
 
 
1088
    /* most metaclasses are simply derived from Object */
 
1089
    virtual CVmMetaclass *get_supermeta_reg() const
 
1090
        { return CVmObject::metaclass_reg_; }
 
1091
 
 
1092
    /* 
 
1093
     *   get my class object - we'll look up our class object in the
 
1094
     *   metaclass registration table 
 
1095
     */
 
1096
    vm_obj_id_t get_class_obj(VMG0_) const;
 
1097
 
 
1098
private:
 
1099
    /* system metaclass registration table index */
 
1100
    uint meta_reg_idx_;
 
1101
};
 
1102
     
 
1103
 
 
1104
/* ------------------------------------------------------------------------ */
 
1105
/*
 
1106
 *   Root Object definition.  The root object can never be instantiated;
 
1107
 *   it is defined purely to provide an object to represent as the root in
 
1108
 *   the type system.  
 
1109
 */
 
1110
class CVmMetaclassRoot: public CVmMetaclass
 
1111
{
 
1112
public:
 
1113
    /* get the metaclass name */
 
1114
    const char *get_meta_name() const { return "root-object/030004"; }
 
1115
 
 
1116
    /* create an instance - this class cannot be instantiated */
 
1117
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
 
1118
    {
 
1119
        err_throw(VMERR_BAD_DYNAMIC_NEW);
 
1120
        AFTER_ERR_THROW(return VM_INVALID_OBJ;)
 
1121
    }
 
1122
 
 
1123
    /* create an object - this class cannot be instantiated */
 
1124
    void create_for_image_load(VMG_ vm_obj_id_t id)
 
1125
        { err_throw(VMERR_BAD_STATIC_NEW); }
 
1126
 
 
1127
    /* create an instance for loading from a saved state */
 
1128
    void create_for_restore(VMG_ vm_obj_id_t id)
 
1129
        { err_throw(VMERR_BAD_STATIC_NEW); }
 
1130
 
 
1131
    /* call a static property */
 
1132
    int call_stat_prop(VMG_ vm_val_t *result,
 
1133
                       const uchar **pc_ptr, uint *argc,
 
1134
                       vm_prop_id_t prop)
 
1135
    {
 
1136
        /* call the base object implementation */
 
1137
        return CVmObject::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
 
1138
    }
 
1139
 
 
1140
    /* the root object has no supermetaclasses */
 
1141
    int get_supermeta_count(VMG0_) const { return 0; }
 
1142
    vm_obj_id_t get_supermeta(VMG_ int) const { return VM_INVALID_OBJ; }
 
1143
 
 
1144
    /* 
 
1145
     *   determine if I'm an instance of the given object - the root
 
1146
     *   object is not a subclass of anything 
 
1147
     */
 
1148
    virtual int is_meta_instance_of(VMG_ vm_obj_id_t obj) const
 
1149
        { return FALSE; }
 
1150
 
 
1151
    /* the base Object metaclass has no supermetaclass */
 
1152
    virtual CVmMetaclass *get_supermeta_reg() const { return 0; }
 
1153
};
 
1154
 
 
1155
/* ------------------------------------------------------------------------ */
 
1156
/*
 
1157
 *   Object fixup table entry 
 
1158
 */
 
1159
struct obj_fixup_entry
 
1160
{
 
1161
    /* old ID */
 
1162
    vm_obj_id_t old_id;
 
1163
 
 
1164
    /* new ID */
 
1165
    vm_obj_id_t new_id;
 
1166
};
 
1167
 
 
1168
/*
 
1169
 *   Object ID Fixup Table.  This is used during state restoration to map
 
1170
 *   from the saved state file's object numbering system to the new
 
1171
 *   in-memory numbering system.
 
1172
 *   
 
1173
 *   The objects must be added to the table IN ASCENDING ORDER OF OLD ID.
 
1174
 *   We assume this sorting order to perform a binary lookup when asked to
 
1175
 *   map an ID.  
 
1176
 */
 
1177
 
 
1178
/* fixup table subarray size */
 
1179
#define VMOBJFIXUP_SUB_SIZE 2048
 
1180
 
 
1181
class CVmObjFixup
 
1182
{
 
1183
public:
 
1184
    CVmObjFixup(ulong entry_cnt);
 
1185
    ~CVmObjFixup();
 
1186
 
 
1187
    /* add a fixup to the table */
 
1188
    void add_fixup(vm_obj_id_t old_id, vm_obj_id_t new_id);
 
1189
 
 
1190
    /* 
 
1191
     *   Translate from the file numbering system to the new numbering
 
1192
     *   system.  If the object isn't found, it must be a static object and
 
1193
     *   hence doesn't require translation, so we'll return the original ID
 
1194
     *   unchanged.  
 
1195
     */
 
1196
    vm_obj_id_t get_new_id(VMG_ vm_obj_id_t old_id);
 
1197
 
 
1198
    /* fix up a DATAHOLDER value */
 
1199
    void fix_dh(VMG_ char *dh);
 
1200
 
 
1201
    /* fix up an array of DATAHOLDER values */
 
1202
    void fix_dh_array(VMG_ char *arr, size_t cnt);
 
1203
 
 
1204
    /* fix a portable VMB_OBJECT_ID field */
 
1205
    void fix_vmb_obj(VMG_ char *p);
 
1206
 
 
1207
    /* fix an array of portable VMB_OBJECT_ID fields */
 
1208
    void fix_vmb_obj_array(VMG_ char *p, size_t cnt);
 
1209
 
 
1210
private:
 
1211
    /* find an entry given the old object ID */
 
1212
    struct obj_fixup_entry *find_entry(vm_obj_id_t old_entry);
 
1213
 
 
1214
    /* get an entry at the given array index */
 
1215
    struct obj_fixup_entry *get_entry(ulong idx) const
 
1216
    {
 
1217
        return &arr_[idx / VMOBJFIXUP_SUB_SIZE][idx % VMOBJFIXUP_SUB_SIZE];
 
1218
    }
 
1219
 
 
1220
    /* array of subarrays */
 
1221
    struct obj_fixup_entry **arr_;
 
1222
 
 
1223
    /* number of subarray pages */
 
1224
    ulong pages_;
 
1225
 
 
1226
    /* number of entries in the array */
 
1227
    ulong cnt_;
 
1228
 
 
1229
    /* number of entries used so far */
 
1230
    ulong used_;
 
1231
};
 
1232
 
 
1233
 
 
1234
/* ------------------------------------------------------------------------ */
 
1235
/*
 
1236
 *   Global variable structure.  We maintain a linked list of these
 
1237
 *   structures for miscellaneous global variables required by other
 
1238
 *   subsystems.  
 
1239
 */
 
1240
struct vm_globalvar_t
 
1241
{
 
1242
    /* the variable's value */
 
1243
    vm_val_t val;
 
1244
 
 
1245
    /* next and previous pointer in linked list of global variables */
 
1246
    vm_globalvar_t *nxt;
 
1247
    vm_globalvar_t *prv;
 
1248
};
 
1249
 
 
1250
 
 
1251
/* ------------------------------------------------------------------------ */
 
1252
/*
 
1253
 *   Global object page.  We keep a linked list of pages of globals that
 
1254
 *   refer to objects that are always reachable but were not loaded from the
 
1255
 *   image file.  
 
1256
 */
 
1257
class CVmObjGlobPage
 
1258
{
 
1259
public:
 
1260
    CVmObjGlobPage()
 
1261
    {
 
1262
        /* we're not in a list yet */
 
1263
        nxt_ = 0;
 
1264
 
 
1265
        /* we have no allocated entries yet */
 
1266
        used_ = 0;
 
1267
    }
 
1268
 
 
1269
    ~CVmObjGlobPage()
 
1270
    {
 
1271
        /* delete the next page */
 
1272
        delete nxt_;
 
1273
    }
 
1274
 
 
1275
    /* 
 
1276
     *   add an entry to this page; returns true on success, false if we're
 
1277
     *   too full to add another entry 
 
1278
     */
 
1279
    int add_entry(vm_obj_id_t obj)
 
1280
    {
 
1281
        /* if we're full, indicate failure */
 
1282
        if (used_ == sizeof(objs_)/sizeof(objs_[0]))
 
1283
            return FALSE;
 
1284
 
 
1285
        /* store the entry and count it */
 
1286
        objs_[used_] = obj;
 
1287
        ++used_;
 
1288
 
 
1289
        /* indicate success */
 
1290
        return TRUE;
 
1291
    }
 
1292
 
 
1293
    /* next page in list */
 
1294
    CVmObjGlobPage *nxt_;
 
1295
 
 
1296
    /* number of entries on this page that are in use */
 
1297
    size_t used_;
 
1298
 
 
1299
    /* array of entries on this page */
 
1300
    vm_obj_id_t objs_[30];
 
1301
};
 
1302
 
 
1303
/* ------------------------------------------------------------------------ */
 
1304
/*
 
1305
 *   Object Header Manager 
 
1306
 */
 
1307
 
 
1308
/* 
 
1309
 *   Number of objects in a page.  We constrain this to be a power of two
 
1310
 *   to make certain calculations fast (in particular, so that division by
 
1311
 *   and modulo the page count can be done as bit shifts and masks).  
 
1312
 */
 
1313
const unsigned int VM_OBJ_PAGE_CNT_LOG2 = 12;
 
1314
const unsigned int VM_OBJ_PAGE_CNT = (1 << VM_OBJ_PAGE_CNT_LOG2);
 
1315
 
 
1316
/*
 
1317
 *   Reachability states.  A Reachable object is in the root set, or can
 
1318
 *   be reached directly or indirectly from the root set.  A
 
1319
 *   Finalizer-Reachable object can be reached directly or indirectly from
 
1320
 *   a finalizable object that is Finalizer-Reachable or Unreachable, but
 
1321
 *   not from any reachable object.  An Unreachable object cannot be
 
1322
 *   reached from any Reachable or Finalizable object.
 
1323
 *   
 
1324
 *   We deliberately arrange the objects in a hierarchical order:
 
1325
 *   Finalizer-Reachable is "more reachable" than Unreachable, and
 
1326
 *   Reachable is more reachable than Finalizer-Reachable.  The numeric
 
1327
 *   values of these states are arranged so that a higher number indicates
 
1328
 *   stronger reachability.  
 
1329
 */
 
1330
#define VMOBJ_UNREACHABLE   0x00
 
1331
#define VMOBJ_F_REACHABLE   0x01
 
1332
#define VMOBJ_REACHABLE     0x02
 
1333
 
 
1334
/*
 
1335
 *   Finalization states.  An Unfinalizable object is one which has not
 
1336
 *   ever been detected by the garbage collector to be less than fully
 
1337
 *   Reachable.  A Finalizable object is one which has been found during a
 
1338
 *   garbage collection pass to be either F-Reachable or Unreachable, but
 
1339
 *   which has not yet been finalized.  A Finalized object is one which
 
1340
 *   has had its finalizer method invoked.  
 
1341
 */
 
1342
#define VMOBJ_UNFINALIZABLE 0x00
 
1343
#define VMOBJ_FINALIZABLE   0x01
 
1344
#define VMOBJ_FINALIZED     0x02
 
1345
 
 
1346
 
 
1347
/*
 
1348
 *   Object table page entry.
 
1349
 */
 
1350
struct CVmObjPageEntry
 
1351
{
 
1352
    /*
 
1353
     *   An entry is either a member of the free list, or it's a valid
 
1354
     *   object.
 
1355
     */
 
1356
    union
 
1357
    {
 
1358
        /* 
 
1359
         *   If it's not in the free list, then it's a VM object.  We
 
1360
         *   can't actually embed a true CVmObject here - that's an
 
1361
         *   abstract type and we therefore can't directly instantiate it
 
1362
         *   through embedding.  So, just allocate enough space for the
 
1363
         *   object; the memory manager will claim this space (via
 
1364
         *   operator new) and store the actual CVmObject here when the
 
1365
         *   slot is allocated to an object.  
 
1366
         */
 
1367
        char obj_[sizeof(CVmObject)];
 
1368
        
 
1369
        /* 
 
1370
         *   if it's in the free list, we just have a pointer to the
 
1371
         *   previous element of the free list 
 
1372
         */
 
1373
        vm_obj_id_t prev_free_;
 
1374
    } ptr_;
 
1375
 
 
1376
    /* next object in list (either the GC work queue or the free list) */
 
1377
    vm_obj_id_t next_obj_;
 
1378
 
 
1379
    /* get my VM object pointer */
 
1380
    CVmObject *get_vm_obj() const { return (CVmObject *)ptr_.obj_; }
 
1381
 
 
1382
    /* flag: the object is in the free list */
 
1383
    int free_ : 1;
 
1384
 
 
1385
    /* 
 
1386
     *   flag: the object is part of the root set (that is, there's a
 
1387
     *   reference to this object from some static location outside of the
 
1388
     *   root set, such as in p-code or in a constant list) 
 
1389
     */
 
1390
    int in_root_set_ : 1;
 
1391
 
 
1392
    /*
 
1393
     *   Reachability state.  This indicates whether the object is
 
1394
     *   reachable, reachable from finalizable objects only, or
 
1395
     *   unreachable.  This is set during garbage collection. 
 
1396
     */
 
1397
    uint reachable_ : 2;
 
1398
 
 
1399
    /*
 
1400
     *   Finalization state.  This indicates whether an object is
 
1401
     *   unfinalizable, finalizable, or finalized. 
 
1402
     */
 
1403
    uint finalize_state_ : 2;
 
1404
 
 
1405
    /*
 
1406
     *   Flag: the object is part of an undo savepoint.  This is cleared
 
1407
     *   when an object is initially created, and set for all existing
 
1408
     *   objects when an undo savepoint is created - this means that this
 
1409
     *   will be set for an object only if an undo savepoint has been
 
1410
     *   created since the object was created.
 
1411
     *   
 
1412
     *   When the undo mechanism is asked to create an undo record
 
1413
     *   associated with an object, it will do nothing if the object is not
 
1414
     *   part of the undo savepoint.  This means that we won't save undo
 
1415
     *   records for objects created since the start of the most recent
 
1416
     *   savepoint - keeping undo for such objects is unnecessary, since if
 
1417
     *   we roll back to the savepoint, the object won't even be in
 
1418
     *   existence any more and hence has no need to restore any of its
 
1419
     *   state.  
 
1420
     */
 
1421
    uint in_undo_ : 1;
 
1422
 
 
1423
    /*
 
1424
     *   Flag: the object is "transient."  A transient object does not
 
1425
     *   participate in undo, is not saved or restored to a saved state, and
 
1426
     *   is not affected by restarting.  
 
1427
     */
 
1428
    uint transient_ : 1;
 
1429
 
 
1430
    /* flag: the object has requested post-load initialization */
 
1431
    uint requested_post_load_init_ : 1;
 
1432
 
 
1433
    /*
 
1434
     *   Garbage collection hint flags.  These flags provide hints on how
 
1435
     *   the object's metaclass interacts with the garbage collector.  These
 
1436
     *   do NOT indicate the object's current status, but rather indicate
 
1437
     *   the metaclass's capabilities - so 'can_have_refs_' does not
 
1438
     *   indicate that the object current has or doesn't have any references
 
1439
     *   to other objects, but rather indicates if it's POSSIBLE for the
 
1440
     *   object EVER to have references to other objects.  For example, all
 
1441
     *   Strings would set 'can_have_refs_' to false, and all TadsObjects
 
1442
     *   would set it to true.
 
1443
     *   
 
1444
     *   We set these flags to true by default, for the maximally
 
1445
     *   conservative settings.  A metaclass can simply ignore these
 
1446
     *   settings and be assured of correct GC behavior.  However, if a
 
1447
     *   metaclass knows that it can correctly set one of these flags to
 
1448
     *   false, it should do so after instances are created, because doing
 
1449
     *   so allows the garbage collector to reduce the amount of work it
 
1450
     *   must do for the object.
 
1451
     *   
 
1452
     *   'can_have_refs_' indicates if the object can ever contain
 
1453
     *   references to other objects.  By default, this is always set to
 
1454
     *   true, but a metaclass that is not capable of storing references to
 
1455
     *   other objects should set this to false.  When this is set to false,
 
1456
     *   the garbage collector will avoid tracing into this object when
 
1457
     *   tracing references, because it will know in advance that tracing
 
1458
     *   into the object will have no effect.
 
1459
     *   
 
1460
     *   'can_have_weak_refs_' indicates if the object can ever contain weak
 
1461
     *   references to other objects.  By default, this is set to true, but
 
1462
     *   a metaclass that never uses weak references can set it to false.
 
1463
     *   When this is set to false, the garbage collector can avoid
 
1464
     *   notifying this object of the need to remove stale weak references.
 
1465
     *   
 
1466
     *   IMPORTANT: We assume that a metaclass that cannot have
 
1467
     *   references/weak references must ALSO never have references/weak
 
1468
     *   references) in its undo information.  It's hard to imagine a case
 
1469
     *   where we'd have no possibility of a kind of references in an object
 
1470
     *   but still have the possibility of the same kind of references in
 
1471
     *   the object's undo records; but should such a case arise, the
 
1472
     *   metaclass must indicate that it does have the possibility of that
 
1473
     *   kind of references.  
 
1474
     */
 
1475
    uint can_have_refs_ : 1;
 
1476
    uint can_have_weak_refs_ : 1;
 
1477
 
 
1478
    /* 
 
1479
     *   An entry is deletable if it's unreachable and has been finalized.
 
1480
     *   If the entry is marked as free, it's already been deleted, hence
 
1481
     *   is certainly deletable. 
 
1482
     */
 
1483
    int is_deletable() const
 
1484
    {
 
1485
        return (free_
 
1486
                || (reachable_ == VMOBJ_UNREACHABLE
 
1487
                    && finalize_state_ == VMOBJ_FINALIZED));
 
1488
    }
 
1489
 
 
1490
    /* 
 
1491
     *   Determine if the object should participate in undo.  An object
 
1492
     *   participates in undo if it existed as of the most recent savepoint,
 
1493
     *   and the object is not transient. 
 
1494
     */
 
1495
    int is_in_undo() const { return in_undo_ && !transient_; }
 
1496
 
 
1497
    /*
 
1498
     *   A "saveable" object is one which must be written to a saved state
 
1499
     *   file.
 
1500
     *   
 
1501
     *   To be saveable, an object must not be free, must not be transient,
 
1502
     *   must be fully reachable, and must have been modified since loading
 
1503
     *   (or simply have been created dynamically, since all an object that
 
1504
     *   was created dynamically has inherently been modified since the
 
1505
     *   program was loaded, as it didn't even exist when the program was
 
1506
     *   loaded).
 
1507
     *   
 
1508
     *   Do not save objects that are only reachable through a finalizer;
 
1509
     *   assume that these objects do not figure into the persistent VM
 
1510
     *   state, but are still around merely because they have some external
 
1511
     *   resource deallocation to which they must yet tend.
 
1512
     *   
 
1513
     *   Do not save objects that are in the root set and which haven't been
 
1514
     *   modified since loading.  We always reset before restoring to the
 
1515
     *   initial image file state, so there's no need to save data for any
 
1516
     *   object that's simply in its initial image file state.  
 
1517
     */
 
1518
    int is_saveable() const
 
1519
    {
 
1520
        return (!free_
 
1521
                && !transient_
 
1522
                && reachable_ == VMOBJ_REACHABLE
 
1523
                && (!in_root_set_
 
1524
                    || get_vm_obj()->is_changed_since_load()));
 
1525
    }
 
1526
 
 
1527
    /*
 
1528
     *   Determine if the object is "persistent."  A persistent object is
 
1529
     *   one which will survive saving and restoring machine state.  An
 
1530
     *   object is persistent if it is not transient, and either it is
 
1531
     *   saveable (in which case it will be explicitly saved and restored),
 
1532
     *   or it is merely in the root set (in which case it is always
 
1533
     *   present).  
 
1534
     */
 
1535
    int is_persistent() const
 
1536
    {
 
1537
        return !transient_ && (in_root_set_ || is_saveable());
 
1538
    }
 
1539
};
 
1540
 
 
1541
/* ------------------------------------------------------------------------ */
 
1542
/*
 
1543
 *   Object table.
 
1544
 */
 
1545
class CVmObjTable
 
1546
{
 
1547
public:
 
1548
    /* create the table */
 
1549
    CVmObjTable() { init(); }
 
1550
 
 
1551
    /* initialize */
 
1552
    void init();
 
1553
 
 
1554
    /* 
 
1555
     *   Destroy the table - call this rather BEFORE using operator delete
 
1556
     *   directly.  After this routine is called, the object table can be
 
1557
     *   deleted.  
 
1558
     */
 
1559
    void delete_obj_table(VMG0_);
 
1560
 
 
1561
    /* clients must call delete_obj_table() before deleting the object */
 
1562
    ~CVmObjTable();
 
1563
 
 
1564
    /* get an object given an object ID */
 
1565
    inline CVmObject *get_obj(vm_obj_id_t id) const
 
1566
    {
 
1567
        /* get the page entry, and get the object from the entry */
 
1568
        return (CVmObject *)&get_entry(id)->ptr_.obj_;
 
1569
    }
 
1570
 
 
1571
    /*
 
1572
     *   Turn garbage collection on or off.  When performing a series of
 
1573
     *   allocations of values that won't be stored on the stack, this can
 
1574
     *   be used to ensure that the intermediate allocations aren't
 
1575
     *   collected as unreferenced before the group of operations is
 
1576
     *   completed.  Returns previous status for later restoration.  
 
1577
     */
 
1578
    int enable_gc(VMG_ int enable);
 
1579
 
 
1580
    /* allocate a new object ID */
 
1581
    vm_obj_id_t alloc_obj(VMG_ int in_root_set)
 
1582
    {
 
1583
        /* allocate, using maximally conservative GC characteristics */
 
1584
        return alloc_obj(vmg_ in_root_set, TRUE, TRUE);
 
1585
    }
 
1586
 
 
1587
    /* allocate a new object ID */
 
1588
    vm_obj_id_t alloc_obj(VMG_ int in_root_set, int can_have_refs,
 
1589
                          int can_have_weak_refs);
 
1590
 
 
1591
    /*
 
1592
     *   Allocate an object at a particular object ID.  This is used when
 
1593
     *   loading objects from an image file or restoring objects from a
 
1594
     *   saved state file, since objects must be loaded or restored with
 
1595
     *   the same object number which they were originally assigned.  This
 
1596
     *   routine throws an error if the object is already allocated.
 
1597
     */
 
1598
    void alloc_obj_with_id(vm_obj_id_t id, int in_root_set)
 
1599
    {
 
1600
        /* allocate with maximally conservative GC characteristics */
 
1601
        alloc_obj_with_id(id, in_root_set, TRUE, TRUE);
 
1602
    }
 
1603
 
 
1604
    /* allocate an object with a given ID */
 
1605
    void alloc_obj_with_id(vm_obj_id_t id, int in_root_set,
 
1606
                           int can_have_refs, int can_have_weak_refs);
 
1607
 
 
1608
    /* 
 
1609
     *   Collect all garbage.  This runs an entire garbage collection pass
 
1610
     *   to completion with a single call.  This can be used for
 
1611
     *   simplicity when the caller does not require incremental operation
 
1612
     *   of the garbage collector.
 
1613
     *   
 
1614
     *   This function actually performs two garbage collection passes to
 
1615
     *   ensure that all collectible objects are collected.  We perform
 
1616
     *   one pass to detect finalizable objects, then finalize all objects
 
1617
     *   that we can, then make one more pass to sweep up all of the
 
1618
     *   finalized objects that can be deleted.  
 
1619
     */
 
1620
    void gc_full(VMG0_);
 
1621
 
 
1622
    /* 
 
1623
     *   Incremental garbage collection.  Call gc_pass_init() to
 
1624
     *   initialize the pass.  Call gc_pass_continue() repeatedly to
 
1625
     *   perform incremental collection; this routine runs for a short
 
1626
     *   time and then returns.  gc_pass_continue() returns true if
 
1627
     *   there's more work to do, false if not, so the caller can stop
 
1628
     *   invoking it as soon as it returns false.  Call gc_pass_finish()
 
1629
     *   to complete the garbage collection.  gc_pass_finish() will call
 
1630
     *   gc_pass_continue() if necessary to finish its work, so the caller
 
1631
     *   need not keep invoking gc_pass_continue() if it runs out of work
 
1632
     *   to interleave with the garbage collector.
 
1633
     *   
 
1634
     *   Once garbage collection is started, it must be finished before
 
1635
     *   any other VM activity occurs.  So, after a call to
 
1636
     *   gc_pass_init(), the caller is not allowed to perform any other VM
 
1637
     *   operations until gc_pass_finish() returns (in particular, no new
 
1638
     *   objects may be created, and no references to existing objects may
 
1639
     *   be created or changed).
 
1640
     */
 
1641
    void gc_pass_init(VMG0_);
 
1642
    int  gc_pass_continue(VMG0_) { return gc_pass_continue(vmg_ TRUE); }
 
1643
    void gc_pass_finish(VMG0_);
 
1644
 
 
1645
    /*
 
1646
     *   Run pending finalizers.  This can be run at any time other than
 
1647
     *   during garbage collection (i.e., between gc_pass_init() and
 
1648
     *   gc_pass_finish()).
 
1649
     */
 
1650
    void run_finalizers(VMG0_);
 
1651
 
 
1652
    /*
 
1653
     *   Determine if a given object is subject to deletion.  This only
 
1654
     *   gives meaningful results during the final garbage collector pass.
 
1655
     *   Returns true if the object is ready for deletion, which can only
 
1656
     *   happen when the object is both Unreachable and Finalized, or
 
1657
     *   false if it not.  A true return means that the object can be
 
1658
     *   deleted at any time.  This can be used by weak referencers to
 
1659
     *   determine if objects they are referencing are about to be
 
1660
     *   deleted, and thus that the weak reference must be forgotten.  
 
1661
     */
 
1662
    int is_obj_deletable(vm_obj_id_t obj) const
 
1663
    {
 
1664
        /* 
 
1665
         *   If it's not a valid object, consider it deletable, since it
 
1666
         *   has indeed already been deleted; otherwise, it's deletable if
 
1667
         *   its object table entry is deletable.  
 
1668
         */
 
1669
        return (obj == VM_INVALID_OBJ
 
1670
                || get_entry(obj)->is_deletable());
 
1671
    }
 
1672
 
 
1673
    /*
 
1674
     *   Mark object references (for GC tracing) made in an object's undo
 
1675
     *   record.  If the object is marked as having no possibility of
 
1676
     *   containing references to other objects, we won't bother invoking
 
1677
     *   the object's tracing method, as we can be assured that the undo
 
1678
     *   records won't contain any references either.  
 
1679
     */
 
1680
    void mark_obj_undo_rec(VMG_ vm_obj_id_t obj,
 
1681
                           struct CVmUndoRecord *undo_rec)
 
1682
    {
 
1683
        CVmObjPageEntry *entry;
 
1684
 
 
1685
        /* get the object entry */
 
1686
        entry = get_entry(obj);
 
1687
 
 
1688
        /* 
 
1689
         *   if the object can have any references, mark any references the
 
1690
         *   object makes from the undo record; if the object can't have any
 
1691
         *   references, assume its undo records cannot either, in which
 
1692
         *   case there should be nothing to mark 
 
1693
         */
 
1694
        if (entry->can_have_refs_)
 
1695
            entry->get_vm_obj()->mark_undo_ref(vmg_ undo_rec);
 
1696
    }
 
1697
 
 
1698
    /* 
 
1699
     *   Remove stale weak undo references for an object.  If the object is
 
1700
     *   marked as having no possibility of weak references, we won't bother
 
1701
     *   invoking the object's weak undo reference remover method, since we
 
1702
     *   know it won't do anything.  
 
1703
     */
 
1704
    void remove_obj_stale_undo_weak_ref(VMG_ vm_obj_id_t obj,
 
1705
                                        struct CVmUndoRecord *undo_rec)
 
1706
    {
 
1707
        CVmObjPageEntry *entry;
 
1708
        
 
1709
        /* get the object entry */
 
1710
        entry = get_entry(obj);
 
1711
 
 
1712
        /* 
 
1713
         *   if the object can have weak references, notify it; if not,
 
1714
         *   there's no need to do anything 
 
1715
         */
 
1716
        if (entry->can_have_weak_refs_)
 
1717
            entry->get_vm_obj()->remove_stale_undo_weak_ref(vmg_ undo_rec);
 
1718
    }
 
1719
 
 
1720
    /*
 
1721
     *   Determine if the given object is part of the latest undo savepoint.
 
1722
     *   Returns true if an undo savepoint has been created since the object
 
1723
     *   was created, false if not.  
 
1724
     */
 
1725
    int is_obj_in_undo(vm_obj_id_t obj) const
 
1726
    {
 
1727
        return (obj != VM_INVALID_OBJ
 
1728
                && get_entry(obj)->is_in_undo());
 
1729
    }
 
1730
 
 
1731
    /*
 
1732
     *   Determine if a vm_val_t contains a reference to a deletable object.
 
1733
     *   This is a simple convenience routine.  This returns true only if
 
1734
     *   the value contains a valid object reference, and the object is
 
1735
     *   currently deletable.  
 
1736
     */
 
1737
    int is_obj_deletable(const vm_val_t *val) const
 
1738
    {
 
1739
        return (val->typ == VM_OBJ
 
1740
                && val->val.obj != VM_INVALID_OBJ
 
1741
                && is_obj_deletable(val->val.obj));
 
1742
    }
 
1743
 
 
1744
    /*
 
1745
     *   Determine if the object is saveable.  If this returns true, the
 
1746
     *   object should be saved to a saved state file.  If not, the object
 
1747
     *   should not be included in the saved state file.  Note that a
 
1748
     *   non-saveable object might still be a persistent object - if the
 
1749
     *   object is a root set object and hasn't been modified since
 
1750
     *   loading, it's still peristent even though it doesn't get written
 
1751
     *   to the saved state file.  
 
1752
     */
 
1753
    int is_obj_saveable(vm_obj_id_t obj) const
 
1754
    {
 
1755
        return (obj != VM_INVALID_OBJ
 
1756
                && get_entry(obj)->is_saveable());
 
1757
    }
 
1758
 
 
1759
    /*
 
1760
     *   Determine if the object is persistent in a saved state.  If this
 
1761
     *   returns true, the object will survive saving and restoring the
 
1762
     *   machine state; if not, the object will not be present after the
 
1763
     *   machine state is restored.  This can be used to test if a weak
 
1764
     *   reference should be included in a saved state file.  
 
1765
     */
 
1766
    int is_obj_persistent(vm_obj_id_t obj) const
 
1767
    {
 
1768
        return (obj != VM_INVALID_OBJ
 
1769
                && get_entry(obj)->is_persistent());
 
1770
    }
 
1771
 
 
1772
    /* determine if the given object is transient */
 
1773
    int is_obj_transient(vm_obj_id_t obj) const
 
1774
    {
 
1775
        return (obj != VM_INVALID_OBJ
 
1776
                && get_entry(obj)->transient_);
 
1777
    }
 
1778
 
 
1779
    /* mark an object as transient */
 
1780
    void set_obj_transient(vm_obj_id_t obj) const
 
1781
    {
 
1782
        /* set the 'transient' flag in the object */
 
1783
        get_entry(obj)->transient_ = TRUE;
 
1784
    }
 
1785
 
 
1786
    /* set an object's garbage collection characteristics */
 
1787
    void set_obj_gc_characteristics(
 
1788
        vm_obj_id_t obj, int can_have_refs, int can_have_weak_refs) const
 
1789
    {
 
1790
        CVmObjPageEntry *entry;
 
1791
 
 
1792
        /* get the object's entry */
 
1793
        entry = get_entry(obj);
 
1794
 
 
1795
        /* set the entry's GC flags as specified */
 
1796
        entry->can_have_refs_ = can_have_refs;
 
1797
        entry->can_have_weak_refs_ = can_have_weak_refs;
 
1798
    }
 
1799
 
 
1800
    /* determine if the given object is in the root set */
 
1801
    int is_obj_in_root_set(vm_obj_id_t obj) const
 
1802
    {
 
1803
        return (obj != VM_INVALID_OBJ
 
1804
                && get_entry(obj)->in_root_set_);
 
1805
    }
 
1806
 
 
1807
    /*
 
1808
     *   Mark the given object as referenced, and recursively mark all of
 
1809
     *   the objects to which it refers as referenced.  
 
1810
     */
 
1811
    void mark_all_refs(vm_obj_id_t obj, uint state)
 
1812
        { add_to_gc_queue(obj, state); }
 
1813
 
 
1814
    /*
 
1815
     *   Receive notification from the undo manager that we're starting a
 
1816
     *   new savepoint.  We'll simply notify all of the objects of this. 
 
1817
     */
 
1818
    void notify_new_savept();
 
1819
 
 
1820
    /*
 
1821
     *   Apply an undo record 
 
1822
     */
 
1823
    void apply_undo(VMG_ struct CVmUndoRecord *rec);
 
1824
 
 
1825
    /*
 
1826
     *   Rebuild the image file's OBJS blocks for a particular metaclass.
 
1827
     *   We'll write all of the objects of the given metaclass to one or
 
1828
     *   more OBJS blocks in the given output file.  This can be used to
 
1829
     *   dump the program state to a new image file after running
 
1830
     *   'preinit' or a similar compile-time pre-initialization procedure.
 
1831
     *   
 
1832
     *   'meta_dep_idx' is the index in the metaclass dependency table of
 
1833
     *   the metaclass to be written.  
 
1834
     */
 
1835
    void rebuild_image(VMG_ int meta_dep_idx, class CVmImageWriter *writer,
 
1836
                       class CVmConstMapper *mapper);
 
1837
 
 
1838
    /*
 
1839
     *   Scan all objects and add metaclass entries to the metaclass
 
1840
     *   dependency table for any metaclasses of which there are existing
 
1841
     *   instances. 
 
1842
     */
 
1843
    void add_metadeps_for_instances(VMG0_);
 
1844
 
 
1845
    /*
 
1846
     *   Scan all active objects and convert objects to constant data
 
1847
     *   where possible.  Certain object metaclasses, such as strings and
 
1848
     *   lists, can be represented in a rebuilt image file as constant
 
1849
     *   data; this routine makes all of these conversions. 
 
1850
     */
 
1851
    void rebuild_image_convert_const_data(VMG_
 
1852
                                          class CVmConstMapper *const_mapper);
 
1853
 
 
1854
    /*
 
1855
     *   Get the maximum object ID that has ever been allocated.  This
 
1856
     *   establishes an upper bound on the object ID's that can be found
 
1857
     *   among the active objects.  
 
1858
     */
 
1859
    vm_obj_id_t get_max_used_obj_id() const
 
1860
        { return pages_used_ * VM_OBJ_PAGE_CNT; }
 
1861
 
 
1862
    /* determine if an object ID refers to a valid object */
 
1863
    int is_obj_id_valid(vm_obj_id_t obj) const
 
1864
    {
 
1865
        /* 
 
1866
         *   the object is valid as long as it's not free, and the ID is
 
1867
         *   within the valid range 
 
1868
         */
 
1869
        return (obj != VM_INVALID_OBJ
 
1870
                && obj < get_max_used_obj_id()
 
1871
                && !get_entry(obj)->free_);
 
1872
    }
 
1873
 
 
1874
    /*
 
1875
     *   Get the object state.  This is intended primarily as a debugging
 
1876
     *   and testing aid for the VM itself; this value should be of no
 
1877
     *   interest to normal programs.  Returns a value suitable for use
 
1878
     *   with CVmBifT3Test::get_obj_gc_state().  
 
1879
     */
 
1880
    ulong get_obj_internal_state(vm_obj_id_t id) const
 
1881
    {
 
1882
        /* if the object ID is invalid, return 0xF000 to so indicate */
 
1883
        if (id >= get_max_used_obj_id())
 
1884
            return 0xF000;
 
1885
 
 
1886
        /* 
 
1887
         *   return the state as a combination of these bits:
 
1888
         *   
 
1889
         *   free ? 0 : 1
 
1890
         *.  Unreachable=0x00, F-Reachable=0x10, Reachable=0x20
 
1891
         *.  Unfinalizable=0x000, Finalizable=0x100, Finalized=0x200 
 
1892
         */
 
1893
        return ((get_entry(id)->free_ ? 0 : 1)
 
1894
                + (((ulong)get_entry(id)->reachable_) << 4)
 
1895
                + (((ulong)get_entry(id)->finalize_state_) << 8));
 
1896
    }
 
1897
 
 
1898
    /*
 
1899
     *   Reset to the initial image file state.  Discards all objects not
 
1900
     *   in the root set, skipping finalizers, and resets all objects to
 
1901
     *   their initial image file state.  
 
1902
     */
 
1903
    void reset_to_image(VMG0_);
 
1904
 
 
1905
    /* 
 
1906
     *   Save state to a file.  We write out each object's state to the
 
1907
     *   file so that the state can be restored later. 
 
1908
     */
 
1909
    void save(VMG_ class CVmFile *fp);
 
1910
 
 
1911
    /* 
 
1912
     *   Restore state from a previously saved file.  Returns zero on
 
1913
     *   success, or a VMERR_xxx code on failure.
 
1914
     *   
 
1915
     *   This routine creates an object fixup table, and returns it in
 
1916
     *   *fixups.  The caller is responsible for deleting this object if a
 
1917
     *   non-null pointer is returned in *fixups.  
 
1918
     */
 
1919
    int restore(VMG_ class CVmFile *fp, class CVmObjFixup **fixups);
 
1920
 
 
1921
    /*
 
1922
     *   Save an object's image data pointer.  An object's load_from_image()
 
1923
     *   routine may call this routine (it cannot be called from anywhere
 
1924
     *   else) to save the loaded image location for the object.  For each
 
1925
     *   object that calls this routine, we will call the object's
 
1926
     *   reload_from_image() method during a reset to initial image file
 
1927
     *   state.  
 
1928
     */
 
1929
    void save_image_pointer(vm_obj_id_t obj, const char *ptr, size_t siz);
 
1930
 
 
1931
    /*
 
1932
     *   Request post-load initialization.  An object can call this to
 
1933
     *   request that its post_load_init() method be called after an initial
 
1934
     *   program load, restart, or restore operation.  The post_load_init()
 
1935
     *   method will not be called until the load/restart/restore operation
 
1936
     *   has loaded every object, so the method can be used to perform any
 
1937
     *   initialization that depends upon other objects being loaded.  
 
1938
     */
 
1939
    void request_post_load_init(vm_obj_id_t obj);
 
1940
 
 
1941
    /* remove a post-load initialization request */
 
1942
    void remove_post_load_init(vm_obj_id_t obj);
 
1943
 
 
1944
    /* invoke all registered post-load initializations */
 
1945
    void do_all_post_load_init(VMG0_);
 
1946
 
 
1947
    /*
 
1948
     *   Ensure that the given object has had its post-load initialization
 
1949
     *   performed during the current load/restart/restore.  If an object's
 
1950
     *   post-load initialization depends upon another object having already
 
1951
     *   been initialized, the first object should call this to ensure that
 
1952
     *   the other object it depends upon has been initialized.  This allows
 
1953
     *   objects to ensure that initialization dependencies are handled in
 
1954
     *   the correct order, regardless of the order in which the objects were
 
1955
     *   loaded.
 
1956
     *   
 
1957
     *   Post-load initialization is guaranteed to be executed exactly once
 
1958
     *   per load/restart/restore cycle.  When this routine is called, we
 
1959
     *   check to see if the target object has already been initialized
 
1960
     *   during this operation, and we do nothing if so.  If we do invoke the
 
1961
     *   target object's post_load_init(), then this will be the only
 
1962
     *   invocation for this operation.
 
1963
     *   
 
1964
     *   Circular dependencies are prohibited.  If object A's
 
1965
     *   post_load_init() method calls this to initialize object B, we will
 
1966
     *   invoke object B's post_load_init().  If object B in turn calls this
 
1967
     *   routine to initialize object A, we will observe that object A is
 
1968
     *   already in the process of being initialized and throw an error.  
 
1969
     */
 
1970
    void ensure_post_load_init(VMG_ vm_obj_id_t obj);
 
1971
 
 
1972
    /*
 
1973
     *   Add an object to the list of machine globals.  An object added to
 
1974
     *   this list will never be deleted.  If the object is in the root set
 
1975
     *   (which means it was loaded from the image file), we will ignore
 
1976
     *   this request, since a root object is inherently global.  
 
1977
     */
 
1978
    void add_to_globals(vm_obj_id_t obj);
 
1979
 
 
1980
    /*
 
1981
     *   Create a "global variable."  A global variable is part of the root
 
1982
     *   set: any value in a variable allocated here will be traced during
 
1983
     *   garbage collection.  Global variables are meant for use by other
 
1984
     *   subsystems, so that other subsystems can include their own static
 
1985
     *   and global variables in the root set.
 
1986
     *   
 
1987
     *   Global variables are not affected by RESTORE, RESTART, or UNDO (like
 
1988
     *   the stack, global variables are transient).
 
1989
     *   
 
1990
     *   The caller can use delete_global_var() to delete the variable when
 
1991
     *   done with it.  Any global variable that is never explicitly deleted
 
1992
     *   will be automatically deleted when the object table itself is
 
1993
     *   destroyed.  
 
1994
     */
 
1995
    vm_globalvar_t *create_global_var();
 
1996
    void delete_global_var(vm_globalvar_t *var);
 
1997
 
 
1998
private:
 
1999
    /* rebuild the image, writing only transient or only persistent objects */
 
2000
    void rebuild_image(VMG_ int meta_dep_idx, CVmImageWriter *writer,
 
2001
                       class CVmConstMapper *mapper, int trans);
 
2002
 
 
2003
    /* invoke a post-load initialization method */
 
2004
    static void call_post_load_init(VMG_ class CVmHashEntryPLI *entry);
 
2005
 
 
2006
    /* enumeration callbacks for post-load initialization */
 
2007
    static void pli_status_cb(void *ctx, class CVmHashEntry *entry);
 
2008
    static void pli_invoke_cb(void *ctx, class CVmHashEntry *entry);
 
2009
 
 
2010
    /* get the page entry for a given ID */
 
2011
    inline CVmObjPageEntry *get_entry(vm_obj_id_t id) const
 
2012
    {
 
2013
        return &pages_[id >> VM_OBJ_PAGE_CNT_LOG2][id & (VM_OBJ_PAGE_CNT - 1)];
 
2014
    }
 
2015
    
 
2016
    /* delete an entry */
 
2017
    void delete_entry(VMG_ vm_obj_id_t id, CVmObjPageEntry *entry);
 
2018
 
 
2019
    /* allocate a new page of objects */
 
2020
    void alloc_new_page();
 
2021
 
 
2022
    /* 
 
2023
     *   initialize a newly-allocated object table entry -- removes the
 
2024
     *   entry from the free list, marks the entry as allocated, marks it
 
2025
     *   in or out of the root set as appropriate, and initializes its GC
 
2026
     *   status as appropriate 
 
2027
     */
 
2028
    void init_entry_for_alloc(vm_obj_id_t id, CVmObjPageEntry *entry,
 
2029
                              int in_root_set, int can_have_refs,
 
2030
                              int can_have_weak_refs);
 
2031
 
 
2032
    /*
 
2033
     *   Mark an object as referenced for the garbage collector and add it
 
2034
     *   to the garbage collector's work queue.  If the object is already
 
2035
     *   marked as referenced, this does nothing. 
 
2036
     */
 
2037
    void add_to_gc_queue(vm_obj_id_t id, uint state)
 
2038
    {
 
2039
        /* get the object header and add it to the work queue */
 
2040
        add_to_gc_queue(id, get_entry(id), state);
 
2041
    }
 
2042
 
 
2043
    /* add an object to the gc work queue given the object header entry */
 
2044
    void add_to_gc_queue(vm_obj_id_t id, CVmObjPageEntry *entry, uint state)
 
2045
    {
 
2046
        /* 
 
2047
         *   If it's not already referenced somehow, add it to the queue.
 
2048
         *   If it's marked as referenced, it's already in the queue (or
 
2049
         *   it's already been in the queue and it's been processed).
 
2050
         *   
 
2051
         *   If the object cannot have references to other objects, don't
 
2052
         *   add it to the queue - simply elevate its reachability state.
 
2053
         *   We put objects in the queue in order to trace into the objects
 
2054
         *   they reference, so an object that can't reference any other
 
2055
         *   objects doesn't need to be put in the queue.  
 
2056
         */
 
2057
        if (entry->can_have_refs_ && entry->reachable_ == VMOBJ_UNREACHABLE)
 
2058
        {
 
2059
            /* add it to the work queue */
 
2060
            entry->next_obj_ = gc_queue_head_;
 
2061
            gc_queue_head_ = id;
 
2062
 
 
2063
            /* 
 
2064
             *   Since the entry is unreachable, and unreachable is the
 
2065
             *   lowest reachability state, we know that 'state' is at least
 
2066
             *   as reachable, so we can without further condidtions elevate
 
2067
             *   the reachability state.  (We can thus avoid the extra
 
2068
             *   comparison we have to do below for other current states.) 
 
2069
             */
 
2070
            entry->reachable_ = state;
 
2071
        }
 
2072
        else
 
2073
        {
 
2074
            /* 
 
2075
             *   Elevate the reachability state.  Never reduce an object's
 
2076
             *   reachability state: Finalizer-Reachable is higher than
 
2077
             *   Unreachable, and Reachable is higher than
 
2078
             *   Finalizer-Reachable.
 
2079
             *   
 
2080
             *   In other words, if an object is already marked Reachable,
 
2081
             *   never reduce its state to Finalizer-Reachable just because
 
2082
             *   we find that it can also be reached from a
 
2083
             *   Finalizer-Reachable object, when we already know that it
 
2084
             *   can be reached from a root-set object.  
 
2085
             */
 
2086
            if (state > entry->reachable_)
 
2087
                entry->reachable_ = state;
 
2088
        }
 
2089
    }
 
2090
 
 
2091
    /* 
 
2092
     *   Add an object to the finalizer work queue.  An object can only be
 
2093
     *   in one queue - it can't be in both the finalizer queue and the
 
2094
     *   main gc work queue.  
 
2095
     */
 
2096
    void add_to_finalize_queue(vm_obj_id_t id, CVmObjPageEntry *entry)
 
2097
    {
 
2098
        /* mark the object as finalizer-reachable */
 
2099
        entry->reachable_ = VMOBJ_F_REACHABLE;
 
2100
        
 
2101
        /* link it into the finalize list */
 
2102
        entry->next_obj_ = finalize_queue_head_;
 
2103
        finalize_queue_head_ = id;
 
2104
    }
 
2105
 
 
2106
    /*
 
2107
     *   Count an allocation and check to see if we should run garbage
 
2108
     *   collection.  We run gc after a certain number of consecutive
 
2109
     *   allocations to ensure that allocation-intensive operations don't
 
2110
     *   fill up memory if we can avoid it by removing unreferenced
 
2111
     *   objects.  
 
2112
     */
 
2113
    void alloc_check_gc(VMG_ int do_count)
 
2114
    {
 
2115
        /* count the allocation if desired */
 
2116
        if (do_count)
 
2117
            ++allocs_since_gc_;
 
2118
 
 
2119
        /* if we've passed our threshhold for collecting garbage, do so now */
 
2120
        if (gc_enabled_ && allocs_since_gc_ > max_allocs_between_gc_)
 
2121
            gc_before_alloc(vmg0_);
 
2122
    }
 
2123
 
 
2124
    /*
 
2125
     *   Run a garbage collection in preparation to allocate memory.  Runs
 
2126
     *   one garbage collection pass then one finalizer pass.  
 
2127
     */
 
2128
    void gc_before_alloc(VMG0_);
 
2129
 
 
2130
    /* garbage collection: trace objects reachable from the stack */
 
2131
    void gc_trace_stack(VMG0_);
 
2132
 
 
2133
    /* garbage collection: trace objects reachable from the imports */
 
2134
    void gc_trace_imports(VMG0_);
 
2135
 
 
2136
    /* garbage collection: trace objects reachable from machine globals */
 
2137
    void gc_trace_globals(VMG0_);
 
2138
 
 
2139
    /* garbage collection: trace all objects reachable from the work queue */
 
2140
    void gc_trace_work_queue(VMG_ int trace_transient);
 
2141
 
 
2142
    /* continue a GC pass */
 
2143
    int gc_pass_continue(VMG_ int trace_transient);
 
2144
 
 
2145
    /* 
 
2146
     *   set the initial GC conditions for an object -- this puts the
 
2147
     *   object into the appropriate queue and sets the appropriate
 
2148
     *   reachability state in preparation for the start of the next GC
 
2149
     *   pass 
 
2150
     */
 
2151
    void gc_set_init_conditions(vm_obj_id_t id,
 
2152
                                struct CVmObjPageEntry *entry)
 
2153
    {
 
2154
        /* 
 
2155
         *   Mark the object as unreachable -- at the start of each GC pass,
 
2156
         *   all non-root-set objects must be marked unreachable.  (It
 
2157
         *   doesn't matter how we mark root set objects, so we simply mark
 
2158
         *   everything as reachable to avoid an unnecessary test.)  
 
2159
         */
 
2160
        entry->reachable_ = VMOBJ_UNREACHABLE;
 
2161
 
 
2162
        /* 
 
2163
         *   If it's in the root set, add it to the GC work queue -- all
 
2164
         *   root-set objects must be in the work queue and marked as
 
2165
         *   reachable at the start of each GC pass.
 
2166
         */
 
2167
        if (entry->in_root_set_)
 
2168
            add_to_gc_queue(id, entry, VMOBJ_REACHABLE);
 
2169
    }
 
2170
 
 
2171
    /* hash table of objects requested post_load_init() service */
 
2172
    class CVmHashTable *post_load_init_table_;
 
2173
 
 
2174
    /* 
 
2175
     *   Head of global object page list.  The global objects are objects
 
2176
     *   that are always reachable but which weren't necessarily loaded from
 
2177
     *   the image file; these objects must be treated as dynamically
 
2178
     *   created for purposes such as saving, but must never be deleted as
 
2179
     *   long as they are globally reachable.  
 
2180
     */
 
2181
    CVmObjGlobPage *globals_;
 
2182
 
 
2183
    /* head of global variable list */
 
2184
    struct vm_globalvar_t *global_var_head_;
 
2185
 
 
2186
    /*
 
2187
     *   Master page table.  This is an array of pointers to pages.  Each
 
2188
     *   page contains a fixed number of slots for fixed-size parts.  
 
2189
     */
 
2190
    CVmObjPageEntry **pages_;
 
2191
 
 
2192
    /* number of page slots allocated, and the number actually used */
 
2193
    size_t page_slots_;
 
2194
    size_t pages_used_;
 
2195
 
 
2196
    /* first free object */
 
2197
    vm_obj_id_t first_free_;
 
2198
 
 
2199
    /* first page of saved image data pointers */
 
2200
    struct vm_image_ptr_page *image_ptr_head_;
 
2201
 
 
2202
    /* last page of saved image data pointers */
 
2203
    struct vm_image_ptr_page *image_ptr_tail_;
 
2204
 
 
2205
    /* number of image data pointers stored on last image pointer page */
 
2206
    size_t image_ptr_last_cnt_;
 
2207
 
 
2208
    /* head of garbage collection work queue */
 
2209
    vm_obj_id_t gc_queue_head_;
 
2210
 
 
2211
    /* head of finalizer queue */
 
2212
    vm_obj_id_t finalize_queue_head_;
 
2213
 
 
2214
    /* 
 
2215
     *   Allocations since last garbage collection.  We increment this on
 
2216
     *   each allocation, and reset it to zero each time we collect
 
2217
     *   garbage.  When we've performed too many allocations since the
 
2218
     *   last garbage collection, we force a gc pass. 
 
2219
     */
 
2220
    uint allocs_since_gc_;
 
2221
 
 
2222
    /*
 
2223
     *   Maximum number of allocations before we run the garbage
 
2224
     *   collector. 
 
2225
     */
 
2226
    uint max_allocs_between_gc_;
 
2227
 
 
2228
    /* garbage collection enabled */
 
2229
    uint gc_enabled_ : 1;
 
2230
};
 
2231
 
 
2232
/* ------------------------------------------------------------------------ */
 
2233
/*
 
2234
 *   An image data pointer.  The object table uses this structure to save
 
2235
 *   the image data location for a given object when the object requests
 
2236
 *   that this information be saved.  
 
2237
 */
 
2238
struct vm_image_ptr
 
2239
{
 
2240
    /* object ID */
 
2241
    vm_obj_id_t obj_id_;
 
2242
 
 
2243
    /* pointer to image data and length of the data */
 
2244
    const char *image_data_ptr_;
 
2245
    size_t image_data_len_;
 
2246
};
 
2247
 
 
2248
/*
 
2249
 *   Maximum number of image pointers stored per image pointer page 
 
2250
 */
 
2251
const size_t VM_IMAGE_PTRS_PER_PAGE = 400;
 
2252
 
 
2253
/*
 
2254
 *   A page of image pointers.  
 
2255
 */
 
2256
struct vm_image_ptr_page
 
2257
{
 
2258
    /* next page in the list of pages */
 
2259
    vm_image_ptr_page *next_;
 
2260
 
 
2261
    /* array of image pointers */
 
2262
    vm_image_ptr ptrs_[VM_IMAGE_PTRS_PER_PAGE];
 
2263
};
 
2264
 
 
2265
 
 
2266
/* ------------------------------------------------------------------------ */
 
2267
/*
 
2268
 *   The variable-size parts are stored in a heap separately from the object
 
2269
 *   headers.  Because the variable-size objects can expand or contract
 
2270
 *   dynamically, objects in the heap can move to new addresses.
 
2271
 *   
 
2272
 *   A particular block of memory in the heap is referenced by zero or one
 
2273
 *   object at any given time; a heap block is never shared among multiple
 
2274
 *   objects.  Furthermore, the only thing that can directly reference a
 
2275
 *   heap block is an object's fixed portion (through its extension
 
2276
 *   pointer).  Hence, we manage the variable heap directly through the
 
2277
 *   object headers: when an object becomes unreferenced, we explicitly free
 
2278
 *   the associated variable part.
 
2279
 *   
 
2280
 *   It is possible for a single object to allocate more than one heap
 
2281
 *   block.  In practice, most objects will allocate only one heap block (if
 
2282
 *   they allocate a heap block at all), but there is no reason an object
 
2283
 *   can't allocate more than one block.
 
2284
 *   
 
2285
 *   Note that polymorphism in the variable parts is handled via the fixed
 
2286
 *   part.  Because the fixed part is responsible for interactions with the
 
2287
 *   variable part, each fixed part implementation will be mated to a
 
2288
 *   particular variable part implementation.  These implementations may
 
2289
 *   themselves be polymorphic, of course, but this isn't directly necessary
 
2290
 *   in the base class.  
 
2291
 */
 
2292
 
 
2293
/*
 
2294
 *   Variable-size object heap interface.
 
2295
 */
 
2296
class CVmVarHeap
 
2297
{
 
2298
public:
 
2299
    virtual ~CVmVarHeap() { }
 
2300
    
 
2301
    /*
 
2302
     *   Initialize.  The global object table is valid at this point, and
 
2303
     *   will remain valid until after terminate() is called.  
 
2304
     */
 
2305
    virtual void init(VMG0_) = 0;
 
2306
 
 
2307
    /*
 
2308
     *   Terminate.  The global object table will remain valid until after
 
2309
     *   this function returns.
 
2310
     *   
 
2311
     *   The object table is expected to free each object's variable part
 
2312
     *   explicitly, so this function need not deallocate the memory used
 
2313
     *   by variable parts.  
 
2314
     */
 
2315
    virtual void terminate() = 0;
 
2316
    
 
2317
    /* 
 
2318
     *   Allocate a variable-size part.  'siz' is the size requested in
 
2319
     *   bytes, and 'obj' is a pointer to the object header.  The object
 
2320
     *   header will never move in memory, so this pointer is valid for as
 
2321
     *   long as the object remains allocated, hence the heap manager can
 
2322
     *   store the header pointer with the memory block if desired.  
 
2323
     */
 
2324
    virtual void *alloc_mem(size_t siz, CVmObject *obj) = 0;
 
2325
 
 
2326
    /*
 
2327
     *   Resize a variable-size part.  The 'siz' is the new size requested
 
2328
     *   in bytes, and 'varpart' is the old variable-size memory block.
 
2329
     *   This should return a new variable-size memory block containing a
 
2330
     *   copy of the data in the original block, but the block should be
 
2331
     *   resized to at least 'siz' bytes.  Returns a pointer to the new
 
2332
     *   block, which may move to a new memory location.
 
2333
     *   
 
2334
     *   If we move the memory to a new location, we are responsible for
 
2335
     *   freeing the old block of memory that the variable part occupied,
 
2336
     *   if necessary.
 
2337
     *   
 
2338
     *   We do not need to worry about informing the object header of any
 
2339
     *   change to the address of the variable part; the caller is
 
2340
     *   responsible for making any necessary changes in the object header
 
2341
     *   based on our return value.  
 
2342
     */
 
2343
    virtual void *realloc_mem(size_t siz, void *varpart,
 
2344
                              CVmObject *obj) = 0;
 
2345
 
 
2346
    /*
 
2347
     *   Free an object in the heap.  The object header may no longer be
 
2348
     *   valid after this function returns, so the heap manager should not
 
2349
     *   store the object header pointer after this function returns.  
 
2350
     */
 
2351
    virtual void free_mem(void *varpart) = 0;
 
2352
 
 
2353
#if 0
 
2354
    /* 
 
2355
     *   This is not currently used by the heap implementation (and doesn't
 
2356
     *   even have any theoretical reason to exist at the moment, since the
 
2357
     *   adoption of a non-moveable heap policy and the removal of
 
2358
     *   move_var_part()), so it's been removed to avoid the unnecessary
 
2359
     *   overhead of calling an empty method. 
 
2360
     */
 
2361
    
 
2362
    /*
 
2363
     *   Receive notification of the completion of a garbage collection
 
2364
     *   pass.  If the heap manager is capable of closing gaps in memory
 
2365
     *   by moving objects around, this is a good time to perform this
 
2366
     *   work, since we have just deleted all unreachable objects.
 
2367
     *   
 
2368
     *   If any object moves during processing here, we must call the
 
2369
     *   associated CVmObject's move_var_part() routine to tell it about
 
2370
     *   its new location.
 
2371
     *   
 
2372
     *   This routine isn't required to do anything at all.  It's simply
 
2373
     *   provided as a notification for heap managers that can take
 
2374
     *   advantage of the opportunity to compact the heap.  
 
2375
     */
 
2376
    virtual void finish_gc_pass() = 0;
 
2377
#endif
 
2378
};
 
2379
 
 
2380
 
 
2381
/* ------------------------------------------------------------------------ */
 
2382
/*
 
2383
 *   Simple variable-size object heap implementation.  This implementation
 
2384
 *   uses the normal C heap manager (malloc and free) to manage the heap.
 
2385
 */
 
2386
 
 
2387
/*
 
2388
 *   block header - we use the header to keep track of the size of the
 
2389
 *   object's data area
 
2390
 */
 
2391
struct CVmVarHeapMallocHdr
 
2392
{
 
2393
    /* size of the object */
 
2394
    size_t siz_;
 
2395
};
 
2396
 
 
2397
/*
 
2398
 *   heap implementation 
 
2399
 */
 
2400
class CVmVarHeapMalloc: public CVmVarHeap
 
2401
{
 
2402
public:
 
2403
    CVmVarHeapMalloc() { }
 
2404
    ~CVmVarHeapMalloc() { }
 
2405
 
 
2406
    /* initialize */
 
2407
    void init(VMG0_) { }
 
2408
 
 
2409
    /* terminate */
 
2410
    void terminate() { }
 
2411
 
 
2412
    /* allocate memory */
 
2413
    void *alloc_mem(size_t siz, CVmObject *)
 
2414
    {
 
2415
        CVmVarHeapMallocHdr *hdr;
 
2416
        
 
2417
        /* allocate space for the block plus the header */
 
2418
        hdr = (CVmVarHeapMallocHdr *)
 
2419
              t3malloc(siz + sizeof(CVmVarHeapMallocHdr));
 
2420
 
 
2421
        /* set up the header */
 
2422
        hdr->siz_ = siz;
 
2423
 
 
2424
        /* return the start of the part immediately after the header */
 
2425
        return (void *)(hdr + 1);
 
2426
    }
 
2427
 
 
2428
    /* reallocate memory */
 
2429
    void *realloc_mem(size_t siz, void *varpart, CVmObject *)
 
2430
    {
 
2431
        CVmVarHeapMallocHdr *hdr;
 
2432
 
 
2433
        /* 
 
2434
         *   get the original header, which immediately precedes the
 
2435
         *   original variable part in memory 
 
2436
         */
 
2437
        hdr = ((CVmVarHeapMallocHdr *)varpart) - 1;
 
2438
 
 
2439
        /* 
 
2440
         *   Reallocate it - the header is the actual memory block as far
 
2441
         *   as malloc was concerned, so realloc that.  Note that we must
 
2442
         *   add in the space needed for our header in the resized block.  
 
2443
         */
 
2444
        hdr = (CVmVarHeapMallocHdr *)
 
2445
              t3realloc(hdr, siz + sizeof(CVmVarHeapMallocHdr));
 
2446
 
 
2447
        /* adjust the size of the block in the header */
 
2448
        hdr->siz_ = siz;
 
2449
 
 
2450
        /* return the part immediately after the header */
 
2451
        return (void *)(hdr + 1);
 
2452
    }
 
2453
 
 
2454
    /* free memory */
 
2455
    void free_mem(void *varpart)
 
2456
    {
 
2457
        CVmVarHeapMallocHdr *hdr;
 
2458
 
 
2459
        /* 
 
2460
         *   get the original header, which immediately precedes the
 
2461
         *   original variable part in memory 
 
2462
         */
 
2463
        hdr = ((CVmVarHeapMallocHdr *)varpart) - 1;
 
2464
 
 
2465
        /* 
 
2466
         *   free the header, which is the actual memory block as far as
 
2467
         *   malloc was concerned 
 
2468
         */
 
2469
        t3free(hdr);
 
2470
    }
 
2471
 
 
2472
#if 0
 
2473
    /* removed with the removal of move_var_part() */
 
2474
    
 
2475
    /* 
 
2476
     *   complete garbage collection pass - we don't have to do anything
 
2477
     *   here, since we can't move objects around to consolidate free
 
2478
     *   space 
 
2479
     */
 
2480
    void finish_gc_pass() { }
 
2481
#endif
 
2482
    
 
2483
private:
 
2484
};
 
2485
 
 
2486
/* ------------------------------------------------------------------------ */
 
2487
/*
 
2488
 *   Hybrid cell-based and malloc-based heap allocator.  This heap manager
 
2489
 *   uses arrays of fixed-size blocks to allocate small objects, and falls
 
2490
 *   back on malloc for allocating large objects.  Small-block allocations
 
2491
 *   and frees are fast, require very little memory overhead, and minimize
 
2492
 *   heap fragmentation by packing large blocks of fixed-size items into
 
2493
 *   arrays, then suballocating out of free lists built from the arrays.  
 
2494
 */
 
2495
 
 
2496
/*
 
2497
 *   Each item we allocate from a small-object array has a header that
 
2498
 *   points back to the array's master list.  This is necessary so that we
 
2499
 *   can put the object back in the appropriate free list when it is
 
2500
 *   deleted.  
 
2501
 */
 
2502
struct CVmVarHeapHybrid_hdr
 
2503
{
 
2504
    /* 
 
2505
     *   the block interface that allocated this object -- we use this
 
2506
     *   when we free the object so that we can call the free() routine in
 
2507
     *   the block manager that originally did the allocation 
 
2508
     */
 
2509
    class CVmVarHeapHybrid_block *block;
 
2510
};
 
2511
 
 
2512
/*
 
2513
 *   Hybrid heap allocator - sub-block interface.  Each small-object cell
 
2514
 *   list is represented by one of these objects, as is the fallback
 
2515
 *   malloc allocator.  
 
2516
 */
 
2517
class CVmVarHeapHybrid_block
 
2518
{
 
2519
public:
 
2520
    /* allocate memory */
 
2521
    virtual struct CVmVarHeapHybrid_hdr *alloc(size_t siz) = 0;
 
2522
 
 
2523
    /* free memory */
 
2524
    virtual void free(struct CVmVarHeapHybrid_hdr *) = 0;
 
2525
 
 
2526
    /*
 
2527
     *   Reallocate memory.  If necessary, allocate new memory, copy the
 
2528
     *   data to the new memory, and delete the old memory.  We receive
 
2529
     *   the heap manager as an argument so that we can call it to
 
2530
     *   allocate new memory if necessary.  
 
2531
     */
 
2532
    virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
 
2533
                          class CVmObject *obj) = 0;
 
2534
};
 
2535
 
 
2536
/*
 
2537
 *   Malloc suballocator 
 
2538
 */
 
2539
class CVmVarHeapHybrid_malloc: public CVmVarHeapHybrid_block
 
2540
{
 
2541
public:
 
2542
    /* allocate memory */
 
2543
    virtual struct CVmVarHeapHybrid_hdr *alloc(size_t siz)
 
2544
    {
 
2545
        CVmVarHeapHybrid_hdr *ptr;
 
2546
        
 
2547
        /* adjust the size to add in the required header */
 
2548
        siz = osrndsz(siz + sizeof(CVmVarHeapHybrid_hdr));
 
2549
        
 
2550
        /* allocate directly via the default system heap manager */
 
2551
        ptr = (CVmVarHeapHybrid_hdr *)t3malloc(siz);
 
2552
 
 
2553
        /* fill in the header */
 
2554
        ptr->block = this;
 
2555
 
 
2556
        /* return the new block */
 
2557
        return ptr;
 
2558
    }
 
2559
 
 
2560
    /* release memory */
 
2561
    virtual void free(CVmVarHeapHybrid_hdr *mem)
 
2562
    {
 
2563
        /* release the memory directly to the default system heap manager */
 
2564
        t3free(mem);
 
2565
    }
 
2566
 
 
2567
    /* reallocate memory */
 
2568
    virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
 
2569
                          CVmObject *)
 
2570
    {
 
2571
        CVmVarHeapHybrid_hdr *ptr;
 
2572
        
 
2573
        /* adjust the new size to add in the required header */
 
2574
        siz = osrndsz(siz + sizeof(CVmVarHeapHybrid_hdr));
 
2575
 
 
2576
        /* reallocate the block */
 
2577
        ptr = (CVmVarHeapHybrid_hdr *)t3realloc(mem, siz);
 
2578
 
 
2579
        /* fill in the header in the new block */
 
2580
        ptr->block = this;
 
2581
 
 
2582
        /* return the caller-visible part of the new block */
 
2583
        return (void *)(ptr + 1);
 
2584
    }
 
2585
};
 
2586
 
 
2587
/*
 
2588
 *   Small-object array list head.  We suballocate small objects from
 
2589
 *   these arrays.  We maintain one of these objects for each distinct
 
2590
 *   cell size; this object manages all of the storage for blocks of the
 
2591
 *   cell size.  
 
2592
 */
 
2593
class CVmVarHeapHybrid_head: public CVmVarHeapHybrid_block
 
2594
{
 
2595
public:
 
2596
    CVmVarHeapHybrid_head(class CVmVarHeapHybrid *mem_mgr,
 
2597
                          size_t cell_size, size_t page_count)
 
2598
    {
 
2599
        /* remember our memory manager */
 
2600
        mem_mgr_ = mem_mgr;
 
2601
        
 
2602
        /* remember our cell size and number of items per array */
 
2603
        cell_size_ = cell_size;
 
2604
        page_count_ = page_count;
 
2605
 
 
2606
        /* we have nothing in our free list yet */
 
2607
        first_free_ = 0;
 
2608
    }
 
2609
    
 
2610
    /* allocate an object from my pool, expanding the pool if necessary */
 
2611
    CVmVarHeapHybrid_hdr *alloc(size_t siz);
 
2612
 
 
2613
    /* free a cell */
 
2614
    void free(CVmVarHeapHybrid_hdr *mem);
 
2615
 
 
2616
    /* reallocate */
 
2617
    virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
 
2618
                          class CVmObject *obj);
 
2619
 
 
2620
    /* get the cell size for this cell manager */
 
2621
    size_t get_cell_size() const { return cell_size_; }
 
2622
 
 
2623
private:
 
2624
    /* size of each cell in the array */
 
2625
    size_t cell_size_;
 
2626
 
 
2627
    /* number of items we allocate per array */
 
2628
    size_t page_count_;
 
2629
 
 
2630
    /* head of the free list of cells in this array */
 
2631
    void *first_free_;
 
2632
 
 
2633
    /* our memory manager */
 
2634
    CVmVarHeapHybrid *mem_mgr_;
 
2635
};
 
2636
 
 
2637
/*
 
2638
 *   Small-object array list block.  We dynamically allocate these array
 
2639
 *   blocks as needed to hold blocks of a particular size.  
 
2640
 */
 
2641
struct CVmVarHeapHybrid_array
 
2642
{
 
2643
    /* next array in the master list */
 
2644
    CVmVarHeapHybrid_array *next_array;
 
2645
 
 
2646
    /* 
 
2647
     *   memory for allocation (we over-allocate the structure to make
 
2648
     *   room for some number of our fixed-size cells) 
 
2649
     */
 
2650
    char mem[1];
 
2651
};
 
2652
 
 
2653
/*
 
2654
 *   heap implementation 
 
2655
 */
 
2656
class CVmVarHeapHybrid: public CVmVarHeap
 
2657
{
 
2658
    friend class CVmVarHeapHybrid_head;
 
2659
    
 
2660
public:
 
2661
    CVmVarHeapHybrid();
 
2662
    ~CVmVarHeapHybrid();
 
2663
 
 
2664
    /* initialize */
 
2665
    void init(VMG0_) { }
 
2666
 
 
2667
    /* terminate */
 
2668
    void terminate() { }
 
2669
 
 
2670
    /* allocate memory */
 
2671
    void *alloc_mem(size_t siz, CVmObject *obj);
 
2672
 
 
2673
    /* reallocate memory */
 
2674
    void *realloc_mem(size_t siz, void *varpart, CVmObject *obj);
 
2675
 
 
2676
    /* free memory */
 
2677
    void free_mem(void *varpart);
 
2678
 
 
2679
#if 0
 
2680
    /* removed with the removal of move_var_part() */
 
2681
    
 
2682
    /* 
 
2683
     *   complete garbage collection pass - we don't have to do anything
 
2684
     *   here, since we can't move objects around to consolidate free
 
2685
     *   space 
 
2686
     */
 
2687
    void finish_gc_pass() { }
 
2688
#endif
 
2689
    
 
2690
private:
 
2691
    /* 
 
2692
     *   Head of list of arrays.  We keep this list so that we can delete
 
2693
     *   all of the arrays when we delete this heap manager object itself.
 
2694
     */
 
2695
    CVmVarHeapHybrid_array *first_array_;
 
2696
 
 
2697
    /* 
 
2698
     *   Array of cell-based subheap managers.  This array will be ordered
 
2699
     *   from smallest to largest, so we can search it for the best fit to
 
2700
     *   a requested size. 
 
2701
     */
 
2702
    CVmVarHeapHybrid_head **cell_heaps_;
 
2703
 
 
2704
    /* number of cell heap managers */
 
2705
    size_t cell_heap_cnt_;
 
2706
 
 
2707
    /*
 
2708
     *   Our fallback malloc heap manager.  We'll use this allocator for
 
2709
     *   any blocks that we can't allocate from one of our cell-based
 
2710
     *   memory managers. 
 
2711
     */
 
2712
    CVmVarHeapHybrid_malloc *malloc_heap_;
 
2713
};
 
2714
 
 
2715
/* ------------------------------------------------------------------------ */
 
2716
/*
 
2717
 *   Memory Manager - this is the primary interface to the object memory
 
2718
 *   subsystem.  
 
2719
 */
 
2720
class CVmMemory
 
2721
{
 
2722
public:
 
2723
    /* create the memory manager, using a given variable-size heap */
 
2724
    CVmMemory(VMG_ CVmVarHeap *varheap);
 
2725
 
 
2726
    /* delete the memory manager */
 
2727
    ~CVmMemory()
 
2728
    {
 
2729
        /* tell the variable-size heap to disengage */
 
2730
        varheap_->terminate();
 
2731
    }
 
2732
 
 
2733
    /* get the variable heap manager */
 
2734
    CVmVarHeap *get_var_heap() const { return varheap_; }
 
2735
 
 
2736
private:
 
2737
    /* variable-size object heap */
 
2738
    CVmVarHeap *varheap_;
 
2739
 
 
2740
    /* our constant pool manager */
 
2741
    class CVmPool *constant_pool_;
 
2742
};
 
2743
 
 
2744
/* ------------------------------------------------------------------------ */
 
2745
/*
 
2746
 *   Allocate a new object ID 
 
2747
 */
 
2748
inline vm_obj_id_t vm_new_id(VMG_ int in_root_set)
 
2749
{
 
2750
    /* ask the global object table to allocate a new ID */
 
2751
    return G_obj_table->alloc_obj(vmg_ in_root_set);
 
2752
}
 
2753
 
 
2754
/*
 
2755
 *   Allocate a new object ID, setting GC characteristics 
 
2756
 */
 
2757
inline vm_obj_id_t vm_new_id(VMG_ int in_root_set, int can_have_refs,
 
2758
                             int can_have_weak_refs)
 
2759
{
 
2760
    /* ask the global object table to allocate a new ID */
 
2761
    return G_obj_table->alloc_obj(vmg_ in_root_set, can_have_refs,
 
2762
                                  can_have_weak_refs);
 
2763
}
 
2764
 
 
2765
/*
 
2766
 *   Given an object ID, get a pointer to the object 
 
2767
 */
 
2768
inline CVmObject *vm_objp(VMG_ vm_obj_id_t id)
 
2769
{
 
2770
    /* ask the global object table to translate the ID */
 
2771
    return G_obj_table->get_obj(id);
 
2772
}
 
2773
 
 
2774
#endif /* VMOBJ_H */
 
2775
 
 
2776
/*
 
2777
 *   Register the root object class
 
2778
 */
 
2779
VM_REGISTER_METACLASS(CVmObject)