dvander@44: /* vim: set ts=4 sw=4 tw=99 et: dvander@44: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: #ifndef _include_jc_types_h_ dvander@0: #define _include_jc_types_h_ dvander@0: dvander@11: #include "Heap.h" dvander@13: #include "Barriers.h" dvander@14: #include "FixedArray.h" dvander@195: #include "compiler/Token.h" dvander@0: dvander@59: namespace ke { dvander@0: dvander@54: class String; dvander@148: class Descriptor; dvander@195: class StructMap; dvander@209: class ArrayMap; dvander@54: dvander@187: #define MAX_ARRAY_DEPTH 5 dvander@187: dvander@0: enum PrimitiveType dvander@0: { dvander@145: // A boolean type semantically represents 0 or 1. As an optimization, its dvander@145: // internal storage type is the same as int32, and any non-zero value dvander@145: // compares positively to "true". dvander@145: PrimitiveType_Bool, dvander@145: dvander@145: // A character is an arbitrary 8-bit value. Characters are not supported dvander@145: // as a normal storage class; they may only be used for arrays. When read dvander@145: // from an array, they are immediately sign extended to 32 bits. Integers dvander@145: // stored into an char array are truncated to 8 bits. dvander@21: PrimitiveType_Char, // signed, 8-bit character dvander@145: dvander@145: // Enumerations and untyped variables are stored as signed, 32-bit integers. dvander@145: PrimitiveType_Int32, dvander@145: dvander@145: // Floating point values are 32-bit IEEE-754 floats. This is required ro dvander@145: // SourcePawn 1 compatibility. dvander@145: PrimitiveType_Float, dvander@145: dvander@145: // This is a native-sized integer type (32-bit on 32-bit systems, 64-bit dvander@145: // on 64-bit systems), and does not exist in language semantics. dvander@145: PrimitiveType_Native, dvander@145: dvander@11: PrimitiveTypes_Total dvander@0: }; dvander@0: dvander@12: class Type : public Object dvander@0: { dvander@195: protected: dvander@0: enum Kind { dvander@167: // A primitive is a plain-old-data type. dvander@0: PRIMITIVE, dvander@167: dvander@167: // An array is a fixed-length vector of any other type. dvander@14: ARRAY, dvander@188: EXTERNAL_ARRAY, dvander@167: dvander@167: // A reference type may only be specified on parameters, and dvander@167: // references may only be computed to primitives or enums. dvander@14: REFERENCE, dvander@167: dvander@167: // A function type encapsulates a function signature. dvander@68: FUNCTION, dvander@167: dvander@167: // Void is an internal type used to specify that a function returns no dvander@167: // value. dvander@145: VOID, dvander@167: dvander@167: // Enums are plain-old-data with int32 storage. They allow for extra dvander@167: // type checking that would not be possible with integers. dvander@146: ENUM, dvander@167: dvander@167: // Structs are composite records that may contain primitives, arrays, dvander@167: // functions, enums, and other structs. dvander@167: STRUCT, dvander@167: dvander@167: // Unchecked is a magic type that has implicit, bitwise coercion to dvander@167: // int32, float, bool, or an enum. dvander@167: UNCHECKED dvander@0: }; dvander@0: dvander@11: private: dvander@11: Kind kind() { dvander@13: return kind_; dvander@11: } dvander@11: dvander@212: public: dvander@71: static Type *NewVoid(Zone *zone); dvander@167: static Type *NewUnchecked(Zone *zone); dvander@12: static Type *NewPrimitive(Zone *zone, PrimitiveType type); dvander@67: static Type *NewReference(Zone *zone, Handle contained, bool isConst); dvander@145: static Type *NewEnum(Zone *zone, Handle name); dvander@0: dvander@63: static bool Compare(Type *left, Type *right); dvander@63: dvander@11: static Type *cast(Object *obj) { dvander@195: assert(!obj || dvander@195: obj->is(MapKind_Type) || dvander@195: obj->is(MapKind_FunctionType) || dvander@209: obj->is(MapKind_StructType) || dvander@209: obj->is(MapKind_ArrayType)); dvander@11: return (Type *)obj; dvander@0: } dvander@11: dvander@11: bool isPrimitive() { dvander@11: return kind() == PRIMITIVE; dvander@11: } dvander@11: bool isArray() { dvander@188: return kind() == ARRAY || kind() == EXTERNAL_ARRAY; dvander@0: } dvander@14: bool isReference() { dvander@14: return kind() == REFERENCE; dvander@14: } dvander@14: bool isFunction() { dvander@195: return kind() == FUNCTION; dvander@68: } dvander@71: bool isVoid() { dvander@71: return kind() == VOID; dvander@71: } dvander@167: bool isUnchecked() { dvander@167: return kind() == UNCHECKED; dvander@167: } dvander@147: bool isStruct() { dvander@147: return kind() == STRUCT; dvander@147: } dvander@11: PrimitiveType primitive() { dvander@0: assert(isPrimitive()); dvander@13: return primitive_; dvander@0: } dvander@168: bool isPod() { dvander@168: return isPrimitive() || isEnum() || isUnchecked(); dvander@168: } dvander@145: PrimitiveType pod() { dvander@168: assert(isPod()); dvander@145: return isPrimitive() dvander@152: ? (primitive() == PrimitiveType_Bool) dvander@152: ? PrimitiveType_Int32 dvander@152: : primitive() dvander@145: : PrimitiveType_Int32; dvander@145: } dvander@212: bool isChar() { dvander@212: return isPrimitive() && primitive() == PrimitiveType_Char; dvander@212: } dvander@11: bool isFloat() { dvander@4: return isPrimitive() && primitive() == PrimitiveType_Float; dvander@4: } dvander@20: bool isInt32() { dvander@4: return isPrimitive() && primitive() == PrimitiveType_Int32; dvander@4: } dvander@145: bool isInt32OrEnum() { dvander@145: return isInt32() || isEnum(); dvander@145: } dvander@147: bool isBool() { dvander@147: return isPrimitive() && primitive() == PrimitiveType_Bool; dvander@147: } dvander@188: bool isExternalArray() { dvander@188: return kind() == EXTERNAL_ARRAY; dvander@188: } dvander@47: bool isTraceable() { dvander@47: return !isPrimitive(); dvander@47: } dvander@67: bool isConst() { dvander@188: assert(isPrimitive() || dvander@188: isArray() || dvander@188: isReference()); dvander@67: return const_; dvander@67: } dvander@145: bool isEnum() { dvander@145: return kind() == ENUM; dvander@145: } dvander@145: dvander@145: String *name() { dvander@147: assert(isEnum() || isStruct()); dvander@145: return name_; dvander@145: } dvander@209: Type *contained_ref() { dvander@195: assert(false); dvander@195: return NULL; dvander@148: } dvander@147: dvander@44: // GC Descriptor. dvander@145: static inline size_t offsetOfName() { dvander@145: return OFFSETOF(Type, name_); dvander@54: } dvander@44: // End GC Descriptor. dvander@44: dvander@195: protected: dvander@13: Kind kind_; dvander@13: PrimitiveType primitive_; dvander@0: dvander@67: // Primitives, arrays, and references. dvander@67: bool const_; dvander@67: dvander@209: // Enums and structs only. dvander@209: Barriered name_; dvander@209: }; dvander@209: dvander@209: class ArrayType : public Type dvander@209: { dvander@209: public: dvander@212: static const int DYNAMIC_ARRAY_SIZE = -1; dvander@212: dvander@209: static ArrayType *New(Zone *zone, Handle contained, int elements); dvander@209: static ArrayType *NewExternal(Zone *zone, Handle contained); dvander@209: dvander@209: Type *innermost() { dvander@209: assert(isArray()); dvander@209: Type *temp = contained(); dvander@209: while (temp->isArray()) dvander@209: temp = ArrayType::cast(temp)->contained(); dvander@209: return temp; dvander@209: } dvander@209: dvander@209: Type *contained() { dvander@209: return contained_; dvander@209: } dvander@209: bool isFixedLength() { dvander@209: assert(isArray()); dvander@209: return elements_ > 0; dvander@209: } dvander@209: bool isCharArray() { dvander@209: return contained()->isPrimitive() && dvander@209: contained()->primitive() == PrimitiveType_Char; dvander@209: } dvander@209: unsigned fixedLength() { dvander@209: assert(isFixedLength()); dvander@209: return elements_; dvander@209: } dvander@209: unsigned levels() { dvander@209: assert(isArray()); dvander@209: return levels_; dvander@209: } dvander@209: bool hasInlineElements() { dvander@209: assert(isArray()); dvander@209: dvander@209: // We don't allocate traceable elements inline, since there's no dvander@209: // point to the optimization; we're going to be allocating lots of dvander@209: // objects anyway (in theory). dvander@209: return isFixedLength() && !contained()->isTraceable(); dvander@209: } dvander@209: dvander@209: // Arrays of this type can be created with this cached map. dvander@209: ArrayMap *newMap() { dvander@209: return newMap_; dvander@209: } dvander@209: void setNewMap(ArrayMap *map) { dvander@209: assert(!newMap()); dvander@209: newMap_ = map; dvander@209: } dvander@209: dvander@209: // GC Descriptor. dvander@209: static inline size_t offsetOfContained() { dvander@209: return OFFSETOF(ArrayType, contained_); dvander@209: } dvander@209: static inline size_t offsetOfNewMap() { dvander@209: return OFFSETOF(ArrayType, newMap_); dvander@209: } dvander@209: // End GC Descriptor. dvander@209: dvander@209: static ArrayType *cast(Object *obj) { dvander@209: assert(!obj || obj->is(MapKind_ArrayType)); dvander@209: return (ArrayType *)obj; dvander@209: } dvander@209: dvander@209: private: dvander@13: int32 elements_; dvander@13: unsigned levels_; dvander@13: Barriered contained_; dvander@209: Barriered newMap_; dvander@195: }; dvander@195: dvander@195: class StructType : public Type dvander@195: { dvander@195: public: dvander@195: static StructType *New(Zone *zone, Handle name, Handle fields); dvander@195: dvander@195: FixedArray *fields() { dvander@195: assert(isStruct()); dvander@195: return fields_; dvander@195: } dvander@195: Descriptor *lookupField(Handle name, unsigned *index = NULL); dvander@195: dvander@195: // Objects of this type can be created with this cached map. dvander@195: StructMap *newMap() { dvander@195: return newMap_; dvander@195: } dvander@195: void setNewMap(StructMap *map) { dvander@195: assert(!newMap()); dvander@195: newMap_ = map; dvander@195: } dvander@195: dvander@195: // GC Descriptor. dvander@195: static inline size_t offsetOfFields() { dvander@195: return OFFSETOF(StructType, fields_); dvander@195: } dvander@195: static inline size_t offsetOfNewMap() { dvander@195: return OFFSETOF(StructType, newMap_); dvander@195: } dvander@195: // End GC Descriptor. dvander@195: dvander@195: static StructType *cast(Object *obj) { dvander@195: assert(!obj || obj->is(MapKind_StructType)); dvander@195: return (StructType *)obj; dvander@195: } dvander@195: dvander@195: private: dvander@195: // Structs only. dvander@195: Barriered fields_; dvander@195: Barriered newMap_; dvander@195: }; dvander@195: dvander@195: class FunctionType : public Type dvander@195: { dvander@195: public: dvander@195: static FunctionType *New(Zone *zone, TokenKind kind); dvander@195: dvander@195: Type *parameterAt(size_t i) { dvander@195: return Type::cast(parameters()->at(i)); dvander@195: } dvander@195: Type *returnType() { dvander@195: assert(isFunction()); dvander@195: return returnType_; dvander@195: } dvander@195: FixedArray *parameters() { dvander@195: assert(isFunction()); dvander@195: return parameters_; dvander@195: } dvander@195: FixedArray *defaults() { dvander@195: assert(isFunction()); dvander@195: return defaults_; dvander@195: } dvander@195: bool isNative() { dvander@195: return token_ == TOK_NATIVE; dvander@195: } dvander@195: bool isForward() { dvander@195: return token_ == TOK_FORWARD; dvander@195: } dvander@195: bool isNativeVariadic() { dvander@195: assert(isNative()); dvander@195: return variadicNative_; dvander@195: } dvander@195: void setReturnType(Handle returnType) { dvander@195: assert(!returnType_); dvander@195: returnType_ = returnType; dvander@195: } dvander@195: void setParameterTypes(Handle types) { dvander@195: assert(!parameters_); dvander@195: parameters_ = types; dvander@195: } dvander@195: TokenKind token() { dvander@195: return token_; dvander@195: } dvander@195: dvander@195: // GC Descriptor. dvander@195: static inline size_t offsetOfReturnType() { dvander@195: return OFFSETOF(FunctionType, returnType_); dvander@195: } dvander@195: static inline size_t offsetOfParameters() { dvander@195: return OFFSETOF(FunctionType, parameters_); dvander@195: } dvander@195: static inline size_t offsetOfDefaults() { dvander@195: return OFFSETOF(FunctionType, defaults_); dvander@195: } dvander@195: // End GC Descriptor. dvander@195: dvander@195: static FunctionType *cast(Object *obj) { dvander@195: assert(!obj || obj->is(MapKind_FunctionType)); dvander@195: return (FunctionType *)obj; dvander@195: } dvander@195: dvander@195: private: dvander@14: // Functions only. dvander@14: Barriered returnType_; dvander@14: Barriered parameters_; dvander@168: Barriered defaults_; dvander@195: TokenKind token_; dvander@68: bool variadicNative_; dvander@0: }; dvander@0: dvander@2: class BoxedPrimitive dvander@2: { dvander@2: PrimitiveType type_; dvander@2: union { dvander@2: int i_; dvander@172: float f_; dvander@2: }; dvander@2: dvander@2: public: dvander@2: static BoxedPrimitive Int(int i) { dvander@2: BoxedPrimitive b; dvander@2: b.type_ = PrimitiveType_Int32; dvander@2: b.i_ = i; dvander@2: return b; dvander@2: } dvander@172: static BoxedPrimitive Float(float f) { dvander@168: BoxedPrimitive b; dvander@172: b.type_ = PrimitiveType_Float; dvander@172: b.f_ = f; dvander@168: return b; dvander@168: } dvander@2: dvander@2: PrimitiveType type() const { dvander@2: return type_; dvander@2: } dvander@2: int toInt() const { dvander@2: assert(type() == PrimitiveType_Int32); dvander@2: return i_; dvander@2: } dvander@172: float toFloat() const { dvander@172: assert(type() == PrimitiveType_Float); dvander@172: return f_; dvander@168: } dvander@2: }; dvander@2: dvander@195: const char *GetTypeName(Type *type); dvander@195: dvander@0: } dvander@0: dvander@0: #endif // _include_jc_types_h_