cfad47cfa3/tads3/vmtobj.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* $Header: d:/cvsroot/tads/tads3/VMTOBJ.H,v 1.2 1999/05/17 02:52:29 MJRoberts Exp $ */
2
3
/* 
4
 *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
5
 *   
6
 *   Please see the accompanying license file, LICENSE.TXT, for information
7
 *   on using and copying this software.  
8
 */
9
/*
10
Name
11
  vmtobj.h - VM TADS Object implementation
12
Function
13
  
14
Notes
15
  This implementation assumes a non-relocating memory manager, both for
16
  the fixed part (the CVmObject part) and the variable part (the
17
  "extension," located in the variable-part heap) of our objects.  In the
18
  present implementation, the memory manager satisfies this requirement, and
19
  there are no plans to change this.
20
21
  The memory manager is designed *in principal* to allow for object
22
  relocation (specifically as a means to reduce heap fragmentation), so it's
23
  not a foregone conclusion that such a thing will never be implemented.
24
  However, given the large memories of modern machines (especially relative
25
  to the size of a typical tads application), and given that recent academic
26
  research has been calling into question the conventional wisdom that heap
27
  fragmentation is actually a problem in practice, we consider the
28
  probability that we will want to implement a relocation memory manager
29
  low, and thus we feel it's better to exploit the efficiencies of using and
30
  storing direct object pointers in some places in this code.
31
Modified
32
  10/30/98 MJRoberts  - Creation
33
*/
34
35
#ifndef VMTOBJ_H
36
#define VMTOBJ_H
37
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "t3std.h"
42
#include "vmtype.h"
43
#include "vmglob.h"
44
#include "vmobj.h"
45
#include "vmundo.h"
46
47
/* forward-declare our main class */
48
class CVmObjTads;
49
50
/* ------------------------------------------------------------------------ */
51
/*
52
 *   TADS-Object image file data.  The image file state is loaded into an
53
 *   image object data block, and we set up our own internal data based on
54
 *   it at load time.  The image file data block is arranged as follows:
55
 *   
56
 *.  UINT2 superclass_count
57
 *.  UINT2 load_image_property_count
58
 *.  UINT2 flags
59
 *.  UINT4 superclass_1
60
 *.  ...
61
 *.  UINT4 superclass_N
62
 *.  UINT2 load_image_property_ID_1
63
 *.  DATAHOLDER load_image_property_value_1
64
 *.  ...
65
 *.  UINT2 load_image_property_ID_N
66
 *.  DATAHOLDER load_image_property_value_N 
67
 */  
68
69
/* superclass structure for object extension */
70
struct vm_tadsobj_sc
71
{
72
    vm_obj_id_t id;
73
    CVmObjTads *objp;
74
};
75
76
77
/*
78
 *   For our in-memory object extension, we use a structure that stores the
79
 *   object data.  We store the properties in a hash table keyed on property
80
 *   ID.  
81
 */
