1 /****************************************************************************
2  * Copyright (C) 2010-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.h
22  * @brief Box virtual machine public API.
23  */
24 
25 #ifndef _BOX_VM_H
26 #  define _BOX_VM_H
27 
28 #  include <stdio.h>
29 #  include <stdlib.h>
30 #  include <stdarg.h>
31 #  include <stdint.h>
32 
33 #  include <box/types.h>
34 #  include <box/srcpos.h>
35 
36 /**
37  * @brief A virtual machine executor.
38  *
39  * This is an object which can be used to execute code from a virtual machine.
40  */
41 typedef struct BoxVMX_struct BoxVMX;
42 
43 /**
44  * When a procedure is created, an ID (an integer number) is assigned to it.
45  * #BoxVMProcID is the type of such a thing.
46  */
47 typedef unsigned int BoxVMProcID;
48 
49 /**
50  * Value for #BoxVMProcID which indicates missing VM procedure (it can be
51  * returned by BoxVM_Proc_Get_ID(), for example).
52  */
53 #define BOXVMPROCID_NONE (0)
54 
55 /**
56  * @brief Procedure implementation kind.
57  */
58 typedef enum {
59   BOXVMPROCKIND_UNDEFINED, /**< Procedure not defined (nor reserved). */
60   BOXVMPROCKIND_RESERVED,  /**< Procedure reserved, but not defined. */
61   BOXVMPROCKIND_VM_CODE,   /**< Procedure defined as VM code. */
62   BOXVMPROCKIND_FOREIGN,   /**< Procedure defined as a foreign callable. */
63   BOXVMPROCKIND_C_CODE     /**< Procedure defined as a foreign callable. */
64 } BoxVMProcKind;
65 
66 
67 /** When a procedure is installed a "call number" X is associated to it,
68  * so that it can be called with "call X". BoxVMCallNum is the type for such
69  * a number.
70  */
71 typedef BoxUInt BoxVMCallNum;
72 
73 /** Macro denoting invalid BoxVMCallNum. */
74 #define BOXVMCALLNUM_NONE ((BoxVMCallNum) 0)
75 
76 /** This is the structure used to store the bytecode representation
77  * of a procedure
78  */
79 typedef struct {
80   struct {
81     unsigned int   error   :1;
82     unsigned int   inhibit :1;
83   }              status;    /**< Settings controlling the assembler */
84   BoxSrcPosTable pos_table; /**< Info about the corresponding source files */
85   BoxArr         code;      /**< Array which contains effectively the code */
86 } BoxVMProc;
87 
88 /**
89  * This structure describes an installed procedure
90  * (a procedure, whose call-number has been defined.
91  * The call number is the one used to call the procedure
92  * in the call instruction).
93  */
94 typedef struct BoxVMProcInstalled_struct BoxVMProcInstalled;
95 
96 /**
97  * @brief The table of installed and uninstalled procedures.
98  *
99  * This structure is embedded in the main VM structure BoxVM.
100  */
101 typedef struct BoxVMProcTable_struct BoxVMProcTable;
102 
103 /** A virtual machine object, containing the code to be executed.
104  * A BoxVM object can be used to construct a VM executor, BoxVMX, which can
105  * execute the code contained in the BoxVM object.
106  */
107 typedef struct BoxVM_struct BoxVM;
108 
109 /* Data type used to write/read binary codes for the instructions */
110 typedef unsigned char BoxVMByte;
111 
112 typedef char BoxVMSByte;
113 
114 typedef uint32_t BoxVMWord;
115 
116 
117 #  define BoxVMWord_Fmt "%8.8lx"
118 
119 /** The opcodes for the operations (instructions) understandable by the Box
120  * virtual machine.
121  * NOTE: the order of the enumeration matters! It corresponds to the order
122  *   in the table vm_instr_desc_table[]
123  */
124 typedef enum {
125   BOXOP_CALL_I=0, BOXOP_CALL_Iimm,
126   BOXOP_NEWC_II, BOXOP_NEWI_II, BOXOP_NEWR_II, BOXOP_NEWP_II, BOXOP_NEWO_II,
127   BOXOP_MOV_Cimm, BOXOP_MOV_Iimm, BOXOP_MOV_Rimm, BOXOP_MOV_Pimm,
128   BOXOP_MOV_CC, BOXOP_MOV_II, BOXOP_MOV_RR, BOXOP_MOV_PP, BOXOP_MOV_OO,
129   BOXOP_BNOT_I, BOXOP_BAND_II, BOXOP_BXOR_II, BOXOP_BOR_II,
130   BOXOP_SHL_II, BOXOP_SHR_II,
131   BOXOP_INC_I, BOXOP_INC_R, BOXOP_DEC_I, BOXOP_DEC_R,
132   BOXOP_POW_II, BOXOP_POW_RR,
133   BOXOP_ADD_II, BOXOP_ADD_RR, BOXOP_ADD_PP, BOXOP_ADD_OO,
134   BOXOP_SUB_II, BOXOP_SUB_RR, BOXOP_SUB_PP,
135   BOXOP_MUL_II, BOXOP_MUL_RR, BOXOP_DIV_II, BOXOP_DIV_RR, BOXOP_REM_II,
136   BOXOP_NEG_I, BOXOP_NEG_R, BOXOP_NEG_P, BOXOP_PMULR_P, BOXOP_PDIVR_P,
137   BOXOP_EQ_II, BOXOP_EQ_RR, BOXOP_EQ_PP, BOXOP_EQ_OO,
138   BOXOP_NE_II, BOXOP_NE_RR, BOXOP_NE_PP, BOXOP_NE_OO,
139   BOXOP_LT_II, BOXOP_LT_RR, BOXOP_LE_II, BOXOP_LE_RR,
140   BOXOP_GT_II, BOXOP_GT_RR, BOXOP_GE_II, BOXOP_GE_RR,
141   BOXOP_LNOT_I, BOXOP_LAND_II, BOXOP_LOR_II,
142   BOXOP_REAL_C, BOXOP_REAL_I, BOXOP_INT_C, BOXOP_INT_R,
143   BOXOP_POINT_II, BOXOP_POINT_RR,
144   BOXOP_PROJX_P, BOXOP_PROJY_P, BOXOP_PPTRX_P, BOXOP_PPTRY_P,
145   BOXOP_RET,
146   BOXOP_CREATE_I, BOXOP_MLN_O, BOXOP_MUNLN_O,
147   BOXOP_MCOPY_OO, BOXOP_RELOC_OO, BOXOP_SHIFT_OO, BOXOP_REF_OO, BOXOP_NULL_O,
148   BOXOP_LEA_C, BOXOP_LEA_I, BOXOP_LEA_R, BOXOP_LEA_P, BOXOP_LEA_OO,
149   BOXOP_PUSH_O, BOXOP_POP_O,
150   BOXOP_JMP_I, BOXOP_JC_I,
151   BOXOP_TYPEOF_I, BOXOP_BOX_O, BOXOP_BOX_OO, BOXOP_WBOX_OO, BOXOP_UNBOX_O,
152   BOXOP_DYCALL_OO,
153   BOX_NUM_OPS
154 } BoxOpId;
155 
156 /** Generic opcodes (type independent) */
157 typedef enum {
158   BOXGOP_CALL=0, BOXGOP_NEWC, BOXGOP_MOV,
159   BOXGOP_BNOT, BOXGOP_BAND, BOXGOP_BXOR, BOXGOP_BOR, BOXGOP_SHL, BOXGOP_SHR,
160   BOXGOP_INC, BOXGOP_DEC, BOXGOP_POW, BOXGOP_ADD, BOXGOP_SUB, BOXGOP_MUL,
161   BOXGOP_DIV, BOXGOP_REM, BOXGOP_NEG, BOXGOP_PMULR, BOXGOP_PDIVR,
162   BOXGOP_EQ, BOXGOP_NE, BOXGOP_LT, BOXGOP_LE, BOXGOP_GT, BOXGOP_GE,
163   BOXGOP_LNOT, BOXGOP_LAND, BOXGOP_LOR, BOXGOP_REAL, BOXGOP_INT, BOXGOP_POINT,
164   BOXGOP_PROJX, BOXGOP_PROJY, BOXGOP_PPTRX, BOXGOP_PPTRY,
165   BOXGOP_RET,
166   BOXGOP_CREATE, BOXGOP_MLN, BOXGOP_MUNLN,
167   BOXGOP_MCOPY, BOXGOP_RELOC, BOXGOP_SHIFT, BOXGOP_REF, BOXGOP_NULL,
168   BOXGOP_LEA, BOXGOP_PUSH, BOXGOP_POP, BOXGOP_JMP, BOXGOP_JC,
169   BOXGOP_TYPEOF, BOXGOP_BOX, BOXGOP_WBOX, BOXGOP_UNBOX, BOXGOP_DYCALL,
170   BOX_NUM_GOPS
171 } BoxGOp;
172 
173 /**
174  * The attributes corresponding to different behaviours of the Box virtual
175  * machine.
176  * @see BoxVM_Set_Attr
177  */
178 typedef enum {
179   BOXVM_ATTR_ASM_LONG_FMT=1,  /**< Use long format when assembling code */
180   BOXVM_ATTR_DASM_WITH_HEX=2, /**< Show also hex values when disassembling */
181   BOXVM_ATTR_ADD_DATA_IDENT=4 /**< Add identity info (debug) to data blocks */
182 } BoxVMAttr;
183 
184 /**
185  * @brief Datastructure representing one instruction to be read/written.
186  */
187 typedef struct BoxOp_struct BoxOp;
188 
189 /**
190  * Object describing a Box VM instruction characteristics.
191  */
192 typedef struct BoxOpDesc_struct BoxOpDesc;
193 
194 /**
195  * @brief Allocate space for a #BoxVM object and initialise it with
196  *   BoxVM_Init().
197  *
198  * You'll need to call BoxVM_Destroy() to destroy the object.
199  */
200 BOXEXPORT BoxVM *
201 BoxVM_Create(void);
202 
203 /**
204  * @brief Destroy a #BoxVM object created with BoxVM_Create().
205  */
206 BOXEXPORT void
207 BoxVM_Destroy(BoxVM *vm);
208 
209 /**
210  * @brief Install a new type and return its type identifier for this VM.
211  *
212  * @param vm The virtual machine where the type is to be installed.
213  * @param t The type to install.
214  * @return The type identifier. This is an integer which identifies the type
215  *   in this VM instance.
216  */
217 BOXEXPORT BoxTypeId
218 BoxVM_Install_Type(BoxVM *vm, BoxType *t);
219 
220 /**
221  * @brief Retrieve the type corresponding to the given type identifier.
222  *
223  * @param vm The virtual machine the identifier @p id refers to.
224  * @param id The type identifier.
225  * @return The installed type corresponding to the identifier @p id.
226  */
227 BOXEXPORT BoxType *
228 BoxVM_Get_Installed_Type(BoxVM *vm, BoxTypeId id);
229 
230 /**
231  * @brief Generate a human-readable description of the table of installed
232  *   types.
233  *
234  * @param vm The virtual machine to which the table refers to.
235  * @return A freshly allocated string (to be freed by Box_Mem_Free() by the
236  *   caller) containing a human-readable representation of the mapping
237  *   type id -> type.
238  */
239 BOXEXPORT char *
240 BoxVM_Get_Installed_Types_Desc(BoxVM *vm);
241 
242 /**
243  * @brief Reference a #BoxVM object, using BoxSPtr_Link().
244  */
245 #define BoxVM_Link(x) (x)
246 
247 /** Set or unset the attributes which control the behaviour of the Box
248  * virtual machine.
249  * @param vmp an instance of the Box virtual machine
250  * @param mask specify what values to set/unset
251  * @param value specify to set/unset the values specified in mask
252  * @see BoxVMAttr
253  */
254 void BoxVM_Set_Attr(BoxVM *vm, BoxVMAttr mask, BoxVMAttr value);
255 
256 /**
257  * @brief This function adds a new piece of data to the data segment.
258  *
259  * @note It returns the address of the data item with respect to the beginning
260  *  of the data segment.
261  *
262  * @param vm the VM object.
263  * @param data the pointer to the data to add.
264  * @param size the size of the data pointed by data.
265  * @param type an integer identifying the type of data.
266  */
267 BOXEXPORT size_t
268 BoxVM_Data_Add(BoxVM *vm, const void *data, size_t size, BoxInt type);
269 
270 /** Produce a human readable representation of the data segment of 'vm'
271  * and send it to the output stream 'stream'.
272  */
273 void BoxVM_Data_Display(BoxVM *vm, FILE *stream);
274 
275 /** Sets the force-long flag and return what was its previous value. */
276 BOXEXPORT int BoxVM_Set_Force_Long(BoxVM *vm, int force_long);
277 
278 BOXEXPORT void BoxVM_ASettings(BoxVM *vmp, int forcelong, int error,
279                                int inhibit);
280 
281 BOXEXPORT void BoxVM_VA_Assemble(BoxVM *vm, BoxOpId instr, va_list ap);
282 
283 BOXEXPORT void BoxVM_Assemble(BoxVM *vmp, BoxOpId instr, ...);
284 
285 /** Similar to VM_Assemble, but use the long bytecode format. */
286 #define BoxVM_Assemble_Long(vm, instr, ...)                     \
287   do {                                                          \
288     int is_long = BoxVM_Set_Force_Long((vm), 1);                \
289     BoxVM_Assemble((vm), (instr), __VA_ARGS__);                 \
290     (void) BoxVM_Set_Force_Long((vm), is_long);} while(0)
291 
292 BOXEXPORT BoxTask BoxVM_Disassemble(BoxVM *vm, FILE *output,
293                                     const void *prog, size_t dim);
294 
295 /** Specifies the number of global registers and variables used by the BoxVM.
296  */
297 BOXEXPORT BoxTask BoxVM_Alloc_Global_Regs(BoxVM *vm, BoxInt num_var[],
298                                           BoxInt num_reg[]);
299 
300 BOXEXPORT void BoxVM_Module_Global_Set(BoxVM *vmp, BoxInt type, BoxInt reg,
301                                        void *value);
302 
303 /**
304  * Get the last failure message.
305  * @param vm the VM.
306  * @param steal if set to BOXBOOL_TRUE, steal the string (and allocation
307  *   responsibility) and remove the failure message from the executor state.
308  * @return A string which must be deallocated by the user iff
309  *   steal == BOXBOOL_TRUE.
310  */
311 BOXEXPORT char *BoxVM_Get_Fail_Msg(BoxVM *vm, BoxBool steal);
312 
313 /**
314  * Set a failure message.
315  * @param vmx the VM executor.
316  * @param msg a string representing an error condition. If this is NULL, then
317  *   the error condition for the VM executor is reset.
318  */
319 BOXEXPORT void BoxVM_Set_Fail_Msg(BoxVM *vm, const char *msg);
320 
321 #endif /* _BOX_VM_H */
322