cfad47cfa3/tads3/vmintcls.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header$";
4
#endif
5
6
/* 
7
 *   Copyright (c) 2000, 2002 Michael J. Roberts.  All Rights Reserved.
8
 *   
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
10
 *   on using and copying this software.  
11
 */
12
/*
13
Name
14
  vmintcls.cpp - T3 metaclass - intrinsic class
15
Function
16
  
17
Notes
18
  
19
Modified
20
  03/08/00 MJRoberts  - Creation
21
*/
22
23
#include <stdlib.h>
24
#include <assert.h>
25
26
#include "vmtype.h"
27
#include "vmobj.h"
28
#include "vmglob.h"
29
#include "vmintcls.h"
30
#include "vmmeta.h"
31
#include "vmfile.h"
32
#include "vmlst.h"
33
#include "vmstack.h"
34
#include "vmtobj.h"
35
36
37
/* ------------------------------------------------------------------------ */
38
/*
39
 *   statics 
40
 */
41
42
/* metaclass registration object */
43
static CVmMetaclassClass metaclass_reg_obj;
44
CVmMetaclass *CVmObjClass::metaclass_reg_ = &metaclass_reg_obj;
45
46
47
/* ------------------------------------------------------------------------ */
48
/* 
49
 *   create dynamically using stack arguments 
50
 */
51
vm_obj_id_t CVmObjClass::create_from_stack(VMG_ const uchar **pc_ptr,
52
                                           uint argc)
53
{
54
    /* it is illegal to create this type of object dynamically */
55
    err_throw(VMERR_ILLEGAL_NEW);
56
    AFTER_ERR_THROW(return VM_INVALID_OBJ;)
57
}
58
59
/* 
60
 *   create with no initial contents 
61
 */
62
vm_obj_id_t CVmObjClass::create(VMG_ int in_root_set)
63
{
64
    vm_obj_id_t id = vm_new_id(vmg_ in_root_set, FALSE, FALSE);
65
    new (vmg_ id) CVmObjClass();
66
    return id;
67
}
68
69
/*
70
 *   create with a given dependency index 
71
 */
72
vm_obj_id_t CVmObjClass::create_dyn(VMG_ uint meta_idx)
73
{
74
    vm_obj_id_t id = vm_new_id(vmg_ FALSE, FALSE, FALSE);
75
    new (vmg_ id) CVmObjClass(vmg_ FALSE, meta_idx, id);
76
    return id;
77
}
78
79
/*
80
 *   create with a given dependency index 
81
 */
82
CVmObjClass::CVmObjClass(VMG_ int in_root_set, uint meta_idx,
83
                         vm_obj_id_t self)
84
{
85
    /* calls of this form can't come from the image file */
86
    assert(!in_root_set);
87
88
    /* allocate the extension */
89
    ext_ = (char *)G_mem->get_var_heap()->alloc_mem(8, this);
90
91
    /* set up the extension - write the length and dependency index */
92
    oswp2(ext_, 8);
93
    oswp2(ext_ + 2, meta_idx);
94
    oswp4(ext_ + 4, VM_INVALID_OBJ);
95
96
    /* register myself with the metaclass table */
97
    register_meta(vmg_ self);
98
}
99
100
/* 
101
 *   notify of deletion 
102
 */
103
void CVmObjClass::notify_delete(VMG_ int in_root_set)
104
{
105
    /* free our extension */
106
    if (ext_ != 0 && !in_root_set)
107
        G_mem->get_var_heap()->free_mem(ext_);
108
}
109
110
/* set a property */
111
void CVmObjClass::set_prop(VMG_ CVmUndo *undo,
112
                           vm_obj_id_t self, vm_prop_id_t prop,
113
                           const vm_val_t *val)