82
struct vm_tadsobj_hdr
83
{
84
    /* allocate */
85
    static vm_tadsobj_hdr *alloc(VMG_ class CVmObjTads *self,
86
                                 unsigned short sc_cnt,
87
                                 unsigned short prop_cnt);
88
89
    /* delete */
90
    void free_mem();
91
92
    /* reallocate an existing object to expand its property table */
93
    static vm_tadsobj_hdr *expand(VMG_ class CVmObjTads *self,
94
                                  vm_tadsobj_hdr *obj);
95
96
    /* 
97
     *   reallocate an existing object to expand its property table to the
98
     *   given minimum number of property entries 
99
     */
100
    static vm_tadsobj_hdr *expand_to(VMG_ class CVmObjTads *self,
101
                                     vm_tadsobj_hdr *obj,
102
                                     size_t new_sc_cnt, size_t min_prop_cnt);
103
104
    /* invalidate the cached inheritance path, if any */
105
    void inval_inh_path()
106
    {
107
        /* if we have an inheritance path cached, forget it */
108
        if (inh_path != 0)
109
        {
110
            /* forget the path, so that we recalculate it on demand */
111
            t3free(inh_path);
112
            inh_path = 0;
113
        }
114
    }
115
116
    /* find a property entry */
117
    inline struct vm_tadsobj_prop *find_prop_entry(uint prop);
118
119
    /* allocate a new hash entry */
120
    vm_tadsobj_prop *alloc_prop_entry(vm_prop_id_t prop,
121
                                      const vm_val_t *val,
122
                                      unsigned int flags);
123
124
    /* calculate the hash code for a property */
125
    unsigned int calc_hash(uint prop) const
126
    {
127
        /* 
128
         *   Simply take the property ID modulo the table size.  We always
129
         *   use a power of 2 as the hash table size, so the remainder is
130
         *   easy to calculate using a bit mask rather than a more expensive
131
         *   integer division. 
132
         */
133
        return (unsigned int)(prop & (hash_siz - 1));
134
    }
135
136
    /* check to see if we have the required number of free entries */
137
    int has_free_entries(size_t cnt) const
138
        { return cnt <= (size_t)(prop_entry_free - prop_entry_cnt); }
139
    
140
    /* load image object flags (a combination of VMTOBJ_OBJF_xxx values) */
141
    unsigned short li_obj_flags;
142
143
    /* internal object flags (a combination of VMTO_OBJ_xxx values) */
144
    unsigned short intern_obj_flags;
145
146
    /* 
147
     *   Inheritance search table.  We build and save the search path for
148
     *   any class with multiple superclasses, because the inheritance path
149
     *   for a class with multiple base classes can be somewhat
150
     *   time-consuming to determine.  For objects with only one base class,
151
     *   we don't bother caching a path, since the path is trivial to
152
     *   calculate in these cases.  
153
     */
154
    struct tadsobj_inh_path *inh_path;
155
156
    /* 
157
     *   Number of hash buckets, and a pointer to the bucket array.  (The
158
     *   hash bucket array is allocated as part of the same memory block as
159
     *   this structure - we suballocate it from the memory block when
160
     *   allocating the structure.)  'hash_arr[hash]' points to the head of
161
     *   a list of property entries with the given hash value.
162
     */
163
    unsigned short hash_siz;
164
    struct vm_tadsobj_prop **hash_arr;
165
166
    /*
167
     *   Pointer to our allocation array of hash buckets.  We suballocate
168
     *   this out of our allocation block.  (Note that this isn't the hash
169
     *   table; this is the pool of elements out of which hash table entries
170
     *   - not buckets, but the entries in the lists pointed to by the
171
     *   buckets - are allocated.)  
172
     */
173
    struct vm_tadsobj_prop *prop_entry_arr;
174
175
    /* total number of hash entries allocated */
176
    unsigned short prop_entry_cnt;
177
178
    /* 
179
     *   Index of next available hash entry.  Hash entries are never
180
     *   deleted, so we don't have to worry about returning entries to the
181
     *   free pool.  So, the free pool simply consists of entries from this
182
     *   index to the maximum index (prop_entry_cnt - 1).
183
     *   
184
     *   When we run out of entries, we must reallocate this entire
185
     *   structure to make room for more.  This means that reallocation is
186
     *   fairly expensive, but this is acceptable because we will always
187
     *   want to resize the hash table at the same time anyway.  We always
188
     *   resize the hash table on exhausting our current allocation size
189
     *   because we pick the hash table size based on the expected maximum
190
     *   number of entries; once we exceed that maximum, we must reconsider
191
     *   the hash table size.  
192
     */
193
    unsigned short prop_entry_free;
194
    
195
    /* 
196
     *   Number of superclasses, and the array of superclasses.  We
197
     *   overallocate the structure to make room for enough superclasses.
198
     *   (Note that this means the 'sc' field must be the last thing in the
199
     *   structure.)  
200
     */
201
    unsigned short sc_cnt;
202
    vm_tadsobj_sc sc[1];
203
};
204
205
/*
206
 *   Tads-object property entry.  Each hash table entry points to a linked
207
 *   list of these entries.  
208
 */
