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