/****************************************************************************
* Copyright (C) 2008-2012 by Matteo Franchin *
* *
* This file is part of Box. *
* *
* Box is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* Box is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with Box. If not, see . *
****************************************************************************/
/**
* @file vm_priv.h
* @brief Box virtual machine private definitions.
*/
#ifndef _BOX_VM_PRIVATE_H
# define _BOX_VM_PRIVATE_H
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
/**
* Structure used in BoxOpInfo to list the input and output registers
* for each VM operation.
*/
typedef struct {
char kind, /**< 'a' for explicit argument, 'r' for implicit local register */
type, /**< 'c':Char, 'i':Int, 'r':Real, 'p':Point, 'o':Obj */
num, /**< Number of argument or register (can be 0, 1, 2) */
io; /**< 'o' for output, 'i' for input, 'b' for input/output */
} BoxOpReg;
/**
* @brief Enumeration of all the possible types of signatures for the Box VM
* instructions.
*
* Different signatures mean different number and/or type of arguments.
*/
typedef enum {
BOXOPSIGNATURE_NONE,
BOXOPSIGNATURE_ANY,
BOXOPSIGNATURE_IMM,
BOXOPSIGNATURE_ANY_ANY,
BOXOPSIGNATURE_ANY_IMM
} BoxOpSignature;
/** Possible methods for disassembling a Box VM operation.
* Each item in the enumeration corresponds to a different method to be used
* for disassembling the operation.
*/
typedef enum {
BOXOPDASM_ANY_ANY,
BOXOPDASM_ANY_IMM,
BOXOPDASM_JMP,
BOXOPDASM_CALL
} BoxOpDAsm;
/** Typedef of struc __BoxOpInfo */
typedef struct BoxOpInfo_struct BoxOpInfo;
/**
* @brief Structure containing detailed information about one VM operation.
*/
struct BoxOpInfo_struct {
BoxOpId opcode; /**< Opcode for the operation */
BoxGOp g_opcode; /**< Generic opcode */
BoxOpInfo *next; /**< Next operation with the same generic opcode */
const char *name; /**< Literal name of the opcode (a string) */
BoxOpSignature
signature; /**< Operation kind (depends on the arguments) */
BoxOpDAsm dasm; /**< How to disassemble the operation */
char arg_type, /**< Type of the arguments */
num_args, /**< Number of arguments */
num_inputs, /**< Num. of input registers (explicit+implicit) */
num_outputs, /**< Num. of output registers(explicit+implicit) */
num_regs; /**< Num. of distinct registers involved by the
operation (this is not just in + out) */
BoxOpReg *regs; /**< Pointer to the list of input/output regs */
BoxVMOpExecutor
executor; /**< Pointer to the function which implements
the operation */
};
/**
* Content of a BoxOpDesc object.
*/
struct BoxOpDesc_struct {
const char *name; /**< Instruction name */
BoxUInt numargs; /**< Number of arguments */
int num_args; /**< Number of proper arguments. */
int has_data; /**< Whether this instruction has attached
data. */
BoxTypeId t_id; /**< Type of the arguments (all have the
same type) */
BoxVMOpExecutor execute; /**< Per eseguire l'istruzione */
};
/** Table containing info about all the VM operations */
typedef struct {
BoxOpInfo info[BOX_NUM_OPS]; /**< Table of BoxOpInfo strucs. One for each
VM operation */
BoxOpReg *regs; /**< Buffer used by the BoxOpTable.info */
} BoxOpTable;
/**
* @brief Identifies the form of a VM instruction argument.
*
* Possible forms are local register (e.g. ri1), global register (e.g. gri1),
* pointer (e.g. i[ro0 + 8]) and immediate (e.g. 1.234).
*/
typedef enum {
BOXOPARGFORM_GREG = 0, /**< Global register. */
BOXOPARGFORM_LREG, /**< Local register. */
BOXOPARGFORM_PTR, /**< Pointer. */
BOXOPARGFORM_IMM /**< Immediate. */
} BoxOpArgForm;
/** Item used in a backtrace to identify where the exception caused the
* particular function to exit.
*/
typedef struct {
BoxVMCallNum call_num; /**< Call number of the function */
size_t vm_pos; /**< Position in the VM code */
} BoxVMTrace;
typedef struct {
void *ptr; /**< Pointer to the region allocated for the registers */
BoxInt min, /**< Min register number */
max; /**< Max register number */
} BoxVMRegs;
/**
* @brief Datastructure used to parse one single instruction argument.
*/
typedef struct {
union {
BoxChar val_char; /**< Value for Char registers. */
BoxInt val_int; /**< Value for Int registers. */
BoxReal val_real; /**< Value for Real registers. */
BoxPtr val_ptr; /**< Value for Ptr registers. */
} data; /**< Data associated to the argument. */
} BoxOpArg;
/**
* This structure contains all the data which define the status for the VM.
* Status is allocated by VM_Module_Execute() inside its stack.
*/
struct BoxVMX_struct {
BoxVM *vm; /**< VM to execute. */
BoxVMProcInstalled *p; /**< Procedure which is currently been executed */
struct {
unsigned int
error :1, /**< Error detected */
exit :1; /**< Exit current execution frame */
} flags; /**< Execution flags */
BoxInt op_size;
BoxVMRegs local[NUM_TYPES], /**< Local register allocation status */
*global; /**< Global register allocation status */
BoxInt alc[NUM_TYPES]; /**< Allocation status of local registers
(whether a 'new num_regs, num_vars'
instruction has been used) */
};
/**
* @brief The full status of the virtual machine of Box.
*/
struct BoxVM_struct {
BoxArr types; /**< Type bound to this VM. */
BoxHT types_dict; /**< Dictionaries to find type IDs the corresponding
types.*/
struct {
unsigned int
forcelong :1, /**< Force long form assembly. */
hexcode :1, /**< Show Hex values in disassembled code */
identdata :1; /**< Add also identity info for data inserted
into the data segment */
} attr; /** Flags controlling the behaviour of the VM */
struct {
unsigned int
globals :1, /**< Global regs have been allocated */
op_table :1; /**< The operation table has been built */
} has; /**< State of the VM */
BoxArr stack, /**< The stack for the VM object */
data_segment; /**< The segment of data (strings, etc.) which is
accessible through the register gro0 */
BoxVMRegs global[NUM_TYPES]; /**< The values of the global registers */
BoxPtr *box_vm_current,
*box_vm_arg1;
const BoxOpDesc
*exec_table; /**< Table collecting info about the instructions
which are useful for execution. */
BoxVMProcTable
proc_table; /**< Table of installed and uninstalled procs */
BoxVMSymTable
sym_table; /**< Table of referenced and defined symbols */
BoxOpTable
op_table; /**< Table describing the instructions and their
properties */
BoxArr backtrace; /**< Information about error location */
char *fail_msg; /**< Failure message */
BoxHT id_from_desc; /**< Hashtable containing object descriptors */
BoxArr desc_from_id; /**< Table of descriptors from allocation IDs */
};
extern const size_t size_of_type[NUM_TYPES];
/** Maximum num of arguments (implicit + explicit) that an operation
* can have
*/
#define BOXOP_MAX_NUM_ARGS 4
/** Build a table containing info on the Box VM operations for each of them.
* The table is addressable using a BoxGOp as index.
* This is quite an internal function.
*/
void BoxOpTable_Build(BoxOpTable *ot);
/** Destroy a BoxOpTable object created with BoxOpTable_Build */
void BoxOpTable_Destroy(BoxOpTable *ot);
/** Print the given BoxOpTable to the given stream. */
void BoxOpTable_Print(FILE *out, BoxOpTable *ot);
/** Get information about the specified generic VM operation. */
BoxOpInfo *BoxVM_Get_Op_Info(BoxVM *vm, BoxGOp g_op);
/** Print all the signatures for a the given BoxOpInfo object. */
void BoxOpInfo_Print(FILE *out, BoxOpInfo *oi);
/** (Internal) Get the execution table for the Box VM instructions. */
const BoxOpDesc *BoxVM_Get_Exec_Table(void);
/** This is the type of the C functions which can be called by the VM. */
typedef BoxTask (*BoxVMFunc)(BoxVMX *);
/**
* Initialise a BoxVM object for which space has been already allocated
* somehow. You'll need to use BoxVM_Finish to destroy the object.
* @see BoxVM_Finish, BoxVM_Create
*/
BOXEXPORT BoxTask
BoxVM_Init(BoxVM *vm);
/**
* @brief Destroy a BoxVM object initialised with BoxVM_Init().
* @see BoxVM_Init
*/
BOXEXPORT void
BoxVM_Finish(BoxVM *vm);
BOXEXPORT BoxTask
BoxVM_Module_Execute(BoxVM *vm, BoxVMCallNum call_num);
/**
* Similar to BoxVM_Module_Execute(), but takes also pointers to child
* and parent. The register gro1 and gro2 are modified after this call: in
* particular, '*parent' is stored in gro1 and '*child' in gro2.
* This guarantee that the reference counting protocol is respected.
*/
BOXEXPORT BoxTask
BoxVM_Module_Execute_With_Args(BoxVM *vm, BoxVMCallNum cn,
BoxPtr *parent, BoxPtr *child);
/**
* Clear the backtrace of the program.
*/
void BoxVM_Backtrace_Clear(BoxVM *vm);
/**
* Print on 'stream' a human redable representation of the backtrace
* of the program.
*/
void BoxVM_Backtrace_Print(BoxVM *vm, FILE *stream);
/** Get the parent of the current combination (this is something with type
* ``BoxPtr *``.
*/
# define BoxVMX_Get_Parent(vmx) ((vmx)->vm->box_vm_current)
/** Get the child of the current combination (this is something with type
* ``BoxPtr *``
*/
# define BoxVMX_Get_Child(vmx) ((vmx)->vm->box_vm_arg1)
/** Shorthand for BoxPtr_Get_Target(BoxVM_Get_Parent(vm)). */
# define BoxVMX_Get_Parent_Target(vmx) \
(BoxPtr_Get_Target(BoxVMX_Get_Parent(vmx)))
/** Shorthand for BoxPtr_Get_Target(BoxVM_Get_Child(vm)). */
# define BoxVMX_Get_Child_Target(vmx) \
(BoxPtr_Get_Target(BoxVMX_Get_Child(vmx)))
/* XXX TODO: the ones below are obsolete macros, which should be removed. */
# define BOX_VM_THIS_PTR(vmx, Type) ((Type *) (vmx)->vm->box_vm_current->ptr)
# define BOX_VM_THIS(vmx, Type) (*BOX_VM_THIS_PTR(vmx, Type))
# define BOX_VM_ARG1_PTR(vmx, Type) ((Type *) (vmx)->vm->box_vm_arg1->ptr)
# define BOX_VM_ARG1(vmx, Type) (*BOX_VM_ARG1_PTR(vmx, Type))
# define BOX_VM_ARG_PTR BOX_VM_ARG1_PTR
# define BOX_VM_ARG BOX_VM_ARG1
# define BOX_VM_SUB_PARENT_PTR(vmp, parent_t) \
SUBTYPE_PARENT_PTR(BOX_VM_THIS_PTR(vmp, BoxSubtype), parent_t)
# define BOX_VM_SUB_PARENT(vmp, parent_t) \
(*BOX_VM_SUB_PARENT_PTR(vmp, parent_t))
# define BOX_VM_SUB_CHILD_PTR(vmp, child_t) \
SUBTYPE_CHILD_PTR(BOX_VM_THIS_PTR(vmp, BoxSubtype), child_t)
# define BOX_VM_SUB_CHILD(vmp, child_t) \
(*BOX_VM_SUB_CHILD_PTR(vmp, child_t))
# define BOX_VM_SUB2_PARENT(vmp, parent_t) \
(*SUBTYPE_PARENT_PTR(BOX_VM_SUB_PARENT_PTR(vmp, BoxSubtype), parent_t))
#endif /* _BOX_VM_PRIVATE_H */