209
struct vm_tadsobj_prop
210
{
211
    /* my property ID */
212
    vm_prop_id_t prop;
213
214
    /* pointer to the next entry at the same hash value */
215
    vm_tadsobj_prop *nxt;
216
217
    /* flags */
218
    unsigned char flags;
219
220
    /* my value */
221
    vm_val_t val;
222
};
223
224
225
/*
226
 *   Internal object flags 
227
 */
228
229
/* from load image - object originally came from image file */
230
#define VMTO_OBJ_IMAGE   0x0001
231
232
/* modified - object has been modified since being loaded from image */
233
#define VMTO_OBJ_MOD     0x0002
234
235
236
/*
237
 *   Property entry flags 
238
 */
239
240
/* modified - this property is not from the load image file */
241
#define VMTO_PROP_MOD     0x01
242
243
/* we've stored undo for this property since the last savepoint */
244
#define VMTO_PROP_UNDO    0x02
245
246
/* ------------------------------------------------------------------------ */
247
/*
248
 *   Load Image Object Flag Values - these values are stored in the image
249
 *   file object header.  
250
 */
251
252
/* class - the object represents a class, not an instance */
253
#define VMTOBJ_OBJF_CLASS    0x0001
254
255
256
/* ------------------------------------------------------------------------ */
257
/*
258
 *   Initial empty property table size.  When we initially load an object,
259
 *   we'll allocate this many empty slots for modifiable properties. 
260
 */
261
const ushort VMTOBJ_PROP_INIT = 16;
262
263
264
/* ------------------------------------------------------------------------ */
265
/*
266
 *   TADS object interface.
267
 */
268
class CVmObjTads: public CVmObject
269
{
270
    friend class CVmMetaclassTads;
271
    friend struct tadsobj_sc_search_ctx;
272
    
273
public:
274
    /* metaclass registration object */
275
    static class CVmMetaclass *metaclass_reg_;
276
    class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
277
278
    /* am I of the given metaclass? */
279
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
280
    {
281
        /* try my own metaclass and my base class */
282
        return (meta == metaclass_reg_
283
                || CVmObject::is_of_metaclass(meta));
284
    }
285
286
    /* is the given object a TadsObject object? */
287
    static int is_tadsobj_obj(VMG_ vm_obj_id_t obj)
288
        { return vm_objp(vmg_ obj)->is_of_metaclass(metaclass_reg_); }
289
290
    /* create dynamically using stack arguments */
291
    static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
292
                                         uint argc)
293
        { return create_from_stack_intern(vmg_ pc_ptr, argc, FALSE); }
294
295
    /* 
296
     *   call a static property - we don't have any of our own, so simply
297
     *   "inherit" the base class handling 
298
     */
299
    static int call_stat_prop(VMG_ vm_val_t *result,
300
                              const uchar **pc_ptr, uint *argc,
301
                              vm_prop_id_t prop);
302
303
    /* create an object with no initial extension */
304
    static vm_obj_id_t create(VMG_ int in_root_set);
305
306
    /* 
307
     *   Create an object with a given number of superclasses, and a given
308
     *   number of property slots.  The property slots are all initially
309
     *   allocated to modified properties.  
310
     */
311
    static vm_obj_id_t create(VMG_ int in_root_set,
312
                              ushort superclass_count, ushort prop_slots);
313
314
    /* notify of deletion */
315
    void notify_delete(VMG_ int in_root_set);
316
317
    /* create an instance of this object */
318
    void create_instance(VMG_ vm_obj_id_t self,
319
                         const uchar **pc_ptr, uint argc);
320
321
    /* determine if the object has a finalizer method */
322
    virtual int has_finalizer(VMG_ vm_obj_id_t /*self*/);
323
324
    /* invoke the object's finalizer */
325
    virtual void invoke_finalizer(VMG_ vm_obj_id_t self);
326
327
    /* get the number of superclasses of this object */
328
    virtual int get_superclass_count(VMG_ vm_obj_id_t self) const
329
    {
330
        /* 
331
         *   if we have no superclass, inherit the default, since we
332
         *   inherit from the system TadsObject class; if we have our own
333
         *   superclasses, return them 
334
         */
335
        if (get_sc_count() == 0)
336
            return CVmObject::get_superclass_count(vmg_ self);
337
        else
338
            return get_sc_count();
339
    }