114
{
115
    vm_obj_id_t mod_obj;
116
    
117
    /* if I have a modifier object, pass the setprop to the modifier */
118
    if ((mod_obj = get_mod_obj()) != VM_INVALID_OBJ)
119
    {
120
        /* set the property in the modifier object */
121
        vm_objp(vmg_ mod_obj)->set_prop(vmg_ undo, mod_obj, prop, val);
122
    }
123
    else
124
    {
125
        /* if we don't have a modifier, we can't set the property */
126
        err_throw(VMERR_INVALID_SETPROP);
127
    }
128
}
129
130
/*
131
 *   Get a list of our properties 
132
 */
133
void CVmObjClass::build_prop_list(VMG_ vm_obj_id_t self, vm_val_t *retval)
134
{
135
    vm_obj_id_t mod_obj;
136
    vm_meta_entry_t *entry;
137
    size_t my_prop_cnt;
138
    size_t mod_prop_cnt;
139
    vm_val_t mod_val;
140
    CVmObjList *lst;
141
    CVmObjList *mod_lst;
142
143
    /* presume we won't find any static properties of our own */
144
    my_prop_cnt = 0;
145
146
    /* get my metaclass table entry */
147
    entry = get_meta_entry(vmg0_);
148
149
    /* if we have an entry, count the properties */
150
    if (entry != 0)
151
        my_prop_cnt = list_class_props(vmg_ self, entry, 0, 0, FALSE);
152
153
    /* if we have a modifier object, get its property list */
154
    if ((mod_obj = get_mod_obj()) != VM_INVALID_OBJ)
155
    {
156
        /* get the modifier's property list - we'll add it to our own */
157
        vm_objp(vmg_ mod_obj)->build_prop_list(vmg_ self, &mod_val);
158
159
        /* get the result as a list object, properly cast */
160
        mod_lst = (CVmObjList *)vm_objp(vmg_ mod_val.val.obj);
161
162
        /*
163
         *   As an optimization, if we don't have any properties of our own
164
         *   to add to the modifier list, just return the modifier list
165
         *   directly (thus avoiding unnecessarily creating another copy of
166
         *   the list with no changes).
167
         */
168
        if (my_prop_cnt == 0)
169
        {
170
            /* the modifier list is the entire return value */
171
            *retval = mod_val;
172
            return;
173
        }
174
175
        /* get the size of the modifier list */
176
        mod_prop_cnt = vmb_get_len(mod_lst->get_as_list());
177
    }
178
    else
179
    {
180
        /* 
181
         *   we have no modifier object - for the result list, we simply
182
         *   need our own list, so set the modifier list to nil 
183
         */
184
        mod_val.set_nil();
185
        mod_prop_cnt = 0;
186
        mod_lst = 0;
187
    }
188
189
    /* for gc protection, push the modifier's list */
190
    G_stk->push(&mod_val);
191
192
    /*
193
     *   Allocate a list big enough to hold the modifier's list plus our own
194
     *   list.  
195
     */
196
    retval->set_obj(CVmObjList::
197
                    create(vmg_ FALSE, my_prop_cnt + mod_prop_cnt));
198
199
    /* push the return value list for gc protection */
200
    G_stk->push(retval);
201
202
    /* get it as a list object, properly cast */
203
    lst = (CVmObjList *)vm_objp(vmg_ retval->val.obj);
204
205
    /* start the list with our own properties */
206
    if (entry != 0)
207
        list_class_props(vmg_ self, entry, lst, 0, FALSE);
208
209
    /* copy the modifier list into the results, if there is a modifier list */
210
    if (mod_prop_cnt != 0)
211
        lst->cons_copy_elements(my_prop_cnt, mod_lst->get_as_list());
212
213
    /* done with the gc protection */
214
    G_stk->discard(2);
215
}
216
217
/*
218
 *   List my metaclass's properties.  Returns the number of properties we
219
 *   find.  We'll add the properties to the given list; if the list is null,
220
 *   we'll simply return the count.  
221
 */
222
size_t CVmObjClass::list_class_props(VMG_ vm_obj_id_t self,
223
                                      vm_meta_entry_t *entry,
224
                                      CVmObjList *lst, size_t starting_idx,
225
                                      int static_only)
