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 */
create_from_stack(VMG_ const uchar ** pc_ptr,uint argc)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 return VM_INVALID_OBJ;
57 }
58
59 /*
60 * create with no initial contents
61 */
create(VMG_ int in_root_set)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 */
create_dyn(VMG_ uint meta_idx)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 */
CVmObjClass(VMG_ int in_root_set,uint meta_idx,vm_obj_id_t self)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 */
notify_delete(VMG_ int in_root_set)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 */
set_prop(VMG_ CVmUndo * undo,vm_obj_id_t self,vm_prop_id_t prop,const vm_val_t * val)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 */
build_prop_list(VMG_ vm_obj_id_t self,vm_val_t * retval)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 }
187
188 /* for gc protection, push the modifier's list */
189 G_stk->push(&mod_val);
190
191 /*
192 * Allocate a list big enough to hold the modifier's list plus our own
193 * list.
194 */
195 retval->set_obj(CVmObjList::
196 create(vmg_ FALSE, my_prop_cnt + mod_prop_cnt));
197
198 /* push the return value list for gc protection */
199 G_stk->push(retval);
200
201 /* get it as a list object, properly cast */
202 lst = (CVmObjList *)vm_objp(vmg_ retval->val.obj);
203
204 /* start the list with our own properties */
205 if (entry != 0)
206 list_class_props(vmg_ self, entry, lst, 0, FALSE);
207
208 /* copy the modifier list into the results, if there is a modifier list */
209 if (mod_prop_cnt != 0)
210 lst->cons_copy_elements(my_prop_cnt, mod_lst->get_as_list());
211
212 /* done with the gc protection */
213 G_stk->discard(2);
214 }
215
216 /*
217 * List my metaclass's properties. Returns the number of properties we
218 * find. We'll add the properties to the given list; if the list is null,
219 * we'll simply return the count.
220 */
list_class_props(VMG_ vm_obj_id_t self,vm_meta_entry_t * entry,CVmObjList * lst,size_t starting_idx,int static_only)221 size_t CVmObjClass::list_class_props(VMG_ vm_obj_id_t self,
222 vm_meta_entry_t *entry,
223 CVmObjList *lst, size_t starting_idx,
224 int static_only)
225 {
226 size_t i;
227 size_t cnt;
228 size_t idx;
229
230 /* count the valid entries */
231 for (i = 1, idx = starting_idx, cnt = 0 ;
232 i <= entry->func_xlat_cnt_ ; ++i)
233 {
234 vm_prop_id_t prop;
235 vm_val_t val;
236 vm_obj_id_t source_obj;
237
238 /* get this property */
239 prop = entry->xlat_func(i);
240
241 /*
242 * If this one's valid, check to see if it's we're interested in
243 * it. If we want only statics, include it only if it's
244 * implemented as a static method on this intrinsic class object;
245 * otherwise, include it unconditionally.
246 *
247 * To determine if the property is implemented as a static, call
248 * the property on self without an argc pointer - this is the
249 * special form of the call which merely retrieves the value of the
250 * property without evaluating it. If the property is defined on
251 * the object, and the source of the definition is self, include
252 * this one in the list of directly-defined properties.
253 */
254 if (prop != VM_INVALID_PROP
255 && (!static_only
256 || (get_prop(vmg_ prop, &val, self, &source_obj, 0)
257 && source_obj == self)))
258 {
259 /* we're interested - add it to the list if we have one */
260 if (lst != 0)
261 {
262 /* set up a value containing the property pointer */
263 val.set_propid(prop);
264
265 /* add it to the list at the next free slot */
266 lst->cons_set_element(idx, &val);
267
268 /* advance to the next slot */
269 ++idx;
270 }
271
272 /* count it */
273 ++cnt;
274 }
275 }
276
277 /* return the number of properties we found */
278 return cnt;
279 }
280
281
282 /*
283 * get a property
284 */
get_prop(VMG_ vm_prop_id_t prop,vm_val_t * val,vm_obj_id_t self,vm_obj_id_t * source_obj,uint * argc)285 int CVmObjClass::get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
286 vm_obj_id_t self, vm_obj_id_t *source_obj,
287 uint *argc)
288 {
289 vm_meta_entry_t *entry;
290
291 /*
292 * pass the property request as a static property of the metaclass
293 * with which we're associated
294 */
295 entry = get_meta_entry(vmg0_);
296 if (entry != 0 && entry->meta_->call_stat_prop(vmg_ val, 0, argc, prop))
297 {
298 /* the metaclass object handled it, so we are the definer */
299 *source_obj = self;
300 return TRUE;
301 }
302
303 /*
304 * Try handling it through the modifier object, if we have one. Note
305 * that we must search our own intrinsic superclass chain, because our
306 * own true intrinsic class is 'intrinsic class,' but we want to expose
307 * the nominal superclass hierarchy of the intrinsic class itself (for
308 * example, we want to search List->Collection->Object, not
309 * List->IntrinsicClass->Object).
310 */
311 if (get_prop_from_mod(vmg_ prop, val, self, source_obj, argc))
312 return TRUE;
313
314 /* inherit default handling */
315 return CVmObject::get_prop(vmg_ prop, val, self, source_obj, argc);
316 }
317
318 /*
319 * Get a property from an intrinsic class modifier object. Look up the
320 * property in my own modifier, and recursively in my superclass modifiers.
321 */
get_prop_from_mod(VMG_ vm_prop_id_t prop,vm_val_t * val,vm_obj_id_t self,vm_obj_id_t * source_obj,uint * argc)322 int CVmObjClass::get_prop_from_mod(VMG_ vm_prop_id_t prop, vm_val_t *val,
323 vm_obj_id_t self, vm_obj_id_t *source_obj,
324 uint *argc)
325 {
326 vm_obj_id_t sc;
327 vm_obj_id_t mod_obj;
328
329 /* if we have a modifier object, look it up in the modifier */
330 if ((mod_obj = get_mod_obj()) != VM_INVALID_OBJ
331 && vm_objp(vmg_ mod_obj)->get_prop(vmg_ prop, val, mod_obj,
332 source_obj, argc))
333 {
334 /* got it - return it from the modifier */
335 return TRUE;
336 }
337
338 /*
339 * it's not in our modifier(s); check with any intrinsic superclass
340 * modifiers
341 */
342 if (get_superclass_count(vmg_ self) != 0
343 && (sc = get_superclass(vmg_ self, 0)) != VM_INVALID_OBJ)
344 {
345 /* we have a superclass - check it recursively */
346 return ((CVmObjClass *)vm_objp(vmg_ sc))
347 ->get_prop_from_mod(vmg_ prop, val, sc, source_obj, argc);
348 }
349
350 /*
351 * we didn't find it, and we have no superclass, so there's nowhere
352 * else to look - return failure
353 */
354 return FALSE;
355 }
356
357 /*
358 * Find the intrinsic class which the given modifier object modifies. This
359 * can only be used with a modifier that modifies me or one of my
360 * superclasses.
361 */
find_mod_src_obj(VMG_ vm_obj_id_t self,vm_obj_id_t mod_obj)362 vm_obj_id_t CVmObjClass::find_mod_src_obj(VMG_ vm_obj_id_t self,
363 vm_obj_id_t mod_obj)
364 {
365 vm_obj_id_t my_mod_obj;
366 vm_obj_id_t sc;
367
368 /*
369 * Is this one of my modifier objects? It is if it's my most
370 * specialized modifier object (i.e., get_mod_obj()), or if my most
371 * specialized modifier object descends from the given object.
372 */
373 my_mod_obj = get_mod_obj();
374 if (my_mod_obj != VM_INVALID_OBJ
375 && (mod_obj == my_mod_obj
376 || vm_objp(vmg_ my_mod_obj)->is_instance_of(vmg_ mod_obj)))
377 {
378 /* it's one of mine, so I'm the intrinsic class mod_obj modifies */
379 return self;
380 }
381
382 /*
383 * It's not one of mine, so check my superclasses recursively. If we
384 * have no direct superclass, we've failed to find the object.
385 */
386 if (get_superclass_count(vmg_ self) == 0
387 || (sc = get_superclass(vmg_ self, 0)) == VM_INVALID_OBJ)
388 return VM_INVALID_OBJ;
389
390 /* ask the superclass to find the modifier */
391 return ((CVmObjClass *)vm_objp(vmg_ sc))
392 ->find_mod_src_obj(vmg_ sc, mod_obj);
393 }
394
395 /*
396 * Get my metaclass table entry
397 */
get_meta_entry(VMG0_) const398 vm_meta_entry_t *CVmObjClass::get_meta_entry(VMG0_) const
399 {
400 uint meta_idx;
401
402 /* get my metaclass table index */
403 meta_idx = get_meta_idx();
404
405 /* look up my metaclass table entry, if we have one */
406 if (meta_idx < G_meta_table->get_count())
407 return G_meta_table->get_entry(meta_idx);
408 else
409 return 0;
410 }
411
412 /*
413 * save to a file
414 */
save_to_file(VMG_ class CVmFile * fp)415 void CVmObjClass::save_to_file(VMG_ class CVmFile *fp)
416 {
417 size_t len;
418
419 /* write our data */
420 len = osrp2(ext_);
421 fp->write_bytes(ext_, len);
422 }
423
424 /*
425 * restore from a file
426 */
restore_from_file(VMG_ vm_obj_id_t self,CVmFile * fp,CVmObjFixup *)427 void CVmObjClass::restore_from_file(VMG_ vm_obj_id_t self,
428 CVmFile *fp, CVmObjFixup *)
429 {
430 size_t len;
431
432 /* read the length */
433 len = fp->read_uint2();
434
435 /* free any existing extension */
436 if (ext_ != 0)
437 {
438 G_mem->get_var_heap()->free_mem(ext_);
439 ext_ = 0;
440 }
441
442 /* allocate the space */
443 ext_ = (char *)G_mem->get_var_heap()->alloc_mem(len, this);
444
445 /* store our length */
446 vmb_put_len(ext_, len);
447
448 /*
449 * read the contents (note that we've already read the length prefix,
450 * so subtract it out of the total remaining to be read)
451 */
452 fp->read_bytes(ext_ + VMB_LEN, len - VMB_LEN);
453
454 /* register myself with the metaclass table */
455 register_meta(vmg_ self);
456 }
457
458 /* load from an image file */
load_from_image(VMG_ vm_obj_id_t self,const char * ptr,size_t siz)459 void CVmObjClass::load_from_image(VMG_ vm_obj_id_t self,
460 const char *ptr, size_t siz)
461 {
462 /* save a pointer to the image file data as our extension */
463 ext_ = (char *)ptr;
464
465 /* make sure the length is valid */
466 if (siz < 8)
467 err_throw(VMERR_INVAL_METACLASS_DATA);
468
469 /* register myself */
470 register_meta(vmg_ self);
471 }
472
473 /*
474 * reset to the initial load state
475 */
reset_to_image(VMG_ vm_obj_id_t self)476 void CVmObjClass::reset_to_image(VMG_ vm_obj_id_t self)
477 {
478 /* re-register myself for the re-load */
479 register_meta(vmg_ self);
480 }
481
482 /*
483 * Register myself with the metaclass dependency table - this establishes
484 * the association between the metaclass in the dependency table and this
485 * instance, so that the metaclass knows about the instance that
486 * represents it.
487 */
register_meta(VMG_ vm_obj_id_t self)488 void CVmObjClass::register_meta(VMG_ vm_obj_id_t self)
489 {
490 vm_meta_entry_t *entry;
491
492 /* get my metaclass table entry */
493 entry = get_meta_entry(vmg0_);
494
495 /*
496 * if we have a valid entry, store a reference to myself in the
497 * metaclass table - this will let the metaclass that we represent find
498 * us when asked for its class object
499 */
500 if (entry != 0)
501 entry->class_obj_ = self;
502 }
503
504 /*
505 * Get the number of superclasses
506 */
get_superclass_count(VMG_ vm_obj_id_t) const507 int CVmObjClass::get_superclass_count(VMG_ vm_obj_id_t) const
508 {
509 vm_meta_entry_t *entry;
510
511 /* get my metaclass table entry */
512 entry = get_meta_entry(vmg0_);
513
514 /*
515 * if we have a valid entry, ask the metaclass object to tell us the
516 * superclass count
517 */
518 if (entry != 0)
519 return entry->meta_->get_supermeta_count(vmg0_);
520 else
521 return 0;
522 }
523
524 /*
525 * Get a superclass
526 */
get_superclass(VMG_ vm_obj_id_t,int sc_idx) const527 vm_obj_id_t CVmObjClass::get_superclass(VMG_ vm_obj_id_t, int sc_idx) const
528 {
529 vm_meta_entry_t *entry;
530
531 /* get my metaclass table entry */
532 entry = get_meta_entry(vmg0_);
533
534 /*
535 * if we have a valid entry, ask the metaclass object to retrieve the
536 * superclass
537 */
538 if (entry != 0)
539 return entry->meta_->get_supermeta(vmg_ sc_idx);
540 else
541 return VM_INVALID_OBJ;
542 }
543
544 /*
545 * Determine if I'm an instance of the given object
546 */
is_instance_of(VMG_ vm_obj_id_t obj)547 int CVmObjClass::is_instance_of(VMG_ vm_obj_id_t obj)
548 {
549 vm_meta_entry_t *entry;
550
551 /* get my metaclass table entry */
552 entry = get_meta_entry(vmg0_);
553
554 /* if we have a valid entry, ask the metaclass object */
555 if (entry != 0)
556 {
557 /* ask the metaclass if it's an instance of the given object */
558 return entry->meta_->is_meta_instance_of(vmg_ obj);
559 }
560 else
561 {
562 /* not a valid metaclass - we can't make sense of this */
563 return FALSE;
564 }
565 }
566