340
341
    /* get the nth superclass of this object */
342
    virtual vm_obj_id_t get_superclass(VMG_ vm_obj_id_t self, int idx) const
343
    {
344
        /* 
345
         *   if we have no superclass, inherit the default, since we
346
         *   inherit from the system TadsObject class; if we have our own
347
         *   superclasses, return them 
348
         */
349
        if (get_sc_count() == 0)
350
            return CVmObject::get_superclass(vmg_ self, idx);
351
        else if (idx >= get_sc_count())
352
            return VM_INVALID_OBJ;
353
        else
354
            return get_sc(idx);
355
    }
356
357
    /* determine if I'm a class object */
358
    virtual int is_class_object(VMG_ vm_obj_id_t /*self*/) const
359
        { return (get_li_obj_flags() & VMTOBJ_OBJF_CLASS) != 0; }
360
361
    /* determine if I'm an instance of the given object */
362
    int is_instance_of(VMG_ vm_obj_id_t obj);
363
364
    /* this object type provides properties */
365
    int provides_props(VMG0_) const { return TRUE; }
366
367
    /* enumerate properties */
368
    void enum_props(VMG_ vm_obj_id_t self,
369
                    void (*cb)(VMG_ void *ctx,
370
                               vm_obj_id_t self, vm_prop_id_t prop,
371
                               const vm_val_t *val),
372
                    void *cbctx);
373
374
    /* set a property */
375
    void set_prop(VMG_ class CVmUndo *undo,
376
                  vm_obj_id_t self, vm_prop_id_t prop, const vm_val_t *val);
377
378
    /* get a property */
379
    int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
380
                 vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc);
381
382
    /* inherit a property */
383
    int inh_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
384
                 vm_obj_id_t self,
385
                 vm_obj_id_t orig_target_obj,
386
                 vm_obj_id_t defining_obj,
387
                 vm_obj_id_t *source_obj, uint *argc);
388
389
    /* build my property list */
390
    void build_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval);
391
392
    /* 
393
     *   Receive notification of a new savepoint.  We keep track of
394
     *   whether or not we've saved undo information for each modifiable
395
     *   property in the current savepoint, so that we can avoid saving
396
     *   redundant undo information when repeatedly changing a property
397
     *   value (since only the first change in a given savepoint needs to
398
     *   be recorded).  When we start a new savepoint, we obviously
399
     *   haven't yet stored any undo information for the new savepoint, so
400
     *   we can simply clear all of the undo records.  
401
     */
402
    void notify_new_savept()
403
        { clear_undo_flags(); }
404
405
    /* apply undo */
406
    void apply_undo(VMG_ struct CVmUndoRecord *rec);
407
408
    /* mark a reference in an undo record */
409
    void mark_undo_ref(VMG_ struct CVmUndoRecord *undo);
410
411
    /* 
412
     *   remove stale weak references from an undo record -- we keep only
413
     *   normal strong references, so we don't need to do anything here 
414
     */
415
    void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { }
416
417
    /* mark references */
418
    void mark_refs(VMG_ uint state);
419
420
    /* 
421
     *   remove weak references - we keep only normal (strong) references,
422
     *   so this routine doesn't need to do anything 
423
     */
424
    void remove_stale_weak_refs(VMG0_) { }
425
426
    /* load from an image file */
427
    void load_from_image(VMG_ vm_obj_id_t self, const char *ptr, size_t siz);
428
429
    /* restore to image file state */
430
    void reload_from_image(VMG_ vm_obj_id_t self,
431
                           const char *ptr, size_t siz);
432
433
    /* determine if the object has been changed since it was loaded */
434
    int is_changed_since_load() const;
435
436
    /* save to a file */
437
    void save_to_file(VMG_ class CVmFile *fp);
438
439
    /* restore from a file */
440
    void restore_from_file(VMG_ vm_obj_id_t self,
441
                           class CVmFile *fp, class CVmObjFixup *fixups);
442
443
    /* rebuild for image file */
444
    virtual ulong rebuild_image(VMG_ char *buf, ulong buflen);
445
446
    /* convert to constant data */
447
    virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper,
448
                                       vm_obj_id_t self);
