1 /* $Header: d:/cvsroot/tads/tads3/VMMETA.H,v 1.2 1999/05/17 02:52:28 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 vmmeta.h - metaclass dependency table 12 Function 13 The metaclass dependency table establishes the correspondence between 14 metaclass index numbers and metaclasses. The load image file contains 15 a list of the metaclasses that the program requires, identifying each 16 required metaclass with its universally unique identifier string. At 17 load time, we scan this list in the load image and create a dependency 18 table. 19 Notes 20 21 Modified 22 12/01/98 MJRoberts - Creation 23 */ 24 25 #ifndef VMMETA_H 26 #define VMMETA_H 27 28 #include <stdlib.h> 29 30 #include "t3std.h" 31 #include "vmtype.h" 32 #include "vmglob.h" 33 #include "vmobj.h" 34 35 /* ------------------------------------------------------------------------ */ 36 /* 37 * Metaclass table entry. This contains information on the metaclass at 38 * one index in the table. 39 */ 40 struct vm_meta_entry_t 41 { 42 /* the class descriptor object for the metaclass */ 43 class CVmMetaclass *meta_; 44 45 /* 46 * name of metaclass as read from image file (this is important for 47 * rewriting an image file during preinit, since it ensures that we 48 * store only the version number required by the compiled image 49 * file, not the version number actually implemented in the preinit 50 * interpreter) 51 */ 52 char *image_meta_name_; 53 54 /* 55 * the IntrinsicClass object (a CVmObjClass object) that represents 56 * this class 57 */ 58 vm_obj_id_t class_obj_; 59 60 /* 61 * Property translation list. The translation list is an array of 62 * internal function numbers, indexed by property ID. However, not 63 * all property ID's are necessarily represented in the index - 64 * instead, the index contains entries only from a minimum property 65 * ID, and only contains a specified number of entries. So, given 66 * property ID 'prop_id', we find the internal function number for 67 * the property at index (prop_id - min_prop_id) in the table. 68 * 69 * We use an unsigned short (16 bits) for each internal function 70 * number - this limits the number of functions per metaclass to 71 * 65535, which should be more than adequate while keeping memory 72 * usage within reason. 73 */ 74 vm_prop_id_t min_prop_; 75 size_t prop_xlat_cnt_; 76 unsigned short *prop_xlat_; 77 78 /* 79 * Function table. This is the reverse of the property translation 80 * list: this table gives the property ID for each of the metaclass 81 * functions. The first entry is the property of function index 1, 82 * the second entry is function index 2, and so on. 83 */ 84 vm_prop_id_t *func_xlat_; 85 size_t func_xlat_cnt_; 86 87 /* relese storage */ release_memvm_meta_entry_t88 void release_mem() 89 { 90 /* if this entry has a property table, delete it */ 91 if (prop_xlat_ != 0) 92 { 93 /* free it */ 94 t3free(prop_xlat_); 95 96 /* forget the pointer */ 97 prop_xlat_ = 0; 98 } 99 100 /* if this entry has a function translation table, delete it */ 101 if (func_xlat_ != 0) 102 { 103 /* free it */ 104 t3free(func_xlat_); 105 106 /* forget the pointer */ 107 func_xlat_ = 0; 108 } 109 110 /* relesae our stored name */ 111 lib_free_str(image_meta_name_); 112 } 113 114 /* store the metaclass name as loaded from the image file */ set_meta_namevm_meta_entry_t115 void set_meta_name(const char *nm) 116 { 117 /* allocate space and store the name */ 118 image_meta_name_ = lib_copy_str(nm); 119 } 120 121 /* 122 * Add a property to the table, given the property ID and the 123 * 1-based index of the corresponding function in the metaclass's 124 * internal function table. 125 */ add_prop_xlatvm_meta_entry_t126 void add_prop_xlat(vm_prop_id_t prop, int func_idx) 127 { 128 /* 129 * Add the translation entry from property ID to function index 130 * - note that we store this as a 1-based function table index 131 * value, because we reserve function index 0 to indicate that 132 * the property is invalid and has no function translation 133 */ 134 prop_xlat_[prop - min_prop_] = func_idx; 135 136 /* 137 * Add the translation entry from function index to property ID. 138 * Note that we must adjust the 1-based function index down one 139 * to get the index into our internal array. 140 */ 141 func_xlat_[func_idx - 1] = prop; 142 } 143 144 /* 145 * Get the translation for a given property ID. This returns zero 146 * if the property does not map to a valid function index for the 147 * metaclass, or the 1-based index of the function in the 148 * metaclass's "vtable" if the property is defined. 149 */ xlat_propvm_meta_entry_t150 unsigned short xlat_prop(vm_prop_id_t prop) const 151 { 152 /* 153 * Check to see if the property is represented in the table. If 154 * it's not within the range of properties in the table, there 155 * is no translation for the property. 156 */ 157 if (prop < min_prop_ || prop >= min_prop_ + prop_xlat_cnt_) 158 { 159 /* the property isn't in the table, so it has no translation */ 160 return 0; 161 } 162 163 /* return the function index from the table */ 164 return prop_xlat_[prop - min_prop_]; 165 } 166 167 /* 168 * Translate a function index to a property ID. The function index 169 * is given as a 1-based index, for consistency with the return 170 * value from xlat_prop(). 171 */ xlat_funcvm_meta_entry_t172 vm_prop_id_t xlat_func(unsigned short func_idx) const 173 { 174 /* 175 * if it's zero, or it's greater than the number of functions in 176 * our table, it has no property translation 177 */ 178 if (func_idx == 0 || func_idx > func_xlat_cnt_) 179 return VM_INVALID_PROP; 180 181 /* 182 * return the entry from our table for the given index, adjusted 183 * to a 1-based index value 184 */ 185 return func_xlat_[func_idx - 1]; 186 } 187 }; 188 189 190 /* ------------------------------------------------------------------------ */ 191 /* 192 * The metaclass table. One global instance of this table is generally 193 * created when the image file is loaded. 194 */ 195 class CVmMetaTable 196 { 197 public: 198 /* 199 * Create a table with a given number of initial entries. The table 200 * may be expanded in the future if necessary, but if the caller can 201 * predict the maximum number of entries required, we can 202 * preallocate the table at its final size and thus avoid the 203 * overhead and memory fragmentation of expanding the table. 204 */ 205 CVmMetaTable(size_t init_entries); 206 207 /* delete the table */ 208 ~CVmMetaTable(); 209 210 /* clear all existing entries from the table */ 211 void clear(); 212 213 /* 214 * Add an entry to the table, given the metaclass identifier (a 215 * string giving the universally unique name for the metaclass). 216 * Fills in the next available slot. Throws an error if the 217 * metaclass is not present in the system. 218 * 219 * If min_prop and max_prop are both VM_INVALID_PROP, the metaclass 220 * has no properties in the translation table. 221 */ 222 void add_entry(const char *metaclass_id, size_t func_cnt, 223 vm_prop_id_t min_prop, vm_prop_id_t max_prop); 224 225 /* add an entry to the table given the registration table index */ 226 void add_entry(const char *metaclass_id, uint idx, size_t func_cnt, 227 vm_prop_id_t min_prop, vm_prop_id_t max_prop); 228 229 /* 230 * Add an entry to the table given the registration table index, but 231 * only if the metaclass at this index isn't already defined in the 232 * dependency table; if the metaclass is already in the dependency 233 * table, this function has no effect. 234 */ 235 void add_entry_if_new(uint reg_table_idx, size_t func_cnt, 236 vm_prop_id_t min_prop, vm_prop_id_t max_prop); 237 238 /* 239 * Get the dependency table index for a metaclass, given the 240 * registration table index. If the metaclass is not present in the 241 * metaclass table, we'll return -1. 242 */ get_dependency_index(uint reg_table_idx)243 int get_dependency_index(uint reg_table_idx) const 244 { return reverse_map_[reg_table_idx]; } 245 246 /* 247 * get the depencency table entry for a metaclass, given the 248 * registration table index 249 */ get_entry_from_reg(int reg_idx)250 vm_meta_entry_t *get_entry_from_reg(int reg_idx) 251 { 252 int dep_idx; 253 254 /* translate the registration table index into a dependency index */ 255 dep_idx = get_dependency_index(reg_idx); 256 257 /* 258 * if we have a valid dependency index, return it; otherwise, 259 * return null 260 */ 261 if (dep_idx >= 0) 262 return &table_[dep_idx]; 263 else 264 return 0; 265 } 266 267 /* 268 * Given a registration table index for a metaclass and a property 269 * ID, retrieve the metaclass function vector index for the property 270 * according to the image file's property mapping for the metaclass. 271 * Returns zero if the property is not in the mapping, 1 for the 272 * first function in the vector, 2 for the second function, and so 273 * on. 274 * 275 * Note that we use the registration table index, NOT the dependency 276 * index, because this function is provided for use by the metaclass 277 * itself, which only has convenient access to its registration 278 * index. 279 */ prop_to_vector_idx(uint reg_table_idx,vm_prop_id_t prop)280 int prop_to_vector_idx(uint reg_table_idx, vm_prop_id_t prop) 281 { 282 vm_meta_entry_t *entry; 283 284 /* get the entry for the registration table index */ 285 entry = get_entry_from_reg(reg_table_idx); 286 287 /* 288 * if there's no entry for this registration index, there's 289 * obviously no metaclass function mapping for the property 290 */ 291 if (entry == 0) 292 return 0; 293 294 /* return the property translation */ 295 return entry->xlat_prop(prop); 296 } 297 298 /* get the entry at a given dependency table index */ get_entry(int idx)299 vm_meta_entry_t *get_entry(int idx) { return &table_[idx]; } 300 301 /* get the total number of entries in the table */ get_count()302 size_t get_count() const { return count_; } 303 304 /* 305 * Invoke the VM-stack-based constructor for the metaclass at the 306 * given index to create a new instance of that metaclass. Throws 307 * an error if no such entry is defined. Returns the object ID of 308 * the constructed object. 309 */ 310 vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, 311 uint idx, uint argc); 312 313 /* invoke a static property of a metaclass */ 314 int call_static_prop(VMG_ vm_val_t *result, const uchar **pc_ptr, 315 uint idx, uint *argc, vm_prop_id_t prop); 316 317 /* 318 * Create an object with the given ID and load the object from the 319 * image file. 320 */ 321 void create_from_image(VMG_ uint idx, vm_obj_id_t id, 322 const char *ptr, size_t siz); 323 324 /* 325 * create an object in preparation for loading the object from a 326 * saved state file 327 */ 328 void create_for_restore(VMG_ uint idx, vm_obj_id_t id); 329 330 /* 331 * write the dependency table to a file, for later reloading with 332 * read_from_file() 333 */ 334 void write_to_file(class CVmFile *fp); 335 336 /* 337 * Read the dependency table from a file, as previously written by 338 * write_to_file(). Returns zero on success, or an error code on 339 * failure. We will entirely clear the current table before 340 * loading, so the new table will replace the existing table. 341 */ 342 int read_from_file(class CVmFile *fp); 343 344 /* rebuild the image file (for use after preinitialization) */ 345 void rebuild_image(class CVmImageWriter *writer); 346 347 /* 348 * Create an IntrinsicClass object for each metaclass that doesn't 349 * already have an IntrinsicClass object. This ensures that every 350 * intrinsic class in use has an associated IntrinsicClass instance, 351 * even if the compiler didn't generate one. 352 */ 353 void create_intrinsic_class_instances(VMG0_); 354 355 /* forget IntrinsicClass objects we created at startup */ 356 void forget_intrinsic_class_instances(VMG0_); 357 358 private: 359 /* 360 * Ensure we have space for a given number of entries, allocating 361 * more if necessary. If we must allocate more space, we'll 362 * increase the current allocation size by at least the given 363 * increment (more if necessary to bring it up to the required 364 * size). 365 */ 366 void ensure_space(size_t entries, size_t increment); 367 368 /* the table array */ 369 vm_meta_entry_t *table_; 370 371 /* 372 * reverse dependency map - each entry in this table is the 373 * dependency table index of the metaclass at the given registration 374 * table index: 375 * 376 * reserve_map[registration_table_index] = dependency_table_index 377 * 378 * This information lets us determine if a given metaclass is in the 379 * current dependency table at all, and if so what it's index is. 380 * We store -1 in each entry that doesn't appear in the dependency 381 * table. 382 */ 383 int *reverse_map_; 384 385 /* number of entries defined in the table */ 386 size_t count_; 387 388 /* number of entries allocated for the table */ 389 size_t alloc_; 390 }; 391 392 393 #endif /* VMMETA_H */ 394