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