449
450
    /* get the nth superclass */
451
    vm_obj_id_t get_sc(uint n) const
452
        { return get_hdr()->sc[n].id; }
453
454
    /* get a pointer to the object for the nth superclass */
455
    CVmObjTads *get_sc_objp(VMG_ ushort n) const
456
    {
457
        CVmObjTads **objpp;
458
459
        /* if we haven't stored the superclass object pointer yet, do so */
460
        objpp = &get_hdr()->sc[n].objp;
461
        if (*objpp == 0)
462
            *objpp = (CVmObjTads *)vm_objp(vmg_ get_hdr()->sc[n].id);
463
464
        /* return the object pointer */
465
        return *objpp;
466
    }
467
468
    /* set the nth superclass to the given object */
469
    void set_sc(VMG_ ushort n, vm_obj_id_t obj)
470
    {
471
        get_hdr()->sc[n].id = obj;
472
        get_hdr()->sc[n].objp = (CVmObjTads *)vm_objp(vmg_ obj);
473
    }
474
475
    /* static class initialization/termination */
476
    static void class_init(VMG0_);
477
    static void class_term(VMG0_);
478
479
protected:
480
    /* create an object with no initial extension */
481
    CVmObjTads() { ext_ = 0; }
482
483
    /* 
484
     *   Create an object with a given number of superclasses, and a given
485
     *   number of property slots.  All property slots are initially
486
     *   allocated to the modifiable property list.  
487
     */
488
    CVmObjTads(VMG_ ushort superclass_count, ushort prop_count);
489
490
    /* internal handler to create from stack arguments */
491
    static vm_obj_id_t create_from_stack_intern(VMG_ const uchar **pc_ptr,
492
                                                uint argc, int is_transient);
493
494
    /* 
495
     *   internal handler to create with multiple inheritance from arguments
496
     *   passed on the stack 
497
     */
498
    static vm_obj_id_t create_from_stack_multi(VMG_ uint argc,
499
                                               int is_transient);
500
501
    /* get the load image object flags */
502
    uint get_li_obj_flags() const
503
        { return get_hdr()->li_obj_flags; }
504
505
    /* set the object flags */
506
    void set_li_obj_flags(ushort flags)
507
        { get_hdr()->li_obj_flags = flags; }
508
509
    /* 
510
     *   Allocate memory - this replaces any existing extension, so the
511
     *   caller must take care to free the extension (if one has already
512
     *   been allocated) before calling this routine.
513
     *   
514
     *   If 'from_image' is true, we're allocating memory for use with an
515
     *   object loaded from an image file, so we'll ignore the superclass
516
     *   count and leave the image_data pointer in the header unchanged.
517
     *   If 'from_image' is false, we're allocating memory for a dynamic
518
     *   object that does not have a presence in the image file, so we'll
519
     *   allocate space for the superclass list as part of the extension
520
     *   and set the image_data pointer in the header to refer the extra
521
     *   space after the modifiable property array and undo bit array.  
522
     */
523
    void alloc_mem(VMG_ ushort sc_count, ushort mod_prop_count,
524
                   int from_image);
525
526
    /* get a property from the intrinsic class */
527
    int get_prop_intrinsic(VMG_ vm_prop_id_t prop, vm_val_t *val,
528
                           vm_obj_id_t self, vm_obj_id_t *source_obj,
529
                           uint *argc);
530
531
    /*
532
     *   Search for a property, continuing a previous search from the given
533
     *   point.  defining_obj is the starting point for the search: we start
534
     *   searching in the target object's inheritance tree after
535
     *   defining_obj.  This is used to continue an inheritance search from
536
     *   a given point, as needed for the 'inherited' operator, for example.
537
     */
538
    static int search_for_prop_from(VMG_ uint prop,
539
                                    vm_val_t *val,
540
                                    vm_obj_id_t orig_target_obj,
541
                                    vm_obj_id_t *source_obj,
542
                                    vm_obj_id_t defining_obj);
543
544
    /* cache and return the inheritance search path for this object */
545
    tadsobj_inh_path *get_inh_search_path(VMG0_);
546
547
    /* load the image file properties and superclasses */
