dvander@238: /* vim: set ts=4 sw=4 tw=99 et: dvander@238: * dvander@238: * Copyright (C) 2012 David Anderson dvander@238: * dvander@238: * This file is part of JITCraft. dvander@238: * dvander@238: * JITCraft is free software: you can redistribute it and/or modify it under dvander@238: * the terms of the GNU General Public License as published by the Free dvander@238: * Software Foundation, either version 3 of the License, or (at your option) dvander@238: * any later version. dvander@238: * dvander@238: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@238: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@238: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@238: * dvander@238: * You should have received a copy of the GNU General Public License along with dvander@238: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@238: */ dvander@238: #ifndef _include_jc_types_h_ dvander@238: #define _include_jc_types_h_ dvander@238: dvander@238: #include "Heap.h" dvander@238: #include "Barriers.h" dvander@238: #include "FixedArray.h" dvander@238: #include "compiler/Token.h" dvander@238: dvander@238: namespace ke { dvander@238: dvander@238: class String; dvander@238: class Descriptor; dvander@238: class StructMap; dvander@238: class ArrayMap; dvander@238: dvander@238: #define MAX_ARRAY_DEPTH 5 dvander@238: dvander@238: enum PrimitiveType dvander@238: { dvander@238: // A boolean type semantically represents 0 or 1. As an optimization, its dvander@238: // internal storage type is the same as int32, and any non-zero value dvander@238: // compares positively to "true". dvander@238: PrimitiveType_Bool, dvander@238: dvander@238: // A character is an arbitrary 8-bit value. Characters are not supported dvander@238: // as a normal storage class; they may only be used for arrays. When read dvander@238: // from an array, they are immediately sign extended to 32 bits. Integers dvander@238: // stored into an char array are truncated to 8 bits. dvander@238: PrimitiveType_Char, // signed, 8-bit character dvander@238: dvander@238: // Enumerations and untyped variables are stored as signed, 32-bit integers. dvander@238: PrimitiveType_Int32, dvander@238: dvander@238: // Floating point values are 32-bit IEEE-754 floats. This is required ro dvander@238: // SourcePawn 1 compatibility. dvander@238: PrimitiveType_Float, dvander@238: dvander@238: // This is a native-sized integer type (32-bit on 32-bit systems, 64-bit dvander@238: // on 64-bit systems), and does not exist in language semantics. dvander@238: PrimitiveType_Native, dvander@238: dvander@238: PrimitiveTypes_Total dvander@238: }; dvander@238: dvander@238: enum TypeQualifiers dvander@238: { dvander@238: TypeQual_None = 0, dvander@238: dvander@241: // Values of this type cannot be modified. dvander@241: TypeQual_Const = (1 << 2) dvander@238: }; dvander@238: dvander@238: class Type : public Object dvander@238: { dvander@238: protected: dvander@238: enum Kind { dvander@238: // A primitive is a plain-old-data type. dvander@238: PRIMITIVE, dvander@238: dvander@238: // Void is an internal type used to specify that a function returns no dvander@238: // value. dvander@238: VOID, dvander@238: dvander@238: // Enums are plain-old-data with int32 storage. They allow for extra dvander@238: // type checking that would not be possible with integers. dvander@238: ENUM, dvander@238: dvander@238: // Unchecked is a magic type that has implicit, bitwise coercion to dvander@238: // int32, float, bool, or an enum. dvander@238: UNCHECKED, dvander@238: dvander@239: // Contains type qualifiers, and a back pointer to the actual dvander@239: // unqualified type. dvander@239: QUALTYPE, dvander@239: dvander@239: // ------ Add traceable types below (STRING FIRST!) ------- dvander@238: dvander@238: // An immutable type that is a primitive in terms of language dvander@238: // semantics, but gets a special type here to make internal dvander@238: // logic easier. dvander@238: STRING, dvander@238: dvander@238: // An array is a fixed-length vector of any other type. dvander@238: ARRAY, dvander@238: EXTERNAL_ARRAY, dvander@238: dvander@238: // A reference type may only be specified on parameters, and dvander@238: // references may only be computed to primitives or enums. dvander@238: REFERENCE, dvander@238: dvander@238: // A function type encapsulates a function signature. dvander@238: FUNCTION, dvander@238: dvander@238: // Structs are composite records that may contain primitives, arrays, dvander@238: // functions, enums, and other structs. dvander@256: STRUCT, dvander@256: dvander@256: // Importable types are mainly used during the compilation process dvander@256: // to distinguish between normal names and static imports. dvander@256: IMPORTABLE dvander@238: }; dvander@238: dvander@240: void init(Kind kind, Type *root = NULL); dvander@238: dvander@238: private: dvander@238: Kind kind() { dvander@238: return root_->kind_; dvander@238: } dvander@238: dvander@238: public: dvander@238: static Type *NewVoid(Zone *zone); dvander@238: static Type *NewUnchecked(Zone *zone); dvander@238: static Type *NewPrimitive(Zone *zone, PrimitiveType type); dvander@238: static Type *NewString(Zone *zone); dvander@240: static Type *NewQualified(Zone *zone, TypeQualifiers qual, Handle type); dvander@256: static Type *NewImportable(Zone *zone); dvander@238: dvander@238: static Type *cast(Object *obj) { dvander@238: assert(!obj || dvander@238: obj->is(MapKind_Type) || dvander@238: obj->is(MapKind_FunctionType) || dvander@238: obj->is(MapKind_StructType) || dvander@238: obj->is(MapKind_ArrayType) || dvander@238: obj->is(MapKind_ReferenceType) || dvander@238: obj->is(MapKind_EnumType)); dvander@238: return (Type *)obj; dvander@238: } dvander@238: dvander@238: bool isPrimitive() { dvander@238: return kind() == PRIMITIVE; dvander@238: } dvander@238: bool isArray() { dvander@238: return kind() == ARRAY || kind() == EXTERNAL_ARRAY; dvander@238: } dvander@238: bool isReference() { dvander@238: return kind() == REFERENCE; dvander@238: } dvander@238: bool isFunction() { dvander@238: return kind() == FUNCTION; dvander@238: } dvander@238: bool isVoid() { dvander@238: return kind() == VOID; dvander@238: } dvander@238: bool isUnchecked() { dvander@238: return kind() == UNCHECKED; dvander@238: } dvander@238: bool isStruct() { dvander@238: return kind() == STRUCT; dvander@238: } dvander@256: bool isImportable() { dvander@256: return kind() == IMPORTABLE; dvander@256: } dvander@238: PrimitiveType primitive() { dvander@238: assert(isPrimitive()); dvander@238: return root_->primitive_; dvander@238: } dvander@238: bool isPod() { dvander@238: return (isPrimitive() && !isString()) || isEnum() || isUnchecked(); dvander@238: } dvander@238: PrimitiveType pod() { dvander@238: assert(isPod()); dvander@238: return isPrimitive() dvander@238: ? (primitive() == PrimitiveType_Bool) dvander@238: ? PrimitiveType_Int32 dvander@238: : primitive() dvander@238: : PrimitiveType_Int32; dvander@238: } dvander@238: bool isChar() { dvander@238: return isPrimitive() && primitive() == PrimitiveType_Char; dvander@238: } dvander@238: bool isFloat() { dvander@238: return isPrimitive() && primitive() == PrimitiveType_Float; dvander@238: } dvander@238: bool isInt32() { dvander@238: return isPrimitive() && primitive() == PrimitiveType_Int32; dvander@238: } dvander@238: bool isInt32OrEnum() { dvander@238: return isInt32() || isEnum(); dvander@238: } dvander@238: bool isBool() { dvander@238: return isPrimitive() && primitive() == PrimitiveType_Bool; dvander@238: } dvander@238: bool isString() { dvander@238: return kind() == STRING; dvander@238: } dvander@238: bool isExternalArray() { dvander@238: return kind() == EXTERNAL_ARRAY; dvander@238: } dvander@238: bool isTraceable() { dvander@238: return kind() >= STRING; dvander@238: } dvander@238: bool isEnum() { dvander@238: return kind() == ENUM; dvander@238: } dvander@238: bool hasTypeQualifiers() { dvander@238: return kind_ == QUALTYPE; dvander@238: } dvander@238: dvander@238: TypeQualifiers quals() { dvander@241: if (!hasTypeQualifiers()) dvander@238: return TypeQual_None; dvander@238: return quals_; dvander@238: } dvander@239: Type *unqualified() { dvander@239: return root_; dvander@239: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfRoot() { dvander@238: return OFFSETOF(Type, root_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@238: protected: dvander@238: Kind kind_; dvander@238: PrimitiveType primitive_; dvander@238: TypeQualifiers quals_; dvander@238: dvander@238: // For unqualified types, this points to |this|. For qualified types, it dvander@238: // points to the unqualified original type. dvander@238: Barriered root_; dvander@238: }; dvander@238: dvander@238: class EnumType : public Type dvander@238: { dvander@238: public: dvander@238: static EnumType *New(Zone *Zone, Handle name); dvander@238: dvander@238: String *name() { dvander@238: return name_; dvander@238: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfName() { dvander@238: return OFFSETOF(EnumType, name_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@238: static EnumType *cast(Object *obj) { dvander@238: assert(!obj || obj->is(MapKind_EnumType)); dvander@238: return (EnumType *)obj; dvander@238: } dvander@238: dvander@238: private: dvander@238: Barriered name_; dvander@238: }; dvander@238: dvander@238: class ReferenceType : public Type dvander@238: { dvander@238: public: dvander@238: static ReferenceType *New(Zone *zone, Handle contained); dvander@238: dvander@238: Type *contained() { dvander@238: return contained_; dvander@238: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfContained() { dvander@238: return OFFSETOF(ReferenceType, contained_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@239: static ReferenceType *cast(Type *obj) { dvander@239: if (!obj) dvander@239: return NULL; dvander@239: obj = obj->unqualified(); dvander@239: assert(obj->is(MapKind_ReferenceType)); dvander@238: return (ReferenceType *)obj; dvander@238: } dvander@238: dvander@238: private: dvander@238: Barriered contained_; dvander@238: }; dvander@238: dvander@238: class ArrayType : public Type dvander@238: { dvander@238: public: dvander@238: static const int DYNAMIC_ARRAY_SIZE = -1; dvander@238: dvander@238: static ArrayType *New(Zone *zone, Handle contained, int elements); dvander@238: static ArrayType *NewExternal(Zone *zone, Handle contained); dvander@238: dvander@238: Type *innermost() { dvander@238: Type *temp = contained(); dvander@238: while (temp->isArray()) dvander@238: temp = ArrayType::cast(temp)->contained(); dvander@238: return temp; dvander@238: } dvander@238: dvander@247: bool isDynamic() { dvander@247: return elements_ == DYNAMIC_ARRAY_SIZE; dvander@247: } dvander@247: bool isExtensible() { dvander@247: return isDynamic() && !(quals_ & TypeQual_Const); dvander@247: } dvander@238: Type *contained() { dvander@238: return contained_; dvander@238: } dvander@238: bool isFixedLength() { dvander@238: return elements_ > 0; dvander@238: } dvander@238: bool isCharArray() { dvander@238: return contained()->isPrimitive() && dvander@238: contained()->primitive() == PrimitiveType_Char; dvander@238: } dvander@238: unsigned fixedLength() { dvander@238: assert(isFixedLength()); dvander@238: return elements_; dvander@238: } dvander@238: unsigned levels() { dvander@238: return levels_; dvander@238: } dvander@238: bool hasInlineElements() { dvander@238: // We don't allocate traceable elements inline, since there's no dvander@238: // point to the optimization; we're going to be allocating lots of dvander@238: // objects anyway (in theory). dvander@238: return isFixedLength() && !contained()->isTraceable(); dvander@238: } dvander@238: dvander@238: // Arrays of this type can be created with this cached map. dvander@238: ArrayMap *newMap() { dvander@238: return newMap_; dvander@238: } dvander@238: void setNewMap(ArrayMap *map) { dvander@238: assert(!newMap()); dvander@238: newMap_ = map; dvander@238: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfContained() { dvander@238: return OFFSETOF(ArrayType, contained_); dvander@238: } dvander@238: static inline size_t offsetOfNewMap() { dvander@238: return OFFSETOF(ArrayType, newMap_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@239: static ArrayType *cast(Type *obj) { dvander@239: if (!obj) dvander@239: return NULL; dvander@239: obj = obj->unqualified(); dvander@239: assert(obj->is(MapKind_ArrayType)); dvander@238: return (ArrayType *)obj; dvander@238: } dvander@238: dvander@238: private: dvander@238: int32 elements_; dvander@238: unsigned levels_; dvander@238: Barriered contained_; dvander@238: Barriered newMap_; dvander@238: }; dvander@238: dvander@238: class StructType : public Type dvander@238: { dvander@238: public: dvander@238: static StructType *New(Zone *zone, Handle name, Handle fields); dvander@238: dvander@238: FixedArray *fields() { dvander@238: assert(isStruct()); dvander@238: return fields_; dvander@238: } dvander@258: Descriptor *lookupField(String *name, unsigned *index = NULL); dvander@238: dvander@238: // Objects of this type can be created with this cached map. dvander@238: StructMap *newMap() { dvander@238: return newMap_; dvander@238: } dvander@238: void setNewMap(StructMap *map) { dvander@238: assert(!newMap()); dvander@238: newMap_ = map; dvander@238: } dvander@238: dvander@238: String *name() { dvander@238: return name_; dvander@238: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfFields() { dvander@238: return OFFSETOF(StructType, fields_); dvander@238: } dvander@238: static inline size_t offsetOfNewMap() { dvander@238: return OFFSETOF(StructType, newMap_); dvander@238: } dvander@238: static inline size_t offsetOfName() { dvander@238: return OFFSETOF(StructType, name_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@239: static StructType *cast(Type *obj) { dvander@239: if (!obj) dvander@239: return NULL; dvander@239: obj = obj->unqualified(); dvander@239: assert(obj->is(MapKind_StructType)); dvander@238: return (StructType *)obj; dvander@238: } dvander@238: dvander@238: private: dvander@238: // Structs only. dvander@238: Barriered fields_; dvander@238: Barriered newMap_; dvander@238: Barriered name_; dvander@238: }; dvander@238: dvander@238: class FunctionType : public Type dvander@238: { dvander@238: public: dvander@238: static FunctionType *New(Zone *zone, Handle name, TokenKind kind); dvander@238: dvander@238: Type *parameterAt(size_t i) { dvander@238: return Type::cast(parameters()->at(i)); dvander@238: } dvander@238: Type *returnType() { dvander@238: assert(isFunction()); dvander@238: return returnType_; dvander@238: } dvander@238: FixedArray *parameters() { dvander@238: assert(isFunction()); dvander@238: return parameters_; dvander@238: } dvander@238: FixedArray *defaults() { dvander@238: assert(isFunction()); dvander@238: return defaults_; dvander@238: } dvander@238: bool isNative() { dvander@238: return token_ == TOK_NATIVE; dvander@238: } dvander@238: bool isForward() { dvander@238: return token_ == TOK_FORWARD; dvander@238: } dvander@238: bool isNativeVariadic() { dvander@238: assert(isNative()); dvander@238: return variadicNative_; dvander@238: } dvander@247: void setVariadic() { dvander@247: assert(isNative()); dvander@247: variadicNative_ = true; dvander@247: } dvander@238: void setReturnType(Handle returnType) { dvander@238: assert(!returnType_); dvander@238: returnType_ = returnType; dvander@238: } dvander@238: void setParameterTypes(Handle types) { dvander@238: assert(!parameters_); dvander@238: parameters_ = types; dvander@238: } dvander@238: TokenKind token() { dvander@238: return token_; dvander@238: } dvander@238: String *name() { dvander@238: return name_; dvander@238: } dvander@238: dvander@238: // GC Descriptor. dvander@238: static inline size_t offsetOfReturnType() { dvander@238: return OFFSETOF(FunctionType, returnType_); dvander@238: } dvander@238: static inline size_t offsetOfParameters() { dvander@238: return OFFSETOF(FunctionType, parameters_); dvander@238: } dvander@238: static inline size_t offsetOfDefaults() { dvander@238: return OFFSETOF(FunctionType, defaults_); dvander@238: } dvander@238: static inline size_t offsetOfName() { dvander@238: return OFFSETOF(FunctionType, name_); dvander@238: } dvander@238: // End GC Descriptor. dvander@238: dvander@239: static FunctionType *cast(Type *obj) { dvander@239: if (!obj) dvander@239: return NULL; dvander@239: obj = obj->unqualified(); dvander@239: assert(obj->is(MapKind_FunctionType)); dvander@238: return (FunctionType *)obj; dvander@238: } dvander@238: dvander@238: private: dvander@238: // Functions only. dvander@238: Barriered returnType_; dvander@238: Barriered parameters_; dvander@238: Barriered defaults_; dvander@238: Barriered name_; dvander@238: TokenKind token_; dvander@238: bool variadicNative_; dvander@238: }; dvander@238: dvander@238: class BoxedPrimitive dvander@238: { dvander@238: PrimitiveType type_; dvander@238: union { dvander@238: int i_; dvander@238: float f_; dvander@238: }; dvander@238: dvander@238: public: dvander@238: static BoxedPrimitive Int(int i) { dvander@238: BoxedPrimitive b; dvander@238: b.type_ = PrimitiveType_Int32; dvander@238: b.i_ = i; dvander@238: return b; dvander@238: } dvander@238: static BoxedPrimitive Float(float f) { dvander@238: BoxedPrimitive b; dvander@238: b.type_ = PrimitiveType_Float; dvander@238: b.f_ = f; dvander@238: return b; dvander@238: } dvander@238: dvander@238: PrimitiveType type() const { dvander@238: return type_; dvander@238: } dvander@238: int toInt() const { dvander@238: assert(type() == PrimitiveType_Int32); dvander@238: return i_; dvander@238: } dvander@238: float toFloat() const { dvander@238: assert(type() == PrimitiveType_Float); dvander@238: return f_; dvander@238: } dvander@238: }; dvander@238: dvander@241: const char *GetTypeName(Type *type, char *buffer, size_t maxlen); dvander@238: dvander@238: } dvander@238: dvander@238: #endif // _include_jc_types_h_