226
{
227
    ushort i;
228
    size_t cnt;
229
    size_t idx;
230
    
231
    /* count the valid entries */
232
    for (i = 1, idx = starting_idx, cnt = 0 ;
233
         i <= entry->func_xlat_cnt_ ; ++i)
234
    {
235
        vm_prop_id_t prop;
236
        vm_val_t val;
237
        vm_obj_id_t source_obj;
238
239
        /* get this property */
240
        prop = entry->xlat_func(i);
241
        
242
        /* 
243
         *   If this one's valid, check to see if it's we're interested in
244
         *   it.  If we want only statics, include it only if it's
245
         *   implemented as a static method on this intrinsic class object;
246
         *   otherwise, include it unconditionally.
247
         *   
248
         *   To determine if the property is implemented as a static, call
249
         *   the property on self without an argc pointer - this is the
250
         *   special form of the call which merely retrieves the value of the
251
         *   property without evaluating it.  If the property is defined on
252
         *   the object, and the source of the definition is self, include
253
         *   this one in the list of directly-defined properties.  
254
         */
255
        if (prop != VM_INVALID_PROP
256
            && (!static_only
257
                || (get_prop(vmg_ prop, &val, self, &source_obj, 0)
258
                    && source_obj == self)))
259
        {
260
            /* we're interested - add it to the list if we have one */
261
            if (lst != 0)
262
            {
263
                /* set up a value containing the property pointer */
264
                val.set_propid(prop);
265
266
                /* add it to the list at the next free slot */
267
                lst->cons_set_element(idx, &val);
268
269
                /* advance to the next slot */
270
                ++idx;
271
            }
272
273
            /* count it */
274
            ++cnt;
275
        }
276
    }
277
278
    /* return the number of properties we found */
279
    return cnt;
280
}
281
282
283
/* 
284
 *   get a property 
285
 */
286
int CVmObjClass::get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
287
                          vm_obj_id_t self, vm_obj_id_t *source_obj,
288
                          uint *argc)
289
{
290
    vm_meta_entry_t *entry;
291
292
    /* 
293
     *   pass the property request as a static property of the metaclass
294
     *   with which we're associated 
295
     */
296
    entry = get_meta_entry(vmg0_);
297
    if (entry != 0 && entry->meta_->call_stat_prop(vmg_ val, 0, argc, prop))
298
    {
299
        /* the metaclass object handled it, so we are the definer */
300
        *source_obj = self;
301
        return TRUE;
302
    }
303
304
    /* 
305
     *   Try handling it through the modifier object, if we have one.  Note
306
     *   that we must search our own intrinsic superclass chain, because our
307
     *   own true intrinsic class is 'intrinsic class,' but we want to expose
308
     *   the nominal superclass hierarchy of the intrinsic class itself (for
309
     *   example, we want to search List->Collection->Object, not
310
     *   List->IntrinsicClass->Object).  
311
     */
312
    if (get_prop_from_mod(vmg_ prop, val, self, source_obj, argc))
313
        return TRUE;
314
315
    /* inherit default handling */
316
    return CVmObject::get_prop(vmg_ prop, val, self, source_obj, argc);
317
}
318
319
/*
320
 *   Get a property from an intrinsic class modifier object.  Look up the
321
 *   property in my own modifier, and recursively in my superclass modifiers.
322
 */
323
int CVmObjClass::get_prop_from_mod(VMG_ vm_prop_id_t prop, vm_val_t *val,
324
                                   vm_obj_id_t self, vm_obj_id_t *source_obj,
325
                                   uint *argc)