548
    void load_image_props_and_scs(VMG_ const char *ptr, size_t siz);
549
550
    /* get/set the superclass count */
551
    ushort get_sc_count() const
552
        { return get_hdr()->sc_cnt; }
553
    void set_sc_count(ushort cnt)
554
        { get_hdr()->sc_cnt = cnt; }
555
556
    /* change the superclass list */
557
    void change_superclass_list(VMG_ const char *lstp, ushort cnt);
558
559
    /* clear all undo flags */
560
    void clear_undo_flags();
561
562
563
    /* -------------------------------------------------------------------- */
564
    /*
565
     *   Low-level format management - these routines encapsulate the byte
566
     *   layout of the object in memory.  This is a bit nasty because we
567
     *   keep the object's contents in the portable image format.  
568
     */
569
570
    /* get my header */
571
    inline struct vm_tadsobj_hdr *get_hdr() const
572
        { return (vm_tadsobj_hdr *)ext_; }
573
574
    /* property evaluator - undefined property */
575
    int getp_undef(VMG_ vm_obj_id_t, vm_val_t *, uint *) { return FALSE; }
576
577
    /* property evaluator - createInstance */
578
    int getp_create_instance(VMG_ vm_obj_id_t, vm_val_t *, uint *);
579
580
    /* property evaluator - createClone */
581
    int getp_create_clone(VMG_ vm_obj_id_t, vm_val_t *, uint *);
582
583
    /* property evaluator - createTransientInstance */
584
    int getp_create_trans_instance(VMG_ vm_obj_id_t, vm_val_t *retval,
585
                                   uint *argc);
586
587
    /* property evaluator - createInstanceOf */
588
    int getp_create_instance_of(VMG_ vm_obj_id_t self,
589
                                vm_val_t *retval, uint *in_argc);
590
591
    /* property evaluator - createTransientInstanceOf */
592
    int getp_create_trans_instance_of(VMG_ vm_obj_id_t self,
593
                                      vm_val_t *retval, uint *in_argc);
594
595
    /* common handler for createInstance and createTransientInstance */
596
    int getp_create_common(VMG_ vm_obj_id_t, vm_val_t *retval, uint *argc,
597
                           int is_transient);
598
599
    /* common handler for createInstanceOf and createTransientInstanceOf */
600
    int getp_create_multi_common(VMG_ vm_obj_id_t, vm_val_t *retval,
601
                                 uint *argc, int is_transient);
602
603
    /* property evaluator - setSuperclassList */
604
    int getp_set_sc_list(VMG_ vm_obj_id_t self,
605
                         vm_val_t *retval, uint *in_argc);
606
607
    /* property evaluation function table */
608
    static int (CVmObjTads::*func_table_[])(VMG_ vm_obj_id_t self,
609
                                            vm_val_t *retval, uint *argc);
610
};
611
612
/* ------------------------------------------------------------------------ */
613
/*
614
 *   Registration table object 
615
 */
616
class CVmMetaclassTads: public CVmMetaclass
617
{
618
public:
619
    /* get the global name */
620
    const char *get_meta_name() const { return "tads-object/030004"; }
621
    
622
    /* create from image file */
623
    void create_for_image_load(VMG_ vm_obj_id_t id)
624
    {
625
        new (vmg_ id) CVmObjTads();
626
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
627
    }
628
    
629
    /* create from restoring from saved state */
630
    void create_for_restore(VMG_ vm_obj_id_t id)
631
    {
632
        new (vmg_ id) CVmObjTads();
633
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
634
    }
635
    
636
    /* create dynamically using stack arguments */
637
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
638
        { return CVmObjTads::create_from_stack(vmg_ pc_ptr, argc); }
639
    
640
    /* call a static property */
641
    int call_stat_prop(VMG_ vm_val_t *result,
642
                       const uchar **pc_ptr, uint *argc,
643
                       vm_prop_id_t prop)
644
    {
645
        return CVmObjTads::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
646
    }
647
};
648
649
/* ------------------------------------------------------------------------ */
650
/*
651
 *   Intrinsic class modifier object.  This object is for use as a modifier
652
 *   object for an intrinsic class.
653
 *   
654
 *   This is a simple subclass of the regular TADS-Object class.  The only
655
 *   difference is that we resolve properties a little differently: unlike
656
 *   regular TADS Objects, this class is essentially a mix-in, and has no
657
 *   intrinsic superclass at all.  This means that the only place we look
658
 *   for a property in get_prop is in our property list; we specifically do
659
 *   not look for an intrinsic property, nor do we look for a superclass
660
 *   that provides an intrinsic property.  
661
 */
