| | 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 | } |