326
{
327
    vm_obj_id_t sc;
328
    vm_obj_id_t mod_obj;
329
330
    /* if we have a modifier object, look it up in the modifier */
331
    if ((mod_obj = get_mod_obj()) != VM_INVALID_OBJ
332
        && vm_objp(vmg_ mod_obj)->get_prop(vmg_ prop, val, mod_obj,
333
                                           source_obj, argc))
334
    {
335
        /* got it - return it from the modifier */
336
        return TRUE;
337
    }
338
339
    /* 
340
     *   it's not in our modifier(s); check with any intrinsic superclass
341
     *   modifiers 
342
     */
343
    if (get_superclass_count(vmg_ self) != 0
344
        && (sc = get_superclass(vmg_ self, 0)) != VM_INVALID_OBJ)
345
    {
346
        /* we have a superclass - check it recursively */
347
        return ((CVmObjClass *)vm_objp(vmg_ sc))
348
            ->get_prop_from_mod(vmg_ prop, val, sc, source_obj, argc);
349
    }
350
351
    /* 
352
     *   we didn't find it, and we have no superclass, so there's nowhere
353
     *   else to look - return failure 
354
     */
355
    return FALSE;
356
}
357
358
/*
359
 *   Find the intrinsic class which the given modifier object modifies.  This
360
 *   can only be used with a modifier that modifies me or one of my
361
 *   superclasses.
362
 */
363
vm_obj_id_t CVmObjClass::find_mod_src_obj(VMG_ vm_obj_id_t self,
364
                                          vm_obj_id_t mod_obj)
365
{
366
    vm_obj_id_t my_mod_obj;
367
    vm_obj_id_t sc;
368
    
369
    /* 
370
     *   Is this one of my modifier objects?  It is if it's my most
371
     *   specialized modifier object (i.e., get_mod_obj()), or if my most
372
     *   specialized modifier object descends from the given object. 
373
     */
374
    my_mod_obj = get_mod_obj();
375
    if (my_mod_obj != VM_INVALID_OBJ
376
        && (mod_obj == my_mod_obj
377
            || vm_objp(vmg_ my_mod_obj)->is_instance_of(vmg_ mod_obj)))
378
    {
379
        /* it's one of mine, so I'm the intrinsic class mod_obj modifies */
380
        return self;
381
    }
382
383
    /* 
384
     *   It's not one of mine, so check my superclasses recursively.  If we
385
     *   have no direct superclass, we've failed to find the object.  
386
     */
387
    if (get_superclass_count(vmg_ self) == 0
388
        || (sc = get_superclass(vmg_ self, 0)) == VM_INVALID_OBJ)
389
        return VM_INVALID_OBJ;
390
    
391
    /* ask the superclass to find the modifier */
392
    return ((CVmObjClass *)vm_objp(vmg_ sc))
393
        ->find_mod_src_obj(vmg_ sc, mod_obj);
394
}
395
396
/*
397
 *   Get my metaclass table entry 
398
 */
399
vm_meta_entry_t *CVmObjClass::get_meta_entry(VMG0_) const
400
{
401
    uint meta_idx;
402
403
    /* get my metaclass table index */
404
    meta_idx = get_meta_idx();
405
    
406
    /* look up my metaclass table entry, if we have one */
407
    if (meta_idx < G_meta_table->get_count())
408
        return G_meta_table->get_entry(meta_idx);
409
    else
410
        return 0;
411
}
412
413
/* 
414
 *   save to a file 
415
 */
416
void CVmObjClass::save_to_file(VMG_ class CVmFile *fp)
417
{
418
    size_t len;
419
    
420
    /* write our data */
421
    len = osrp2(ext_);
422
    fp->write_bytes(ext_, len);
423
}
424
425
/* 
426
 *   restore from a file 
427
 */
428
void CVmObjClass::restore_from_file(VMG_ vm_obj_id_t self,
429
                                    CVmFile *fp, CVmObjFixup *)