662
class CVmObjIntClsMod: public CVmObjTads
663
{
664
    friend class CVmMetaclassIntClsMod;
665
    
666
public:
667
    static class CVmMetaclass *metaclass_reg_;
668
    class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
669
670
    /* am I of the given metaclass? */
671
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
672
    {
673
        /* try my own metaclass and my base class */
674
        return (meta == metaclass_reg_
675
                || CVmObjTads::is_of_metaclass(meta));
676
    }
677
678
    /* is the given object an intrinsic class modifier object? */
679
    static int is_intcls_mod_obj(VMG_ vm_obj_id_t obj)
680
        { return vm_objp(vmg_ obj)->is_of_metaclass(metaclass_reg_); }
681
682
    /* create dynamically using stack arguments */
683
    static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
684
                                         uint argc)
685
    {
686
        /* can't create instances of intrinsic class modifiers */
687
        err_throw(VMERR_ILLEGAL_NEW);
688
        AFTER_ERR_THROW(return VM_INVALID_OBJ;)
689
    }
690
691
    /* 
692
     *   call a static property - we don't have any of our own, so simply
693
     *   "inherit" the base class handling 
694
     */
695
    static int call_stat_prop(VMG_ vm_val_t *result,
696
                              const uchar **pc_ptr, uint *argc,
697
                              vm_prop_id_t prop)
698
    {
699
        return CVmObjTads::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
700
    }
701
702
    /* get a property */
703
    int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
704
                 vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc);
705
706
    /* inherit a property */
707
    int inh_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
708
                 vm_obj_id_t self,
709
                 vm_obj_id_t orig_target_obj,
710
                 vm_obj_id_t defining_obj,
711
                 vm_obj_id_t *source_obj, uint *argc);
712
713
    /* build my property list */
714
    void build_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval);
715
716
    /* create an object with no initial extension */
717
    CVmObjIntClsMod() { ext_ = 0; }
718
719
    /* 
720
     *   Create an object with a given number of superclasses, and a given
721
     *   number of property slots.  All property slots are initially
722
     *   allocated to the modifiable property list.  
723
     */
724
    CVmObjIntClsMod(VMG_ ushort superclass_count, ushort prop_count)
725
        : CVmObjTads(vmg_ superclass_count, prop_count) { }
726
};
727
728
/*
729
 *   Registration table object 
730
 */
731
class CVmMetaclassIntClsMod: public CVmMetaclass
732
{
733
public:
734
    /* get the global name */
735
    const char *get_meta_name() const { return "int-class-mod/030000"; }
736
737
    /* create from image file */
738
    void create_for_image_load(VMG_ vm_obj_id_t id)
739
    {
740
        new (vmg_ id) CVmObjIntClsMod();
741
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
742
    }
743
744
    /* create from restoring from saved state */
745
    void create_for_restore(VMG_ vm_obj_id_t id)
746
    {
747
        new (vmg_ id) CVmObjIntClsMod();
748
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
749
    }
750
751
    /* create dynamically using stack arguments */
752
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
753
        { return CVmObjIntClsMod::create_from_stack(vmg_ pc_ptr, argc); }
754
755
    /* call a static property */
756
    int call_stat_prop(VMG_ vm_val_t *result,
757
                       const uchar **pc_ptr, uint *argc,
758
                       vm_prop_id_t prop)
759
    {
760
        return CVmObjIntClsMod::
761
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
762
    }
763
};
764
765
#endif /* VMTOBJ_H */
766
767
/*
768
 *   Register the classes 
769
 */
770
VM_REGISTER_METACLASS(CVmObjTads)
771
VM_REGISTER_METACLASS(CVmObjIntClsMod)