1 /****************************************************************************
2  * Copyright (C) 2008-2012 by Matteo Franchin                               *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 /**
21  * @file vmsym.h
22  * @brief The implementation of the reference/definition list for the box VM.
23  *
24  * This file implements the mechanism to define and reference procedures,
25  * labels and other symbols needed by a Box bytecode compiled program.
26  * This mechanism is similar to the linking of the object files produced
27  * by the compilation of several C-source files. In this sense whe could
28  * say that this file implements the Box linker.
29  */
30 
31 #ifndef _BOX_VMSYM_H
32 #  define _BOX_VMSYM_H
33 
34 #  include <box/types.h>
35 #  include <box/array.h>
36 #  include <box/hashtable.h>
37 #  include <box/list.h>
38 #  include <box/vm.h>
39 
40 /**
41  * @brief An integer number used to identify a symbol.
42  */
43 typedef BoxUInt BoxVMSymID;
44 
45 /** Invalid symbol ID */
46 #define BOXVMSYMID_NONE ((BoxVMSymID) 0)
47 
48 /**
49  * @brief The table of references and definitions for the Box VM.
50  *
51  * This structure is embedded in the main VM structure VMProgram.
52  */
53 typedef struct {
54   BoxHT  syms;
55   BoxArr data,
56          defs,
57          refs,
58          dylibs;
59 } BoxVMSymTable;
60 
61 /** This is the prototype for a function which generates a piece of code
62  * which makes a reference to a symbol.
63  * Functions of this type are called when a reference is made to a symbol
64  * ('resolving=0') or when the reference is being resolved ('resolving=1').
65  * If the symbol has already been defined, then 'defined=1', otherwise
66  * 'defined=0'. 'def' and 'def_size'are respectively the pointer
67  * and the size of the definition data (which are allocated when the symbol
68  * is created with BoxVMSym_New).
69  */
70 typedef BoxTask (*BoxVMSymResolver)(BoxVM *vm, BoxVMSymID sym_id,
71                                     BoxUInt sym_type, int defined,
72                                     void *def, size_t def_size,
73                                     void *ref, size_t ref_size);
74 
75 /**
76  * @brief The details about a symbol.
77  */
78 typedef struct {
79   BoxVMSymID sym_id;    /**< The symbol ID number */
80   BoxName    name;      /**< The name of the symbol */
81   int        defined;   /**< Has a definition been given for the symbol? */
82   size_t     def_size,  /**< Size of the symbol definition data. */
83              def_addr;  /**< Address of the data in the array 'data' */
84   BoxUInt    sym_type,  /**< Type of the symbol */
85              first_ref; /**< Number of the first reference to the symbol */
86 } BoxVMSym;
87 
88 /**
89  * @brief A reference...
90  */
91 typedef struct {
92   BoxVMSymID
93           sym_id,  /**< ID-number of the referenced symbol */
94           next;     /**< ID-number of the next reference to the same symbol */
95   size_t  ref_size, /**< Size of the data containing the symbol reference */
96           ref_addr; /**< Address of the data in the array 'data' */
97   int     resolved; /**< Has the reference been resolved? */
98   BoxVMSymResolver
99           resolver; /**< Function to be called for resolution */
100 } BoxVMSymRef;
101 
102 /* Data types used by the BoxVMSym_Code_* functions */
103 typedef BoxTask (*BoxVMSymCodeGen)(BoxVM *vm, BoxVMSymID sym_id,
104                                    BoxUInt sym_type, int defined,
105                                    void *def, size_t def_size,
106                                    void *ref, size_t ref_size);
107 
108 typedef struct {
109   BoxUInt proc_num,
110           pos,
111           size;
112   BoxVMSymCodeGen
113           code_gen;
114 } BoxVMSymCodeRef;
115 
116 /** Initialize the symbol table of the program.
117  * @param vmp is the VM-program.
118  */
119 BOXEXPORT void
120 BoxVMSymTable_Init(BoxVMSymTable *t);
121 
122 /** Destroy the symbol table of the program.
123  * @param vmp is the VM-program.
124  */
125 BOXEXPORT void
126 BoxVMSymTable_Finish(BoxVMSymTable *t);
127 
128 /** Create a new symbol with name 'n' and type 'sym_type'.
129  * '*sym_id' is set with the allocated symbol number.
130  */
131 BOXEXPORT BoxVMSymID
132 BoxVMSym_New(BoxVM *vmp, BoxUInt sym_type, BoxUInt def_size);
133 
134 /**
135  * @brief Create a new symbol.
136  *
137  * @param vm The virtual machine associated to the symbol.
138  * @param sym_type The type of the symbol.
139  * @param def Pointer to the symbol data.
140  * @param def_size Size of the symbol data.
141  * @return A new symbol identifier (an integer).
142  */
143 BOXEXPORT BoxVMSymID
144 BoxVMSym_Create(BoxVM *vm, BoxUInt sym_type,
145                 const void *def, size_t def_size);
146 
147 /** Associate a name to the symbol sym_id.
148  */
149 BOXEXPORT void
150 BoxVMSym_Set_Name(BoxVM *vm, BoxVMSymID sym_id, const char *name);
151 
152 /** Get the name of the given symbol sym_id (NULL if the symbol has not
153  * a name)
154  */
155 const char *BoxVMSym_Get_Name(BoxVM *vm, BoxVMSymID sym_id);
156 
157 /**
158  * @brief Find a symbol with the given name.
159  */
160 BOXEXPORT BoxVMSymID
161 BoxVM_Find_Sym(BoxVM *vm, const char *name);
162 
163 /**
164  * @brief Get the definition data for a symbol.
165  *
166  * @param vm The virtual machine the symbol refers to.
167  * @param sym_id The symbol identifier.
168  * @return The pointer to the definion data. The caller can write the
169  *   definition data before defining the symbol. If this is what the caller
170  *   decides to do, then it should also define the symbol by passing @c NULL
171  *   as a last argument for BoxVMSym_Define() to avoid overwriting the symbol
172  *   data.
173  * @note The pointer returned by this function must be used immediately,
174  *   before adding new symbols (as data may be relocated when doing so).
175  */
176 BOXEXPORT void *
177 BoxVMSym_Get_Definition(BoxVM *vm, BoxVMSymID sym_id);
178 
179 /**
180  * @brief Define a symbol which was previously created with BoxVMSym_Create().
181  *
182  * @param vm The virtual machine the symbol refers to.
183  * @param sym_id The symbol identifier.
184  * @param def The symbol data. Use @c NULL to leave the symbol data as it
185  *   currently is (as set using BoxVMSym_Get_Definition()).
186  * @return @c BOXTASK_OK if the symbol was defined, else @c BOXTASK_FAILURE
187  *   (which typically means that a symbol was defined twice).
188  */
189 BOXEXPORT BoxTask
190 BoxVMSym_Define(BoxVM *vm, BoxVMSymID sym_id, void *def);
191 
192 /** Return whether the symbol 'sym_id' has been defined or not */
193 BOXEXPORT int
194 BoxVMSym_Is_Defined(BoxVM *vm, BoxVMSymID sym_id);
195 
196 typedef enum {
197   BOXVMSYM_AUTO,
198   BOXVMSYM_RESOLVED,
199   BOXVMSYM_UNRESOLVED,
200 } BoxVMSymStatus;
201 
202 /** Add a reference to the symbol 'sym_id'. The reference data is pointed
203  * by 'ref' and has size 'ref_size'. 'r' is the function to be called for
204  * resolving the symbol. If 'resolved' == BOXVMSYM_RESOLVED, the reference
205  * is marked as resolved, if 'resolved' == BOXVMSYM_UNRESOLVED, it is marked
206  * as unresolved. If 'resolved' == BOXVMSYM_AUTO, then it is marked as resolved
207  * only if the symbol is defined.
208  */
209 BOXEXPORT void
210 BoxVMSym_Ref(BoxVM *vm, BoxVMSymID sym_id, BoxVMSymResolver r,
211              void *ref, size_t ref_size, BoxVMSymStatus resolved);
212 
213 #if 0
214 /** Set the symbol resolver */
215 BOXEXPORT BoxTask
216 BoxVMSym_Resolver_Set(BoxVM *vm, BoxVMSymID sym_id, VMSymResolver r);
217 #endif
218 
219 /** Set *all_resolved = 1 only if there are no unresolved references */
220 void BoxVMSym_Ref_Check(BoxVM *vm, int *all_resolved);
221 
222 /** Print an error message for every unresolved reference */
223 BOXEXPORT void
224 BoxVMSym_Ref_Report(BoxVM *vm);
225 
226 /**
227  * @brief Resolve the symbol.
228  *
229  * A symbol can be resolved once it has been defined with BoxVMSym_Define().
230  * The resolution consist in iterating over all the reference to the symbol
231  * and calling the resolutor (a callback).
232  * @param vm The virtual machine the symbol refers to.
233  * @param sym_id The symbol identifier.
234  * @return Whether the operation succeeded.
235  * @note If <pp>sym_id=0</pp>, then try to resolve all the defined symbols
236  *   (undefined symbols are ignored).
237  */
238 BOXEXPORT BoxTask
239 BoxVMSym_Resolve(BoxVM *vm, BoxVMSymID sym_id);
240 
241 /**
242  * @brief Print the symbol table for the given symbol.
243  *
244  * The symbol table is a list of all the references made to the symbol. If @p
245  * sym_id is zero the references to all symbols will be printed.
246  * @param vm The virtual machine.
247  * @param out The output stream.
248  * @param sym_id The symbol identifier.
249  */
250 BOXEXPORT void
251 BoxVMSym_Table_Print(BoxVM *vm, FILE *out, BoxVMSymID sym_id);
252 
253 /**
254  * @brief Check that the type of the symbol @p sym_id is @p sym_type.
255  */
256 BOXEXPORT BoxTask
257 BoxVMSym_Check_Type(BoxVM *vm, BoxVMSymID sym_id, BoxUInt sym_type);
258 
259 /**
260  * @brief Open the given dynamic library to resolve symbols.
261  *
262  * If the file is not found then this function appends an appropriate extension
263  * (.so for linux, .dll for windows, etc.) and tries again.
264  */
265 BOXEXPORT BoxTask
266 BoxVMSym_Resolve_CLib(BoxVM *vm, const char *lib_file);
267 
268 /**
269  * @brief Resolution of functions defined in external dynamically loaded
270  *   C libraries.
271  */
272 BOXEXPORT BoxTask
273 BoxVMSym_Resolve_CLibs(BoxVM *vm, BoxList *lib_paths, BoxList *libs);
274 
275 /**
276  * This function calls the function given as argument BoxVMSym_Code_Ref()
277  * to assemble a piece of VM-code which makes reference to the symbol
278  * @p sym_id. The reference will be resolved calling again @p code_gen
279  * once the symbol has been defined.
280  * The function @p code_gen assembles parametrically a piece of VM byte-code.
281  */
282 BOXEXPORT BoxTask
283 BoxVMSym_Code_Ref(BoxVM *vm, BoxVMSymID sym_id, BoxVMSymCodeGen code_gen,
284                   void *ref, size_t ref_size);
285 
286 #  define BoxVMSym_Code_New BoxVMSym_New
287 #  define BoxVMSym_Code_Def BoxVMSym_Def
288 
289 #  define BoxVMSym_Resolve_All(vm) \
290   BoxVMSym_Resolve((vm), 0)
291 
292 #endif /* _BOX_VMSYM_H */
293