430
{
431
    size_t len;
432
433
    /* read the length */
434
    len = fp->read_uint2();
435
436
    /* free any existing extension */
437
    if (ext_ != 0)
438
    {
439
        G_mem->get_var_heap()->free_mem(ext_);
440
        ext_ = 0;
441
    }
442
443
    /* allocate the space */
444
    ext_ = (char *)G_mem->get_var_heap()->alloc_mem(len, this);
445
446
    /* store our length */
447
    vmb_put_len(ext_, len);
448
449
    /* 
450
     *   read the contents (note that we've already read the length prefix,
451
     *   so subtract it out of the total remaining to be read) 
452
     */
453
    fp->read_bytes(ext_ + VMB_LEN, len - VMB_LEN);
454
455
    /* register myself with the metaclass table */
456
    register_meta(vmg_ self);
457
}
458
459
/* load from an image file */
460
void CVmObjClass::load_from_image(VMG_ vm_obj_id_t self,
461
                                  const char *ptr, size_t siz)
462
{
463
    /* save a pointer to the image file data as our extension */
464
    ext_ = (char *)ptr;
465
466
    /* make sure the length is valid */
467
    if (siz < 8)
468
        err_throw(VMERR_INVAL_METACLASS_DATA);
469
470
    /* register myself */
471
    register_meta(vmg_ self);
472
}
473
474
/* 
475
 *   reset to the initial load state 
476
 */
477
void CVmObjClass::reset_to_image(VMG_ vm_obj_id_t self)
478
{
479
    /* re-register myself for the re-load */
480
    register_meta(vmg_ self);
481
}
482
483
/*
484
 *   Register myself with the metaclass dependency table - this establishes
485
 *   the association between the metaclass in the dependency table and this
486
 *   instance, so that the metaclass knows about the instance that
487
 *   represents it.  
488
 */
489
void CVmObjClass::register_meta(VMG_ vm_obj_id_t self)
490
{
491
    vm_meta_entry_t *entry;
492
493
    /* get my metaclass table entry */
494
    entry = get_meta_entry(vmg0_);
495
496
    /* 
497
     *   if we have a valid entry, store a reference to myself in the
498
     *   metaclass table - this will let the metaclass that we represent find
499
     *   us when asked for its class object 
500
     */
501
    if (entry != 0)
502
        entry->class_obj_ = self;
503
}
504
505
/*
506
 *   Get the number of superclasses 
507
 */
508
int CVmObjClass::get_superclass_count(VMG_ vm_obj_id_t) const
509
{
510
    vm_meta_entry_t *entry;
511
512
    /* get my metaclass table entry */
513
    entry = get_meta_entry(vmg0_);
514
515
    /* 
516
     *   if we have a valid entry, ask the metaclass object to tell us the
517
     *   superclass count 
518
     */
519
    if (entry != 0)
520
        return entry->meta_->get_supermeta_count(vmg0_);
521
    else
522
        return 0;
523
}
524
525
/*
526
 *   Get a superclass 
527
 */
528
vm_obj_id_t CVmObjClass::get_superclass(VMG_ vm_obj_id_t, int sc_idx) const
529
{
530
    vm_meta_entry_t *entry;
531
532
    /* get my metaclass table entry */
533
    entry = get_meta_entry(vmg0_);
534
535
    /* 
536
     *   if we have a valid entry, ask the metaclass object to retrieve the
537
     *   superclass 
538
     */
539
    if (entry != 0)
540
        return entry->meta_->get_supermeta(vmg_ sc_idx);
541
    else
542
        return VM_INVALID_OBJ;
543
}
544
545
/*
546
 *   Determine if I'm an instance of the given object 
547
 */
548
int CVmObjClass::is_instance_of(VMG_ vm_obj_id_t obj)
549
{
550
    vm_meta_entry_t *entry;
551
552
    /* get my metaclass table entry */
553
    entry = get_meta_entry(vmg0_);
554
555
    /* if we have a valid entry, ask the metaclass object */
556
    if (entry != 0)
557
    {
558
        /* ask the metaclass if it's an instance of the given object */
559
        return entry->meta_->is_meta_instance_of(vmg_ obj);
560
    }
561
    else
562
    {
563
        /* not a valid metaclass - we can't make sense of this */
564
        return FALSE;
565
    }
566
}