/* * TYPE.H * * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the * COPYRIGHT file at the base of the distribution. * * See libsupport/coretype.h for definitions of runesize_t and a few others. */ #ifndef _LIBRUNE_TYPE_H_ #define _LIBRUNE_TYPE_H_ struct Exp; struct Stmt; struct SemGroup; struct Type; /* * These are used everywhere but the structure definitions are more * localized. */ struct RunContext; struct GenContext; struct RuneThread; struct RuneLock; struct RefStor; typedef struct RunContext *runctx_p; typedef struct GenContext *genctx_p; /* * PointerInfo - This structure is typically stored as part of the RefStor * or stack context. It contains the auxillary data needed to * validate a pointer. * * Auxillary data is essentially static and the code generator * can cache bits and pieces of it as necessary. The s_Info * pointer itself may change when the pointer is reassigned, * but does not change for nominal pointer arithmatic within * the pointer's current domain. * * in_Beg and in_End are only used for PCheck operations and * may require a dynamic info structure, which is not usually * implemented. All info structures are taken from the * type's static ty_Info template. * * PointerStor - This structure represents a pointer, consisting of the * actual pointer and a secondary pointer to the related * info structure. * * LValueStor - This structure represents an LValue and is essentially the * same format as a PointerStor now, but we treat it separately * to reduce confusion. Unlike pointers, the pointer embedded * in an LValueStor cannot change and has already been validated. * * NOTE: PointerInfo.s_Type is the pointer target type, not the pointer type. * * WARNING: These structures are hard-coded in various places. */ typedef struct PointerInfo { struct RefStor *in_RefStor; char *in_Beg; /* (only for pointer tracking) */ char *in_End; /* (only for pointer tracking) */ struct Type *in_Type; /* pointer TARGET type */ void **in_DynVec; /* broken-out of the type */ struct PointerInfo *in_Next; runesize_t in_Refs; } PointerInfo; #define PINFO_STATIC ((runesize_t)0x00000001) #define PINFO_INCR ((runesize_t)0x00000002) /* * NOTE: s_Info->in_Type is the type of the object pointed to by s_Addr. * That is, the pointer target type, not the pointer type. */ typedef struct PointerStor { char *s_Addr; /* The actual pointer */ PointerInfo *s_Info; /* Auxillary information */ } __aligned(16) PointerStor; #define SIZE_SIZE ((runesize_t)(sizeof(runesize_t))) #define CPOINTER_SIZE ((runesize_t)(sizeof(void *))) #define CPOINTER_ALIGN ((runesize_t)(CPOINTER_SIZE - 1)) #define POINTERINFO_SIZE ((runesize_t)(sizeof(PointerInfo))) #define POINTERSTOR_SIZE ((runesize_t)(sizeof(PointerStor))) #define LVALUESTOR_SIZE ((runesize_t)(sizeof(LValueStor))) #define POINTERSTOR_ALIGN ((runesize_t)(sizeof(PointerStor) - 1)) #define LVALUESTOR_ALIGN ((runesize_t)(sizeof(LValueStor) - 1)) #define EXTRA_INTERNAL_SPACE (CPOINTER_SIZE * 6) #define RUNE_PTRSTOR_ADDR offsetof(PointerStor, s_Addr) #define RUNE_PTRSTOR_INFO offsetof(PointerStor, s_Info) #define RUNE_LVSTOR_ADDR offsetof(LValueStor, s_Addr) #define RUNE_LVSTOR_INFO offsetof(LValueStor, s_Info) #define RUNE_PINFO_REFSTOR offsetof(PointerInfo, in_RefStor) #define RUNE_PINFO_BEG offsetof(PointerInfo, in_Beg) #define RUNE_PINFO_END offsetof(PointerInfo, in_End) #define RUNE_PINFO_TYPE offsetof(PointerInfo, in_Type) #define RUNE_PINFO_DYNVEC offsetof(PointerInfo, in_DynVec) /* * LValueStor * * This structure is the run-time representation of an lvalue object. It * is typically used to present lvalue arguments and return values for method * calls but may also represent special storage mechanics such as "heap" * and "persist", as well as interpreter-related objects. * * LValue objects are always considered to be valid. They are not pointers * in that their s_Addr cannot be changed, and the s_Info structure always * points to the type's static ty_Info (in_Beg and in_End are always NULL). * * NOTE: s_Info->in_Type is the type of the object pointed to by s_Addr. * That is, the target type (which is also how PointerStor works). */ typedef struct LValueStor { void *s_Addr; /* the actual pointer */ PointerInfo *s_Info; /* Auxillary information */ } __aligned(16) LValueStor; /* * Interpreter's temporary storage structure. * * Note, however, that an exp should never store more data into the * RunTmpStor than it's ex_Type says it can because higher level calls * (like InterpCompoundExp()) will attempt to avoid copies by directly * passing the destination storage as the TmpStor. * * NOTE: Expression-temporaries never store LValueStor's, which are entities * that can exist in SemGroups. The type's SF_LVALUE flag is not * related to the LValueStor structure. */ typedef union RunTmpStor { d_bool_t ts_Bool; int8_t ts_Int8; int16_t ts_Int16; int32_t ts_Int32; runesize_t ts_Size; int64_t ts_Int64; int64_t ts_Int64Ary[2]; d_off_t ts_Off; u_int8_t ts_UInt8; u_int16_t ts_UInt16; u_int32_t ts_UInt32; u_int64_t ts_UInt64; u_int64_t ts_UInt64Ary[2]; float ts_Float32; double ts_Float64; long double ts_Float128; PointerStor ts_Pointer; void *ts_VoidPtr; void *ts_CPtr; } RunTmpStor; /* * Data element for interpreter. Note that the data pointer itself is * returned directly as a return value as a means of maintaining high * interpreter performance. Callers must reassociate the data pointer with * the data object upon return prior to making any calls to data-centric * support routines. This allows low-level operators to mostly ignore * RunData when operating on basic data. * * mrs - Sideband ref on the memory containing the object. * * Non-temporary objects remain valid when discarded. Their content is * only dereferenced when they are content-dropped by other means. * Temporaries are always content-dropped when discarded. */ typedef struct RunData { void *data; struct RefStor *mrs; union { uint32_t rollup; struct { int8_t istmp; int8_t storage; int8_t unused02; int8_t isdcopy; }; }; RunTmpStor ts; } rundata_t; static __inline void rundata_clear(rundata_t *data) { data->data = NULL; data->mrs = NULL; data->rollup = 0; } static __inline void rundata_copy(rundata_t *src, void *ptr, rundata_t *dst) { dst->data = ptr; dst->mrs = src->mrs; dst->rollup = src->rollup; if (ptr == &src->ts) { bcopy(&src->ts, &dst->ts, sizeof(src->ts)); dst->data = &dst->ts; } } /* * Data element for code generator. * * minfo - Sideband info for the storage containing the object, * typically needed when evaluating lvalue objects and * &object. * rssg - Static generation semgroup so static address output can * figure out the correct info reference. * * Non-temporary objects remain valid when discarded. Their content is * only dereferenced when they are content-dropped by other means. * Temporaries are always content-dropped when discarded. */ typedef struct GenData { uint32_t regno; uint8_t eamode; uint8_t storage; uint8_t istmp; uint8_t unused03; char *label; int64_t offset; /* also used for immediate value */ int64_t immhi; /* if 128-bit immediate */ /* * s_Beg, s_End used by the generator's global data init * during interpretation to calculate relative offsets of * ps->s_Beg and ps->s_End for global pointer initialization. */ runesize_t s_Beg; /* (generator global data init only) */ runesize_t s_End; /* (generator global data init only) */ /* * implied_mask is a bitmask for up to the first 64 LValueStor's * (SCOPE_LVALUE elements) of a compound type, or of a * SCOPE_LVALUE type (such as a lvalue return). If a bit is * set it indicates that the lvalue element has an implied lock * and should not be LVPUT/LVREL'd on drop. * * We can do this optimization for lvalue elements because the * caller is not allowed to modify the lvs->s_RefStor itself, * and will separately ref/lock any copy it makes. Such situations * are strictly temporary so the original code setting the bits * knows the content will be done when it disposes of them. * And because of that, implied locks can be chained. */ uint64_t implied_mask; /* implied locks on LVALUEs */ void *cache_id; /* non-NULL means cacheable */ struct Type *load_type; /* for memory load/store only */ struct GenData *minfo; /* sideband PointerInfo on memory */ struct GenData *type; /* extracted Type, NULL if not dyn */ struct SemGroup *rssg; /* list of decls */ } gendata_t; typedef gendata_t *gendata_p; #define EA_UNKNOWN 0 #define EA_DIRECT 1 #define EA_MEMORY 2 #define EA_UNUSED03 3 #define EA_IMMEDIATE 4 #define EA_IMMEDIATE16 5 /* 128-bit immediate */ #define EA_BAD 0x80U /* * The storage fields above represent the nominal storage mode for * the target content of an object, not the memory containing the object. * It is only applicable to references, pointers, lvalues, and compound * types (and only recurses via compound types). The storage mode for * elements making up e.g. class objects are governed by the class's * declarations. * * For a pointer or reference, for example, 'storage' represents how * the target object represented by PointerStor.s_Info is lock+refd, * not how the memory containing the pointer is lock+refd, or how each * element of a compound type is handled recursively for compound types. * * However, the storage field does NOT classify the elements of a structure. * it strictly classifies only the 'top' element. A pointer or reference * is different from a structure containing a pointer or reference. * * LValues are a bit more confusing. An LValue's 'storage' specification * represents how its LValueStor.s_Info is lock+refd and nothing more. * If the LValue represents a pointer/reference type then it is an * LValueStor that points to a PointerStor, but the lock+refd mode of the * PointerStor's target is NOT determined by the 'storage' specification. * * If an LValueStor represents a compound type (verses a pointer to a compound * type), the storage specification recurses as per normal for compound types. * * In method calls, the LValue object is an LValueStor that points to * the object, NOT an LValueStor that pointers to a PointerStor. It is * NOT a pointer semantically. Hence why method procedures access the * object using dot notation, as in 'this.BLAH'. * * DEFAULT STORAGE MODES: * Method target objects GENSTAT_LOCKH (default) * GENSTAT_LOCK ('soft') * GENSTAT_NONE ('untracked') (note 1) * Procedure arguments GENSTAT_ARGDEF (note 2) * Procedure return GENSTAT_RETDEF (note 2) * local variables GENSTAT_STKDEF (note 2) * expression temporaries GENSTAT_EXPDEF * structural elements GENSTAT_MEMDEF (note 3) * compound types (recursion for passed-in storage mode) * * note 1 - In untracked mode no refs or locks are obtained. Untracked * pointers cannot be cast (as this required a sideband info * structure). * * note 2 - If the address is taken of an element or the element is * used as an lvalue it needs to be GENSTAT_REFD (XXX) * * note 3 - For maximum compatibility, structural elements are * GENSTAT_REFD. The 'storage' field for a class object * is not applicable (its only applicable for pointers, * references, and lvalues). * * NONE Nominal storage status is nothing. * REFD Nominal storage status is REFD. * LOCK Nominal storage status is LOCK+REFD. * LOCKH Nominal storage status is LOCK+REFD using a hard lock. * * EMPTY (flag) indicates no prior contents to storage, allows * unnecessary PUTs(etc) to be optimized out. */ #define GENSTAT_NONE 0 #define GENSTAT_REFD 1 #define GENSTAT_LOCK 2 #define GENSTAT_LOCKH 3 #define GENSTAT_UNSPEC 4 /* when storage mode not known */ #define GENSTATF_EMPTY 0x10 #define GENSTAT_EXPDEF GENSTAT_NONE /* expression temporaries */ #define GENSTAT_ARGDEF GENSTAT_NONE /* argument declarations */ #define GENSTAT_RETDEF GENSTAT_NONE /* return declaration */ #define GENSTAT_STKDEF GENSTAT_NONE /* local declarations */ #define GENSTAT_MEMDEF GENSTAT_REFD /* nominal memory */ #define GENSTAT_METDEF GENSTAT_LOCKH /* method object */ #define GENSTAT_ARYDEF GENSTAT_REFD /* array elements */ #define GENSTAT_TYPDEF GENSTAT_NONE /* type default initialization */ #define REGF_PTR 0x80000000U #define REGF_MASK 0x00FFFFFFU #define REGF_USRMASK 0x7F000000U #define REGF_USRBASE 0x01000000U #define REG_FIRSTTMP 100 #define REG_NEWDAT ((uint32_t)-1 & REGF_MASK) #define REG_NEWPTR (REGF_PTR | ((uint32_t)-1 & REGF_MASK)) #define REG_SG (REGF_PTR | 9) /* semgroup pointer (varargs calls) */ #define REG_RP (REGF_PTR | 10) /* return data pointer */ #define REG_DB (REGF_PTR | 11) /* data & module base */ #define REG_TP (REGF_PTR | 12) /* thread pointer */ #define REG_AP (REGF_PTR | 13) /* argument pointer */ #define REG_FP (REGF_PTR | 14) /* frame pointer */ #define REG_PC (REGF_PTR | 15) /* program counter */ #define REG_ZERO 0 #define REG_NULL (REGF_PTR | 0) #define REG_ABS REG_NULL /* * Branch label element for code generator */ typedef struct { genctx_p ct; /* (for accounting only) */ int32_t id; int32_t unused01; runesize_t bytes; /* string constants only */ } genlabel_t; typedef genlabel_t *genlabel_p; /* * Type - the type structure. Types are various forms of instantiated * objects. * * (note 1) - TY_DYNAMIC types are special. During run-time an * expression that normally returns a dynamic type must * either be cast to the type you want (which is hinted * into exp->ex_Type, replacing the dynamic type), or * it must be marked as returning a type. * * Normally a returned type is simply stored in ex_Type, * but this doesn't work when making run-time changes * (due to reusing the Exp's in a threaded environment). * In this case the expression leaves ex_Type set to * a TY_DYNAMIC type and will return a pointer to * the type as data. * * * (note 2) - The visibility of a type's contents is set in * resolveType() and based on where the type's base * class or compound type was defined vs where it * is referenced. * * WARNING: Must match classes/sys/runtime.d */ struct Type; typedef RUNE_HEAD(typelist, Type) typelist_t; typedef struct Type { RUNE_ENTRY(Type) ty_Node; typelist_t ty_QList; /* qualified type (ptr-to, etc...) */ int ty_Op; /* type opcode (TY_*) */ int ty_Flags; /* type flags (must be int) */ runesize_t ty_Bytes; /* size of type in bytes */ runesize_t ty_AlignMask; /* alignment mask */ int ty_SQFlags; /* qualifiers, if any */ int ty_Visibility; /* visib of type's contents (note 2) */ typelist_t *ty_SQList; /* qualifications list (shared) */ struct Exp *ty_AssExp; /* assigned default for type */ runesize_t ty_TmpBytes; /* temporary required for assignment */ runesize_t ty_TmpAlignMask;/* temporary space alignment mask */ void **ty_DynamicVector; /* placeholder for generator */ PointerInfo ty_Info; /* info template for NULL pointer */ union { struct { struct SemGroup *et_SemGroup; /* list of decls */ struct Type *et_Super; /* superclass */ } ClassType; struct { struct SemGroup *et_SemGroup; /* list of decls */ } ImportType; struct { struct Type *et_Type; /* pointer to type */ } PtrType; struct { struct SemGroup *et_SemGroup; /* for sem search */ struct Exp *et_ArySize; /* size exp or NULL */ struct Type *et_Type; /* array of this type */ runesize_t et_Count; /* resolved elements */ } AryType; struct { struct SemGroup *et_SemGroup; /* list of decls */ } CompType; struct { struct SemGroup *et_SemGroup; /* list of decls */ struct Type *et_Type; /* type to extend */ } VarType; struct { struct Type *et_ArgsType; /* args (compound) */ struct Type *et_RetType; /* return type */ runesize_t et_ArgCount; /* # of args */ } ProcType; struct { runesize_t et_Bytes; /* size in bytes */ } StorType; struct { runesize_t et_Unused00; } DynamicType; struct { string_t *et_DottedId; /* a, b, c, NULL */ struct SemGroup *et_SemGroup; /* for sem search */ struct SemGroup *et_ImportSemGroup; /* for sem search */ } UnresType; struct { void *et_Fill0; void *et_Fill1; void *et_Fill2; void *et_Fill3; } FILLER; } u; } Type; #define RUNE_TYPE_DYNAMIC_VECTOR \ ((runesize_t)offsetof(Type, ty_DynamicVector)) #define RUNE_TYPE_INFO \ ((runesize_t)offsetof(Type, ty_Info)) /* * Weak aliases to the actual type label for well-defined type names */ struct TypeRegNode; typedef RUNE_HEAD(typereglist, TypeRegNode) typereglist_t; typedef struct TypeRegNode { RUNE_ENTRY(TypeRegNode) tr_Node; string_t tr_Id; const char *tr_LinkName; Type *tr_Type; } TypeRegNode; #define ty_ClassType u.ClassType #define ty_ImportType u.ImportType #define ty_PtrType u.PtrType #define ty_CPtrType u.PtrType #define ty_AryType u.AryType #define ty_CompType u.CompType #define ty_ArgsType u.CompType #define ty_VarType u.VarType #define ty_ProcType u.ProcType #define ty_QualType u.QualType #define ty_StorType u.StorType #define ty_UnresType u.UnresType #define ty_RefType u.PtrType /* must be same as PtrType */ #define TY_CLASS 1 /* the type represents a base class */ #define TY_PTRTO 2 /* the type is a pointer to BLAH */ #define TY_ARYOF 3 /* the type is an array of BLAH */ #define TY_COMPOUND 4 /* the type is compound, made up of BLAH */ #define TY_PROC 5 /* the type is a procedure */ #define TY_IMPORT 6 #define TY_STORAGE 7 /* as a special raw-storage type */ #define TY_ARGS 8 /* procedure arguments (compound) type */ #define TY_VAR 9 /* variable procedure arguments */ #define TY_DYNAMIC 10 /* run-time type (must be cast) (note 1) */ #define TY_UNRESOLVED 11 /* unresolved identifier path */ #define TY_REFTO 12 /* reference type (no indrection) */ #define TY_CPTRTO 13 /* C pointer type (no PointerStor) */ #define TF_RESOLVING 0x000001 /* type fully resolved */ #define TF_RESOLVED 0x000002 /* type fully resolved */ #define TF_DEFINED 0x000004 /* type has been defined, else only refd */ #define TF_NOINIT 0x000008 /* (interpreter - status) */ #define TF_HASLVPTR 0x000010 /* is or contains arg-lvalue, or ptr */ #define TF_HASCONSTRUCT 0x000020 /* contains constructor */ #define TF_HASDESTRUCT 0x000040 /* contains destructor */ #define TF_TMPRESOLVED 0x000080 /* temporary storage for exp eval resolv */ #define TF_CONDESDATA 0x000100 /* constr/destruct data as well as procs */ #define TF_HASGCONSTRUCT 0x00200 /* contains global constructor */ #define TF_HASGDESTRUCT 0x000400 /* contains global destructor */ #define TF_ISUNSIGNED 0x000800 /* Unsigned Integer (helper) */ #define TF_ISFLOATING 0x001000 /* Floating Point (helper) */ #define TF_ISINTEGER 0x002000 /* Unsigned or signed integer (helper) */ #define TF_HASASS 0x004000 /* has or contains assignments {*/ #define TF_ISBOOL 0x008000 /* Boolean (helper) */ #define TF_GENERATING 0x010000 /* backend generation */ #define TF_COLLAPSED 0x020000 /* collapse pass in prog or done */ #define TF_LAYOUT 0x040000 /* available for global layout */ #define TF_ISINTERNAL 0x080000 /* special internal type, do not collapse */ #define TF_ALIGNRESOLVED 0x100000 /* alignment resolved */ /* * Special storage qualifier masks */ #define SF_MASK_ARY_INHERIT (SF_CONST|SF_VOLATILE|SF_LVALUE|SF_NOZERO) /* * Global Info structure */ typedef struct GlobInfo { char *gi_Label; /* location of global entity */ runesize_t gi_Offset; runesize_t gi_Bytes; Type *gi_Type; int gi_Flags; int gi_Hash; struct SemGroup *gi_RSSG; /* SG for global RefStor */ struct GlobInfo *gi_HNext; } GlobInfo; #define GLF_GENERATING 0x00000001 /* * Needed for inlines */ Type *TypeToQualType(Type *otype, Type *ntype, int sqFlags, struct Exp *exp); static __inline Type * AddTypeQual(Type *type, int sqFlags) { return(TypeToQualType(type, NULL, type->ty_SQFlags | sqFlags, NULL)); } static __inline Type * DelTypeQual(Type *type, int sqFlags) { return(TypeToQualType(type, NULL, type->ty_SQFlags & ~sqFlags, NULL)); } #define dassert_type(type, cond) dassert(cond) #endif