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 vm_priv.h
22  * @brief Box virtual machine private definitions.
23  */
24 
25 #ifndef _BOX_VM_PRIVATE_H
26 #  define _BOX_VM_PRIVATE_H
27 
28 #  include <stdio.h>
29 #  include <stdarg.h>
30 #  include <stdlib.h>
31 
32 #  include <box/types.h>
33 #  include <box/defaults.h>
34 #  include <box/array.h>
35 #  include <box/occupation.h>
36 #  include <box/hashtable.h>
37 #  include <box/vm.h>
38 #  include <box/vmsym.h>
39 #  include <box/vmdasm.h>
40 #  include <box/vmproc_priv.h>
41 
42 #  include <box/vmexec_priv.h>
43 
44 
45 /**
46  * Structure used in BoxOpInfo to list the input and output registers
47  * for each VM operation.
48  */
49 typedef struct {
50   char kind, /**< 'a' for explicit argument, 'r' for implicit local register */
51        type, /**< 'c':Char, 'i':Int, 'r':Real, 'p':Point, 'o':Obj */
52        num,  /**< Number of argument or register (can be 0, 1, 2) */
53        io;   /**< 'o' for output, 'i' for input, 'b' for input/output */
54 } BoxOpReg;
55 
56 /**
57  * @brief Enumeration of all the possible types of signatures for the Box VM
58  *   instructions.
59  *
60  * Different signatures mean different number and/or type of arguments.
61  */
62 typedef enum {
63   BOXOPSIGNATURE_NONE,
64   BOXOPSIGNATURE_ANY,
65   BOXOPSIGNATURE_IMM,
66   BOXOPSIGNATURE_ANY_ANY,
67   BOXOPSIGNATURE_ANY_IMM
68 } BoxOpSignature;
69 
70 /** Possible methods for disassembling a Box VM operation.
71  * Each item in the enumeration corresponds to a different method to be used
72  * for disassembling the operation.
73  */
74 typedef enum {
75   BOXOPDASM_ANY_ANY,
76   BOXOPDASM_ANY_IMM,
77   BOXOPDASM_JMP,
78   BOXOPDASM_CALL
79 } BoxOpDAsm;
80 
81 /** Typedef of struc __BoxOpInfo */
82 typedef struct BoxOpInfo_struct BoxOpInfo;
83 
84 /**
85  * @brief Structure containing detailed information about one VM operation.
86  */
87 struct BoxOpInfo_struct {
88   BoxOpId    opcode;       /**< Opcode for the operation */
89   BoxGOp     g_opcode;     /**< Generic opcode */
90   BoxOpInfo  *next;        /**< Next operation with the same generic opcode */
91   const char *name;        /**< Literal name of the opcode (a string) */
92   BoxOpSignature
93              signature;    /**< Operation kind (depends on the arguments) */
94   BoxOpDAsm  dasm;         /**< How to disassemble the operation */
95   char       arg_type,     /**< Type of the arguments */
96              num_args,     /**< Number of arguments */
97              num_inputs,   /**< Num. of input registers (explicit+implicit) */
98              num_outputs,  /**< Num. of output registers(explicit+implicit) */
99              num_regs;     /**< Num. of distinct registers involved by the
100                                 operation (this is not just in + out) */
101   BoxOpReg   *regs;        /**< Pointer to the list of input/output regs */
102   BoxVMOpExecutor
103              executor;    /**< Pointer to the function which implements
104                                the operation */
105 };
106 
107 /**
108  * Content of a BoxOpDesc object.
109  */
110 struct BoxOpDesc_struct {
111   const char         *name;    /**< Instruction name */
112   BoxUInt            numargs;  /**< Number of arguments */
113 
114   int                num_args; /**< Number of proper arguments. */
115   int                has_data; /**< Whether this instruction has attached
116                                     data. */
117   BoxTypeId          t_id;     /**< Type of the arguments (all have the
118                                     same type) */
119   BoxVMOpExecutor    execute;  /**< Per eseguire l'istruzione */
120 };
121 
122 /** Table containing info about all the VM operations */
123 typedef struct {
124   BoxOpInfo info[BOX_NUM_OPS]; /**< Table of BoxOpInfo strucs. One for each
125                                     VM operation */
126   BoxOpReg  *regs;             /**< Buffer used by the BoxOpTable.info */
127 } BoxOpTable;
128 
129 /**
130  * @brief Identifies the form of a VM instruction argument.
131  *
132  * Possible forms are local register (e.g. ri1), global register (e.g. gri1),
133  * pointer (e.g. i[ro0 + 8]) and immediate (e.g. 1.234).
134  */
135 typedef enum {
136   BOXOPARGFORM_GREG = 0, /**< Global register. */
137   BOXOPARGFORM_LREG,     /**< Local register. */
138   BOXOPARGFORM_PTR,      /**< Pointer. */
139   BOXOPARGFORM_IMM       /**< Immediate. */
140 } BoxOpArgForm;
141 
142 /** Item used in a backtrace to identify where the exception caused the
143  * particular function to exit.
144  */
145 typedef struct {
146   BoxVMCallNum call_num; /**< Call number of the function */
147   size_t       vm_pos;   /**< Position in the VM code */
148 } BoxVMTrace;
149 
150 
151 typedef struct {
152   void   *ptr; /**< Pointer to the region allocated for the registers */
153   BoxInt min,  /**< Min register number */
154          max;  /**< Max register number */
155 } BoxVMRegs;
156 
157 /**
158  * @brief Datastructure used to parse one single instruction argument.
159  */
160 typedef struct {
161   union {
162     BoxChar val_char; /**< Value for Char registers. */
163     BoxInt  val_int;  /**< Value for Int registers. */
164     BoxReal val_real; /**< Value for Real registers. */
165     BoxPtr  val_ptr;  /**< Value for Ptr registers. */
166   }         data;     /**< Data associated to the argument. */
167 } BoxOpArg;
168 
169 /**
170  * This structure contains all the data which define the status for the VM.
171  * Status is allocated by VM_Module_Execute() inside its stack.
172  */
173 struct BoxVMX_struct {
174   BoxVM       *vm;        /**< VM to execute. */
175 
176   BoxVMProcInstalled *p;  /**< Procedure which is currently been executed */
177 
178   struct {
179     unsigned int
180               error   :1, /**< Error detected */
181               exit    :1; /**< Exit current execution frame */
182   } flags;                /**< Execution flags */
183 
184   BoxInt      op_size;
185 
186   BoxVMRegs   local[NUM_TYPES], /**< Local register allocation status */
187               *global;          /**< Global register allocation status */
188 
189   BoxInt      alc[NUM_TYPES]; /**< Allocation status of local registers
190                                    (whether a 'new num_regs, num_vars'
191                                    instruction has been used) */
192 };
193 
194 /**
195  * @brief The full status of the virtual machine of Box.
196  */
197 struct BoxVM_struct {
198   BoxArr  types;           /**< Type bound to this VM. */
199   BoxHT   types_dict;      /**< Dictionaries to find type IDs the corresponding
200                               types.*/
201   struct {
202     unsigned int
203           forcelong :1,    /**< Force long form assembly. */
204           hexcode   :1,    /**< Show Hex values in disassembled code */
205           identdata :1;    /**< Add also identity info for data inserted
206                                 into the data segment */
207   }       attr;            /** Flags controlling the behaviour of the VM */
208 
209   struct {
210     unsigned int
211           globals   :1,    /**< Global regs have been allocated */
212           op_table  :1;    /**< The operation table has been built */
213 
214   }       has;             /**< State of the VM */
215 
216   BoxArr  stack,           /**< The stack for the VM object */
217           data_segment;    /**< The segment of data (strings, etc.) which is
218                                 accessible through the register gro0 */
219 
220   BoxVMRegs global[NUM_TYPES];  /**< The values of the global registers */
221 
222   BoxPtr    *box_vm_current,
223             *box_vm_arg1;
224 
225   const BoxOpDesc
226             *exec_table;    /**< Table collecting info about the instructions
227                                  which are useful for execution. */
228 
229   BoxVMProcTable
230             proc_table;     /**< Table of installed and uninstalled procs */
231 
232   BoxVMSymTable
233             sym_table;      /**< Table of referenced and defined symbols */
234 
235   BoxOpTable
236             op_table;       /**< Table describing the instructions and their
237                                  properties */
238 
239   BoxArr    backtrace;      /**< Information about error location */
240   char      *fail_msg;      /**< Failure message */
241 
242   BoxHT     id_from_desc;   /**< Hashtable containing object descriptors */
243   BoxArr    desc_from_id;   /**< Table of descriptors from allocation IDs */
244 };
245 
246 extern const size_t size_of_type[NUM_TYPES];
247 
248 /** Maximum num of arguments (implicit + explicit) that an operation
249  * can have
250  */
251 #define BOXOP_MAX_NUM_ARGS 4
252 
253 /** Build a table containing info on the Box VM operations for each of them.
254  * The table is addressable using a BoxGOp as index.
255  * This is quite an internal function.
256  */
257 void BoxOpTable_Build(BoxOpTable *ot);
258 
259 /** Destroy a BoxOpTable object created with BoxOpTable_Build */
260 void BoxOpTable_Destroy(BoxOpTable *ot);
261 
262 /** Print the given BoxOpTable to the given stream. */
263 void BoxOpTable_Print(FILE *out, BoxOpTable *ot);
264 
265 /** Get information about the specified generic VM operation. */
266 BoxOpInfo *BoxVM_Get_Op_Info(BoxVM *vm, BoxGOp g_op);
267 
268 /** Print all the signatures for a the given BoxOpInfo object. */
269 void BoxOpInfo_Print(FILE *out, BoxOpInfo *oi);
270 
271 /** (Internal) Get the execution table for the Box VM instructions. */
272 const BoxOpDesc *BoxVM_Get_Exec_Table(void);
273 
274 /** This is the type of the C functions which can be called by the VM. */
275 typedef BoxTask (*BoxVMFunc)(BoxVMX *);
276 
277 /**
278  * Initialise a BoxVM object for which space has been already allocated
279  * somehow. You'll need to use BoxVM_Finish to destroy the object.
280  * @see BoxVM_Finish, BoxVM_Create
281  */
282 BOXEXPORT BoxTask
283 BoxVM_Init(BoxVM *vm);
284 
285 /**
286  * @brief Destroy a BoxVM object initialised with BoxVM_Init().
287  * @see BoxVM_Init
288  */
289 BOXEXPORT void
290 BoxVM_Finish(BoxVM *vm);
291 
292 BOXEXPORT BoxTask
293 BoxVM_Module_Execute(BoxVM *vm, BoxVMCallNum call_num);
294 
295 /**
296  * Similar to BoxVM_Module_Execute(), but takes also pointers to child
297  * and parent. The register gro1 and gro2 are modified after this call: in
298  * particular, '*parent' is stored in gro1 and '*child' in gro2.
299  * This guarantee that the reference counting protocol is respected.
300  */
301 BOXEXPORT BoxTask
302 BoxVM_Module_Execute_With_Args(BoxVM *vm, BoxVMCallNum cn,
303                                BoxPtr *parent, BoxPtr *child);
304 
305 /**
306  * Clear the backtrace of the program.
307  */
308 void BoxVM_Backtrace_Clear(BoxVM *vm);
309 
310 /**
311  * Print on 'stream' a human redable representation of the backtrace
312  * of the program.
313  */
314 void BoxVM_Backtrace_Print(BoxVM *vm, FILE *stream);
315 
316 /** Get the parent of the current combination (this is something with type
317  * ``BoxPtr *``.
318  */
319 #  define BoxVMX_Get_Parent(vmx) ((vmx)->vm->box_vm_current)
320 
321 /** Get the child of the current combination (this is something with type
322  * ``BoxPtr *``
323  */
324 #  define BoxVMX_Get_Child(vmx) ((vmx)->vm->box_vm_arg1)
325 
326 /** Shorthand for BoxPtr_Get_Target(BoxVM_Get_Parent(vm)). */
327 #  define BoxVMX_Get_Parent_Target(vmx) \
328   (BoxPtr_Get_Target(BoxVMX_Get_Parent(vmx)))
329 
330 /** Shorthand for BoxPtr_Get_Target(BoxVM_Get_Child(vm)). */
331 #  define BoxVMX_Get_Child_Target(vmx) \
332   (BoxPtr_Get_Target(BoxVMX_Get_Child(vmx)))
333 
334 
335 /* XXX TODO: the ones below are obsolete macros, which should be removed. */
336 #  define BOX_VM_THIS_PTR(vmx, Type) ((Type *) (vmx)->vm->box_vm_current->ptr)
337 #  define BOX_VM_THIS(vmx, Type) (*BOX_VM_THIS_PTR(vmx, Type))
338 #  define BOX_VM_ARG1_PTR(vmx, Type) ((Type *) (vmx)->vm->box_vm_arg1->ptr)
339 #  define BOX_VM_ARG1(vmx, Type) (*BOX_VM_ARG1_PTR(vmx, Type))
340 #  define BOX_VM_ARG_PTR BOX_VM_ARG1_PTR
341 #  define BOX_VM_ARG BOX_VM_ARG1
342 #  define BOX_VM_SUB_PARENT_PTR(vmp, parent_t) \
343    SUBTYPE_PARENT_PTR(BOX_VM_THIS_PTR(vmp, BoxSubtype), parent_t)
344 #  define BOX_VM_SUB_PARENT(vmp, parent_t) \
345    (*BOX_VM_SUB_PARENT_PTR(vmp, parent_t))
346 #  define BOX_VM_SUB_CHILD_PTR(vmp, child_t) \
347    SUBTYPE_CHILD_PTR(BOX_VM_THIS_PTR(vmp, BoxSubtype), child_t)
348 #  define BOX_VM_SUB_CHILD(vmp, child_t) \
349    (*BOX_VM_SUB_CHILD_PTR(vmp, child_t))
350 #  define BOX_VM_SUB2_PARENT(vmp, parent_t) \
351   (*SUBTYPE_PARENT_PTR(BOX_VM_SUB_PARENT_PTR(vmp, BoxSubtype), parent_t))
352 
353 #endif /* _BOX_VM_PRIVATE_H */
354