1
/* $Header: d:/cvsroot/tads/tads3/VMOBJ.H,v 1.3 1999/07/11 00:46:58 MJRoberts Exp $ */
4
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
6
* Please see the accompanying license file, LICENSE.TXT, for information
7
* on using and copying this software.
11
vmobj.h - VM object memory manager
17
10/20/98 MJRoberts - Creation
32
/* ------------------------------------------------------------------------ */
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.
38
#ifndef VM_REGISTER_METACLASS
39
# define VM_REGISTER_METACLASS(metaclass)
42
/* ------------------------------------------------------------------------ */
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:
52
* VM_REGISTER_METACLASS("metaclass-string-name", CVmClassName)
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).
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.
64
/* ------------------------------------------------------------------------ */
66
* To get a pointer to an object (CVmObject *) given an object ID
67
* (vm_obj_id_t), use this:
69
* CVmObject *obj = vm_objp(vmg_ id);
71
* To allocate a new object:
73
* vm_obj_id_t id = vm_newid(vmg_ in_root_set);
74
*. CVmObject *obj = new (vmg_ id) CVmObjXxx(constructor params);
76
* The functions vm_objp() and vm_newid() are defined later in this
81
/* ------------------------------------------------------------------------ */
83
* Garbage collector work increment. This is the number of objects that
84
* the GC will process on each call to gc_pass_queue().
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.
94
const int VM_GC_WORK_INCREMENT = 500;
98
/* ------------------------------------------------------------------------ */
100
* flag values for propDefined
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
108
/* ------------------------------------------------------------------------ */
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.
118
/* ------------------------------------------------------------------------ */
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.
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.
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
138
* The fixed-size objects are always allocated within the page table,
139
* thus operator new is overridden to allocate memory within the page
143
* In addition to the virtual methods listed, every object must define a
144
* data member as follows:
146
* public: static class CVmMetaclass *metaclass_reg_;
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
157
friend class CVmVarHeap;
160
/* metaclass registration object (for the root object implementation) */
161
static class CVmMetaclass *metaclass_reg_;
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.
168
static int call_stat_prop(VMG_ vm_val_t *retval, const uchar **pc_ptr,
169
uint *argc, vm_prop_id_t);
171
/* get the registration object for this metaclass */
172
virtual class CVmMetaclass *get_metaclass_reg() const
173
{ return metaclass_reg_; }
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.
180
virtual int is_of_metaclass(class CVmMetaclass *meta) const
181
{ return (meta == metaclass_reg_); }
184
* Receive notification that this object is being deleted - the
185
* garbage collector calls this function when the object is
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.)
195
virtual void notify_delete(VMG_ int in_root_set) = 0;
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.
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.
207
virtual void create_instance(VMG_ vm_obj_id_t self,
208
const uchar **pc_ptr, uint argc)
210
/* throw the error */
211
err_throw(VMERR_CANNOT_CREATE_INST);
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.
220
virtual int has_finalizer(VMG_ vm_obj_id_t /*self*/)
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.
229
virtual void invoke_finalizer(VMG_ vm_obj_id_t /*self*/) { }
232
* Determine if this is a class object. This returns true if this
233
* object is a class, false if it's an instance.
235
virtual int is_class_object(VMG_ vm_obj_id_t /*self*/) const
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.
245
virtual int is_instance_of(VMG_ vm_obj_id_t obj);
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.
252
virtual int get_superclass_count(VMG_ vm_obj_id_t /*self*/) const
254
virtual vm_obj_id_t get_superclass(VMG_ vm_obj_id_t /*self*/,
255
int /*superclass_index*/) const;
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.
263
virtual int provides_props(VMG0_) const { return FALSE; }
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
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),
277
/* by default, assume we have nothing to enumerate */
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;
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.
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.
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.
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).
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,
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)
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.
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'.
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().
337
* 'argc' has the same meaning as for get_prop().
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.
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,
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
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.
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.
363
virtual void build_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval);
366
* Mark all strongly-referenced objects. Calls
367
* obj_table->mark_refs() for each referenced object.
369
virtual void mark_refs(VMG_ uint state) = 0;
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.
376
virtual void remove_stale_weak_refs(VMG0_) = 0;
379
* Receive notification that the undo manager is creating a new
382
virtual void notify_new_savept() = 0;
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
390
virtual void apply_undo(VMG_ struct CVmUndoRecord *rec) = 0;
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.
398
virtual void discard_undo(VMG_ struct CVmUndoRecord *) { }
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.
406
virtual void mark_undo_ref(VMG_ struct CVmUndoRecord *rec) = 0;
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').
417
virtual void remove_stale_undo_weak_ref(VMG_
418
struct CVmUndoRecord *rec) = 0;
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.
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.
433
virtual void post_load_init(VMG_ vm_obj_id_t /*self*/)
435
/* we do nothing by default */
439
* Load the object from an image file. The object's data block is
440
* at the given address and has the given size.
442
* The underlying memory is owned by the image file loader. The
443
* object must not attempt to deallocate this memory.
445
virtual void load_from_image(VMG_ vm_obj_id_t self,
446
const char *ptr, size_t siz) = 0;
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,
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.
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().
468
virtual void reload_from_image(VMG_ vm_obj_id_t self,
469
const char *ptr, size_t siz) { }
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.
476
* NOTE: this routine doesn't have to do anything if
477
* reload_from_image() is implemented for the object.
479
virtual void reset_to_image(VMG_ vm_obj_id_t /*self*/) { }
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
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.
493
virtual int is_changed_since_load() const { return FALSE; }
496
* save this object to a file, so that it can be restored to its
497
* current state via restore_from_file
499
virtual void save_to_file(VMG_ class CVmFile *fp) = 0;
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.
507
virtual void restore_from_file(VMG_ vm_obj_id_t self,
509
class CVmObjFixup *fixups) = 0;
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.
520
* 'depth' has the same meaning as in calc_hash().
522
virtual int equals(VMG_ vm_obj_id_t self, const vm_val_t *val,
525
/* return true if the other value is a reference to this object */
526
return (val->typ == VM_OBJ && val->val.obj == self);
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.
536
* By default, magnitude comparisons between objects are not
537
* meaningful, so we throw an error.
539
virtual int compare_to(VMG_ vm_obj_id_t /*self*/, const vm_val_t *) const
541
/* by default, magnitude comparisons between objects are illegal */
542
err_throw(VMERR_INVALID_COMPARISON);
544
/* the compiler doesn't know that we'll never get here */
545
AFTER_ERR_THROW(return 0;)
549
* Calculate a hash value for the object.
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
560
virtual uint calc_hash(VMG_ vm_obj_id_t self, int /*depth*/) const
563
* by default, use a 16-bit hash of our object ID as the hash
566
return (uint)(((ulong)self & 0xffff)
567
^ (((ulong)self & 0xffff0000) >> 16));
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.
577
* By default, we'll throw an error indicating that the value cannot
580
virtual void add_val(VMG_ vm_val_t * /*result*/,
581
vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
584
err_throw(VMERR_BAD_TYPE_ADD);
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.
593
virtual void sub_val(VMG_ vm_val_t * /*result*/,
594
vm_obj_id_t /*self*/, const vm_val_t * /*val*/)
597
err_throw(VMERR_BAD_TYPE_SUB);
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*/)
605
err_throw(VMERR_BAD_TYPE_MUL);
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*/)
613
err_throw(VMERR_BAD_TYPE_DIV);
616
/* negate the value, returning the result in *result */
617
virtual void neg_val(VMG_ vm_val_t * /* result */, vm_obj_id_t self)
620
err_throw(VMERR_BAD_TYPE_NEG);
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.
631
virtual size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const
633
/* by default, we contribute only 'self', thus only one element */
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*/)
641
/* by default, we contribute only 'self' */
642
retval->set_obj(self);
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.
651
virtual void index_val(VMG_ vm_val_t * /*result*/,
652
vm_obj_id_t /*self*/,
653
const vm_val_t * /*index_val*/)
655
/* by default, throw an error */
656
err_throw(VMERR_CANNOT_INDEX_TYPE);
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.
669
* By default, we'll throw an error, since default objects cannot be
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*/)
677
/* by default, throw an error */
678
err_throw(VMERR_CANNOT_INDEX_TYPE);
682
* Get a string representation of the object. If necessary, this
683
* can create a new string object to represent the result.
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
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.
697
* If it is not possible to create a string representation of the
698
* object, throw an error (VMERR_NO_STR_CONV).
700
* By default, we'll throw an error indicating that the object
701
* cannot be converted to a string.
703
virtual const char *cast_to_string(VMG_ vm_obj_id_t /*self*/,
704
vm_val_t * /*new_str*/) const
707
err_throw(VMERR_NO_STR_CONV);
709
/* we can't get here, but the compiler doesn't know that */
710
AFTER_ERR_THROW(return 0;)
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
721
* Most object classes will return null for this, since they do not
722
* store lists. By default, we return null.
724
virtual const char *get_as_list() const { return 0; }
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).
733
* Most object classes will return null for this, since they do not
734
* store strings. By default, we return null.
736
virtual const char *get_as_string(VMG0_) const { return 0; }
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.
743
* This should write the complete metaclass-specific record needed
744
* for an OBJS data block entry, not including the generic header.
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
753
virtual ulong rebuild_image(VMG_ char *, ulong)
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.
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.
767
virtual void reserve_const_data(VMG_ class CVmConstMapper *,
768
vm_obj_id_t /*self*/)
769
{ /* default does nothing */ }
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).
784
virtual void convert_to_const_data(VMG_ class CVmConstMapper *,
785
vm_obj_id_t /*self*/)
786
{ /* default does nothing */ }
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.
797
virtual vm_datatype_t get_convert_to_const_data_type() const
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.
806
* To create an object, use a sequence like this:
808
* obj_id = mem_mgr->get_obj_table()->alloc_obj(vmg_ in_root_set);
809
*. new (vmg_ obj_id) CVmObjString(subclass constructor params)
811
* The caller need not store the result of 'new'; the caller
812
* identifies the object by the obj_id value.
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.
818
void *operator new(size_t siz, VMG_ vm_obj_id_t obj_id);
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.
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,
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.
843
static int get_prop_check_argc(vm_val_t *val, uint *argc,
844
const CVmNativeCodeDesc *desc)
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
853
/* indicate a native code evaluation is required */
854
val->set_native(desc);
856
/* tell get_prop() to return without further work */
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);
864
/* everything's fine - consume the arguments */
867
/* tell get_prop() to proceed with the native evaluation */
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.
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.
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.
895
* This routine can be called ONLY during garbage collection. The
896
* heap manager is not allowed to move variable-size blocks at any
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
905
virtual void move_var_part(void *old_pos, void *new_pos)
907
/* if the block being moved is our extension, note the new location */
908
if (ext_ == (char *)old_pos)
909
ext_ = (char *)new_pos;
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.
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
970
/* property evaluation function table */
971
static int (CVmObject::*func_table_[])(VMG_ vm_obj_id_t self,
972
vm_val_t *retval, uint *argc,
974
vm_obj_id_t *source_obj);
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.
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;
992
/* ------------------------------------------------------------------------ */
994
* Each CVmObject subclass must define a singleton instance of
995
* CVmMetaclass that describes the class and instantiates objects of the
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.
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.
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.
1026
uint get_reg_idx() const { return meta_reg_idx_; }
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.
1033
virtual const char *get_meta_name() const = 0;
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.
1041
virtual vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
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:
1053
* new (vmg_ id) CVmObjXxx();
1055
virtual void create_for_image_load(VMG_ vm_obj_id_t id) = 0;
1058
* Create an instance of the metaclass with the given ID in
1059
* preparation for restoring the object from a saved state file.
1061
virtual void create_for_restore(VMG_ vm_obj_id_t id) = 0;
1064
* Call a static property of the metaclass
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;
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.
1076
virtual int get_supermeta_count(VMG0_) const { return 1; }
1077
virtual vm_obj_id_t get_supermeta(VMG_ int idx) const;
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;
1083
* set the metaclass registration table index - this can only be
1084
* done by vm_register_metaclass() during initialization
1086
void set_metaclass_reg_index(uint idx) { meta_reg_idx_ = idx; }
1088
/* most metaclasses are simply derived from Object */
1089
virtual CVmMetaclass *get_supermeta_reg() const
1090
{ return CVmObject::metaclass_reg_; }
1093
* get my class object - we'll look up our class object in the
1094
* metaclass registration table
1096
vm_obj_id_t get_class_obj(VMG0_) const;
1099
/* system metaclass registration table index */
1104
/* ------------------------------------------------------------------------ */
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
1110
class CVmMetaclassRoot: public CVmMetaclass
1113
/* get the metaclass name */
1114
const char *get_meta_name() const { return "root-object/030004"; }
1116
/* create an instance - this class cannot be instantiated */
1117
vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
1119
err_throw(VMERR_BAD_DYNAMIC_NEW);
1120
AFTER_ERR_THROW(return VM_INVALID_OBJ;)
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); }
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); }
1131
/* call a static property */
1132
int call_stat_prop(VMG_ vm_val_t *result,
1133
const uchar **pc_ptr, uint *argc,
1136
/* call the base object implementation */
1137
return CVmObject::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
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; }
1145
* determine if I'm an instance of the given object - the root
1146
* object is not a subclass of anything
1148
virtual int is_meta_instance_of(VMG_ vm_obj_id_t obj) const
1151
/* the base Object metaclass has no supermetaclass */
1152
virtual CVmMetaclass *get_supermeta_reg() const { return 0; }
1155
/* ------------------------------------------------------------------------ */
1157
* Object fixup table entry
1159
struct obj_fixup_entry
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.
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
1178
/* fixup table subarray size */
1179
#define VMOBJFIXUP_SUB_SIZE 2048
1184
CVmObjFixup(ulong entry_cnt);
1187
/* add a fixup to the table */
1188
void add_fixup(vm_obj_id_t old_id, vm_obj_id_t new_id);
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
1196
vm_obj_id_t get_new_id(VMG_ vm_obj_id_t old_id);
1198
/* fix up a DATAHOLDER value */
1199
void fix_dh(VMG_ char *dh);
1201
/* fix up an array of DATAHOLDER values */
1202
void fix_dh_array(VMG_ char *arr, size_t cnt);
1204
/* fix a portable VMB_OBJECT_ID field */
1205
void fix_vmb_obj(VMG_ char *p);
1207
/* fix an array of portable VMB_OBJECT_ID fields */
1208
void fix_vmb_obj_array(VMG_ char *p, size_t cnt);
1211
/* find an entry given the old object ID */
1212
struct obj_fixup_entry *find_entry(vm_obj_id_t old_entry);
1214
/* get an entry at the given array index */
1215
struct obj_fixup_entry *get_entry(ulong idx) const
1217
return &arr_[idx / VMOBJFIXUP_SUB_SIZE][idx % VMOBJFIXUP_SUB_SIZE];
1220
/* array of subarrays */
1221
struct obj_fixup_entry **arr_;
1223
/* number of subarray pages */
1226
/* number of entries in the array */
1229
/* number of entries used so far */
1234
/* ------------------------------------------------------------------------ */
1236
* Global variable structure. We maintain a linked list of these
1237
* structures for miscellaneous global variables required by other
1240
struct vm_globalvar_t
1242
/* the variable's value */
1245
/* next and previous pointer in linked list of global variables */
1246
vm_globalvar_t *nxt;
1247
vm_globalvar_t *prv;
1251
/* ------------------------------------------------------------------------ */
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
1257
class CVmObjGlobPage
1262
/* we're not in a list yet */
1265
/* we have no allocated entries yet */
1271
/* delete the next page */
1276
* add an entry to this page; returns true on success, false if we're
1277
* too full to add another entry
1279
int add_entry(vm_obj_id_t obj)
1281
/* if we're full, indicate failure */
1282
if (used_ == sizeof(objs_)/sizeof(objs_[0]))
1285
/* store the entry and count it */
1289
/* indicate success */
1293
/* next page in list */
1294
CVmObjGlobPage *nxt_;
1296
/* number of entries on this page that are in use */
1299
/* array of entries on this page */
1300
vm_obj_id_t objs_[30];
1303
/* ------------------------------------------------------------------------ */
1305
* Object Header Manager
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).
1313
const unsigned int VM_OBJ_PAGE_CNT_LOG2 = 12;
1314
const unsigned int VM_OBJ_PAGE_CNT = (1 << VM_OBJ_PAGE_CNT_LOG2);
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.
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.
1330
#define VMOBJ_UNREACHABLE 0x00
1331
#define VMOBJ_F_REACHABLE 0x01
1332
#define VMOBJ_REACHABLE 0x02
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.
1342
#define VMOBJ_UNFINALIZABLE 0x00
1343
#define VMOBJ_FINALIZABLE 0x01
1344
#define VMOBJ_FINALIZED 0x02
1348
* Object table page entry.
1350
struct CVmObjPageEntry
1353
* An entry is either a member of the free list, or it's a valid
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.
1367
char obj_[sizeof(CVmObject)];
1370
* if it's in the free list, we just have a pointer to the
1371
* previous element of the free list
1373
vm_obj_id_t prev_free_;
1376
/* next object in list (either the GC work queue or the free list) */
1377
vm_obj_id_t next_obj_;
1379
/* get my VM object pointer */
1380
CVmObject *get_vm_obj() const { return (CVmObject *)ptr_.obj_; }
1382
/* flag: the object is in the free list */
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)
1390
int in_root_set_ : 1;
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.
1397
uint reachable_ : 2;
1400
* Finalization state. This indicates whether an object is
1401
* unfinalizable, finalizable, or finalized.
1403
uint finalize_state_ : 2;
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.
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
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.
1428
uint transient_ : 1;
1430
/* flag: the object has requested post-load initialization */
1431
uint requested_post_load_init_ : 1;
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.
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.
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.
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.
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.
1475
uint can_have_refs_ : 1;
1476
uint can_have_weak_refs_ : 1;
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.
1483
int is_deletable() const
1486
|| (reachable_ == VMOBJ_UNREACHABLE
1487
&& finalize_state_ == VMOBJ_FINALIZED));
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.
1495
int is_in_undo() const { return in_undo_ && !transient_; }
1498
* A "saveable" object is one which must be written to a saved state
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
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.
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.
1518
int is_saveable() const
1522
&& reachable_ == VMOBJ_REACHABLE
1524
|| get_vm_obj()->is_changed_since_load()));
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
1535
int is_persistent() const
1537
return !transient_ && (in_root_set_ || is_saveable());
1541
/* ------------------------------------------------------------------------ */
1548
/* create the table */
1549
CVmObjTable() { init(); }
1555
* Destroy the table - call this rather BEFORE using operator delete
1556
* directly. After this routine is called, the object table can be
1559
void delete_obj_table(VMG0_);
1561
/* clients must call delete_obj_table() before deleting the object */
1564
/* get an object given an object ID */
1565
inline CVmObject *get_obj(vm_obj_id_t id) const
1567
/* get the page entry, and get the object from the entry */
1568
return (CVmObject *)&get_entry(id)->ptr_.obj_;
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.
1578
int enable_gc(VMG_ int enable);
1580
/* allocate a new object ID */
1581
vm_obj_id_t alloc_obj(VMG_ int in_root_set)
1583
/* allocate, using maximally conservative GC characteristics */
1584
return alloc_obj(vmg_ in_root_set, TRUE, TRUE);
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);
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.
1598
void alloc_obj_with_id(vm_obj_id_t id, int in_root_set)
1600
/* allocate with maximally conservative GC characteristics */
1601
alloc_obj_with_id(id, in_root_set, TRUE, TRUE);
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);
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.
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.
1620
void gc_full(VMG0_);
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.
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).
1641
void gc_pass_init(VMG0_);
1642
int gc_pass_continue(VMG0_) { return gc_pass_continue(vmg_ TRUE); }
1643
void gc_pass_finish(VMG0_);
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()).
1650
void run_finalizers(VMG0_);
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.
1662
int is_obj_deletable(vm_obj_id_t obj) const
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.
1669
return (obj == VM_INVALID_OBJ
1670
|| get_entry(obj)->is_deletable());
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.
1680
void mark_obj_undo_rec(VMG_ vm_obj_id_t obj,
1681
struct CVmUndoRecord *undo_rec)
1683
CVmObjPageEntry *entry;
1685
/* get the object entry */
1686
entry = get_entry(obj);
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
1694
if (entry->can_have_refs_)
1695
entry->get_vm_obj()->mark_undo_ref(vmg_ undo_rec);
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.
1704
void remove_obj_stale_undo_weak_ref(VMG_ vm_obj_id_t obj,
1705
struct CVmUndoRecord *undo_rec)
1707
CVmObjPageEntry *entry;
1709
/* get the object entry */
1710
entry = get_entry(obj);
1713
* if the object can have weak references, notify it; if not,
1714
* there's no need to do anything
1716
if (entry->can_have_weak_refs_)
1717
entry->get_vm_obj()->remove_stale_undo_weak_ref(vmg_ undo_rec);
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.
1725
int is_obj_in_undo(vm_obj_id_t obj) const
1727
return (obj != VM_INVALID_OBJ
1728
&& get_entry(obj)->is_in_undo());
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.
1737
int is_obj_deletable(const vm_val_t *val) const
1739
return (val->typ == VM_OBJ
1740
&& val->val.obj != VM_INVALID_OBJ
1741
&& is_obj_deletable(val->val.obj));
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.
1753
int is_obj_saveable(vm_obj_id_t obj) const
1755
return (obj != VM_INVALID_OBJ
1756
&& get_entry(obj)->is_saveable());
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.
1766
int is_obj_persistent(vm_obj_id_t obj) const
1768
return (obj != VM_INVALID_OBJ
1769
&& get_entry(obj)->is_persistent());
1772
/* determine if the given object is transient */
1773
int is_obj_transient(vm_obj_id_t obj) const
1775
return (obj != VM_INVALID_OBJ
1776
&& get_entry(obj)->transient_);
1779
/* mark an object as transient */
1780
void set_obj_transient(vm_obj_id_t obj) const
1782
/* set the 'transient' flag in the object */
1783
get_entry(obj)->transient_ = TRUE;
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
1790
CVmObjPageEntry *entry;
1792
/* get the object's entry */
1793
entry = get_entry(obj);
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;
1800
/* determine if the given object is in the root set */
1801
int is_obj_in_root_set(vm_obj_id_t obj) const
1803
return (obj != VM_INVALID_OBJ
1804
&& get_entry(obj)->in_root_set_);
1808
* Mark the given object as referenced, and recursively mark all of
1809
* the objects to which it refers as referenced.
1811
void mark_all_refs(vm_obj_id_t obj, uint state)
1812
{ add_to_gc_queue(obj, state); }
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.
1818
void notify_new_savept();
1821
* Apply an undo record
1823
void apply_undo(VMG_ struct CVmUndoRecord *rec);
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.
1832
* 'meta_dep_idx' is the index in the metaclass dependency table of
1833
* the metaclass to be written.
1835
void rebuild_image(VMG_ int meta_dep_idx, class CVmImageWriter *writer,
1836
class CVmConstMapper *mapper);
1839
* Scan all objects and add metaclass entries to the metaclass
1840
* dependency table for any metaclasses of which there are existing
1843
void add_metadeps_for_instances(VMG0_);
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.
1851
void rebuild_image_convert_const_data(VMG_
1852
class CVmConstMapper *const_mapper);
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.
1859
vm_obj_id_t get_max_used_obj_id() const
1860
{ return pages_used_ * VM_OBJ_PAGE_CNT; }
1862
/* determine if an object ID refers to a valid object */
1863
int is_obj_id_valid(vm_obj_id_t obj) const
1866
* the object is valid as long as it's not free, and the ID is
1867
* within the valid range
1869
return (obj != VM_INVALID_OBJ
1870
&& obj < get_max_used_obj_id()
1871
&& !get_entry(obj)->free_);
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().
1880
ulong get_obj_internal_state(vm_obj_id_t id) const
1882
/* if the object ID is invalid, return 0xF000 to so indicate */
1883
if (id >= get_max_used_obj_id())
1887
* return the state as a combination of these bits:
1890
*. Unreachable=0x00, F-Reachable=0x10, Reachable=0x20
1891
*. Unfinalizable=0x000, Finalizable=0x100, Finalized=0x200
1893
return ((get_entry(id)->free_ ? 0 : 1)
1894
+ (((ulong)get_entry(id)->reachable_) << 4)
1895
+ (((ulong)get_entry(id)->finalize_state_) << 8));
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.
1903
void reset_to_image(VMG0_);
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.
1909
void save(VMG_ class CVmFile *fp);
1912
* Restore state from a previously saved file. Returns zero on
1913
* success, or a VMERR_xxx code on failure.
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.
1919
int restore(VMG_ class CVmFile *fp, class CVmObjFixup **fixups);
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
1929
void save_image_pointer(vm_obj_id_t obj, const char *ptr, size_t siz);
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.
1939
void request_post_load_init(vm_obj_id_t obj);
1941
/* remove a post-load initialization request */
1942
void remove_post_load_init(vm_obj_id_t obj);
1944
/* invoke all registered post-load initializations */
1945
void do_all_post_load_init(VMG0_);
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
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.
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.
1970
void ensure_post_load_init(VMG_ vm_obj_id_t obj);
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.
1978
void add_to_globals(vm_obj_id_t obj);
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.
1987
* Global variables are not affected by RESTORE, RESTART, or UNDO (like
1988
* the stack, global variables are transient).
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
1995
vm_globalvar_t *create_global_var();
1996
void delete_global_var(vm_globalvar_t *var);
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);
2003
/* invoke a post-load initialization method */
2004
static void call_post_load_init(VMG_ class CVmHashEntryPLI *entry);
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);
2010
/* get the page entry for a given ID */
2011
inline CVmObjPageEntry *get_entry(vm_obj_id_t id) const
2013
return &pages_[id >> VM_OBJ_PAGE_CNT_LOG2][id & (VM_OBJ_PAGE_CNT - 1)];
2016
/* delete an entry */
2017
void delete_entry(VMG_ vm_obj_id_t id, CVmObjPageEntry *entry);
2019
/* allocate a new page of objects */
2020
void alloc_new_page();
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
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);
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.
2037
void add_to_gc_queue(vm_obj_id_t id, uint state)
2039
/* get the object header and add it to the work queue */
2040
add_to_gc_queue(id, get_entry(id), state);
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)
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).
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.
2057
if (entry->can_have_refs_ && entry->reachable_ == VMOBJ_UNREACHABLE)
2059
/* add it to the work queue */
2060
entry->next_obj_ = gc_queue_head_;
2061
gc_queue_head_ = id;
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.)
2070
entry->reachable_ = state;
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.
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.
2086
if (state > entry->reachable_)
2087
entry->reachable_ = state;
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.
2096
void add_to_finalize_queue(vm_obj_id_t id, CVmObjPageEntry *entry)
2098
/* mark the object as finalizer-reachable */
2099
entry->reachable_ = VMOBJ_F_REACHABLE;
2101
/* link it into the finalize list */
2102
entry->next_obj_ = finalize_queue_head_;
2103
finalize_queue_head_ = id;
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
2113
void alloc_check_gc(VMG_ int do_count)
2115
/* count the allocation if desired */
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_);
2125
* Run a garbage collection in preparation to allocate memory. Runs
2126
* one garbage collection pass then one finalizer pass.
2128
void gc_before_alloc(VMG0_);
2130
/* garbage collection: trace objects reachable from the stack */
2131
void gc_trace_stack(VMG0_);
2133
/* garbage collection: trace objects reachable from the imports */
2134
void gc_trace_imports(VMG0_);
2136
/* garbage collection: trace objects reachable from machine globals */
2137
void gc_trace_globals(VMG0_);
2139
/* garbage collection: trace all objects reachable from the work queue */
2140
void gc_trace_work_queue(VMG_ int trace_transient);
2142
/* continue a GC pass */
2143
int gc_pass_continue(VMG_ int trace_transient);
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
2151
void gc_set_init_conditions(vm_obj_id_t id,
2152
struct CVmObjPageEntry *entry)
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.)
2160
entry->reachable_ = VMOBJ_UNREACHABLE;
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.
2167
if (entry->in_root_set_)
2168
add_to_gc_queue(id, entry, VMOBJ_REACHABLE);
2171
/* hash table of objects requested post_load_init() service */
2172
class CVmHashTable *post_load_init_table_;
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.
2181
CVmObjGlobPage *globals_;
2183
/* head of global variable list */
2184
struct vm_globalvar_t *global_var_head_;
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.
2190
CVmObjPageEntry **pages_;
2192
/* number of page slots allocated, and the number actually used */
2196
/* first free object */
2197
vm_obj_id_t first_free_;
2199
/* first page of saved image data pointers */
2200
struct vm_image_ptr_page *image_ptr_head_;
2202
/* last page of saved image data pointers */
2203
struct vm_image_ptr_page *image_ptr_tail_;
2205
/* number of image data pointers stored on last image pointer page */
2206
size_t image_ptr_last_cnt_;
2208
/* head of garbage collection work queue */
2209
vm_obj_id_t gc_queue_head_;
2211
/* head of finalizer queue */
2212
vm_obj_id_t finalize_queue_head_;
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.
2220
uint allocs_since_gc_;
2223
* Maximum number of allocations before we run the garbage
2226
uint max_allocs_between_gc_;
2228
/* garbage collection enabled */
2229
uint gc_enabled_ : 1;
2232
/* ------------------------------------------------------------------------ */
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.
2241
vm_obj_id_t obj_id_;
2243
/* pointer to image data and length of the data */
2244
const char *image_data_ptr_;
2245
size_t image_data_len_;
2249
* Maximum number of image pointers stored per image pointer page
2251
const size_t VM_IMAGE_PTRS_PER_PAGE = 400;
2254
* A page of image pointers.
2256
struct vm_image_ptr_page
2258
/* next page in the list of pages */
2259
vm_image_ptr_page *next_;
2261
/* array of image pointers */
2262
vm_image_ptr ptrs_[VM_IMAGE_PTRS_PER_PAGE];
2266
/* ------------------------------------------------------------------------ */
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.
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.
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.
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.
2294
* Variable-size object heap interface.
2299
virtual ~CVmVarHeap() { }
2302
* Initialize. The global object table is valid at this point, and
2303
* will remain valid until after terminate() is called.
2305
virtual void init(VMG0_) = 0;
2308
* Terminate. The global object table will remain valid until after
2309
* this function returns.
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.
2315
virtual void terminate() = 0;
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.
2324
virtual void *alloc_mem(size_t siz, CVmObject *obj) = 0;
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.
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,
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.
2343
virtual void *realloc_mem(size_t siz, void *varpart,
2344
CVmObject *obj) = 0;
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.
2351
virtual void free_mem(void *varpart) = 0;
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.
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.
2368
* If any object moves during processing here, we must call the
2369
* associated CVmObject's move_var_part() routine to tell it about
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.
2376
virtual void finish_gc_pass() = 0;
2381
/* ------------------------------------------------------------------------ */
2383
* Simple variable-size object heap implementation. This implementation
2384
* uses the normal C heap manager (malloc and free) to manage the heap.
2388
* block header - we use the header to keep track of the size of the
2389
* object's data area
2391
struct CVmVarHeapMallocHdr
2393
/* size of the object */
2398
* heap implementation
2400
class CVmVarHeapMalloc: public CVmVarHeap
2403
CVmVarHeapMalloc() { }
2404
~CVmVarHeapMalloc() { }
2407
void init(VMG0_) { }
2410
void terminate() { }
2412
/* allocate memory */
2413
void *alloc_mem(size_t siz, CVmObject *)
2415
CVmVarHeapMallocHdr *hdr;
2417
/* allocate space for the block plus the header */
2418
hdr = (CVmVarHeapMallocHdr *)
2419
t3malloc(siz + sizeof(CVmVarHeapMallocHdr));
2421
/* set up the header */
2424
/* return the start of the part immediately after the header */
2425
return (void *)(hdr + 1);
2428
/* reallocate memory */
2429
void *realloc_mem(size_t siz, void *varpart, CVmObject *)
2431
CVmVarHeapMallocHdr *hdr;
2434
* get the original header, which immediately precedes the
2435
* original variable part in memory
2437
hdr = ((CVmVarHeapMallocHdr *)varpart) - 1;
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.
2444
hdr = (CVmVarHeapMallocHdr *)
2445
t3realloc(hdr, siz + sizeof(CVmVarHeapMallocHdr));
2447
/* adjust the size of the block in the header */
2450
/* return the part immediately after the header */
2451
return (void *)(hdr + 1);
2455
void free_mem(void *varpart)
2457
CVmVarHeapMallocHdr *hdr;
2460
* get the original header, which immediately precedes the
2461
* original variable part in memory
2463
hdr = ((CVmVarHeapMallocHdr *)varpart) - 1;
2466
* free the header, which is the actual memory block as far as
2467
* malloc was concerned
2473
/* removed with the removal of move_var_part() */
2476
* complete garbage collection pass - we don't have to do anything
2477
* here, since we can't move objects around to consolidate free
2480
void finish_gc_pass() { }
2486
/* ------------------------------------------------------------------------ */
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.
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
2502
struct CVmVarHeapHybrid_hdr
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
2509
class CVmVarHeapHybrid_block *block;
2513
* Hybrid heap allocator - sub-block interface. Each small-object cell
2514
* list is represented by one of these objects, as is the fallback
2517
class CVmVarHeapHybrid_block
2520
/* allocate memory */
2521
virtual struct CVmVarHeapHybrid_hdr *alloc(size_t siz) = 0;
2524
virtual void free(struct CVmVarHeapHybrid_hdr *) = 0;
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.
2532
virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
2533
class CVmObject *obj) = 0;
2537
* Malloc suballocator
2539
class CVmVarHeapHybrid_malloc: public CVmVarHeapHybrid_block
2542
/* allocate memory */
2543
virtual struct CVmVarHeapHybrid_hdr *alloc(size_t siz)
2545
CVmVarHeapHybrid_hdr *ptr;
2547
/* adjust the size to add in the required header */
2548
siz = osrndsz(siz + sizeof(CVmVarHeapHybrid_hdr));
2550
/* allocate directly via the default system heap manager */
2551
ptr = (CVmVarHeapHybrid_hdr *)t3malloc(siz);
2553
/* fill in the header */
2556
/* return the new block */
2560
/* release memory */
2561
virtual void free(CVmVarHeapHybrid_hdr *mem)
2563
/* release the memory directly to the default system heap manager */
2567
/* reallocate memory */
2568
virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
2571
CVmVarHeapHybrid_hdr *ptr;
2573
/* adjust the new size to add in the required header */
2574
siz = osrndsz(siz + sizeof(CVmVarHeapHybrid_hdr));
2576
/* reallocate the block */
2577
ptr = (CVmVarHeapHybrid_hdr *)t3realloc(mem, siz);
2579
/* fill in the header in the new block */
2582
/* return the caller-visible part of the new block */
2583
return (void *)(ptr + 1);
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
2593
class CVmVarHeapHybrid_head: public CVmVarHeapHybrid_block
2596
CVmVarHeapHybrid_head(class CVmVarHeapHybrid *mem_mgr,
2597
size_t cell_size, size_t page_count)
2599
/* remember our memory manager */
2602
/* remember our cell size and number of items per array */
2603
cell_size_ = cell_size;
2604
page_count_ = page_count;
2606
/* we have nothing in our free list yet */
2610
/* allocate an object from my pool, expanding the pool if necessary */
2611
CVmVarHeapHybrid_hdr *alloc(size_t siz);
2614
void free(CVmVarHeapHybrid_hdr *mem);
2617
virtual void *realloc(struct CVmVarHeapHybrid_hdr *mem, size_t siz,
2618
class CVmObject *obj);
2620
/* get the cell size for this cell manager */
2621
size_t get_cell_size() const { return cell_size_; }
2624
/* size of each cell in the array */
2627
/* number of items we allocate per array */
2630
/* head of the free list of cells in this array */
2633
/* our memory manager */
2634
CVmVarHeapHybrid *mem_mgr_;
2638
* Small-object array list block. We dynamically allocate these array
2639
* blocks as needed to hold blocks of a particular size.
2641
struct CVmVarHeapHybrid_array
2643
/* next array in the master list */
2644
CVmVarHeapHybrid_array *next_array;
2647
* memory for allocation (we over-allocate the structure to make
2648
* room for some number of our fixed-size cells)
2654
* heap implementation
2656
class CVmVarHeapHybrid: public CVmVarHeap
2658
friend class CVmVarHeapHybrid_head;
2662
~CVmVarHeapHybrid();
2665
void init(VMG0_) { }
2668
void terminate() { }
2670
/* allocate memory */
2671
void *alloc_mem(size_t siz, CVmObject *obj);
2673
/* reallocate memory */
2674
void *realloc_mem(size_t siz, void *varpart, CVmObject *obj);
2677
void free_mem(void *varpart);
2680
/* removed with the removal of move_var_part() */
2683
* complete garbage collection pass - we don't have to do anything
2684
* here, since we can't move objects around to consolidate free
2687
void finish_gc_pass() { }
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.
2695
CVmVarHeapHybrid_array *first_array_;
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
2702
CVmVarHeapHybrid_head **cell_heaps_;
2704
/* number of cell heap managers */
2705
size_t cell_heap_cnt_;
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
2712
CVmVarHeapHybrid_malloc *malloc_heap_;
2715
/* ------------------------------------------------------------------------ */
2717
* Memory Manager - this is the primary interface to the object memory
2723
/* create the memory manager, using a given variable-size heap */
2724
CVmMemory(VMG_ CVmVarHeap *varheap);
2726
/* delete the memory manager */
2729
/* tell the variable-size heap to disengage */
2730
varheap_->terminate();
2733
/* get the variable heap manager */
2734
CVmVarHeap *get_var_heap() const { return varheap_; }
2737
/* variable-size object heap */
2738
CVmVarHeap *varheap_;
2740
/* our constant pool manager */
2741
class CVmPool *constant_pool_;
2744
/* ------------------------------------------------------------------------ */
2746
* Allocate a new object ID
2748
inline vm_obj_id_t vm_new_id(VMG_ int in_root_set)
2750
/* ask the global object table to allocate a new ID */
2751
return G_obj_table->alloc_obj(vmg_ in_root_set);
2755
* Allocate a new object ID, setting GC characteristics
2757
inline vm_obj_id_t vm_new_id(VMG_ int in_root_set, int can_have_refs,
2758
int can_have_weak_refs)
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);
2766
* Given an object ID, get a pointer to the object
2768
inline CVmObject *vm_objp(VMG_ vm_obj_id_t id)
2770
/* ask the global object table to translate the ID */
2771
return G_obj_table->get_obj(id);
2774
#endif /* VMOBJ_H */
2777
* Register the root object class
2779
VM_REGISTER_METACLASS(CVmObject)