diff -r c77540a61905 -r e9bec7549c28 src/Types.h --- a/src/Types.h Mon Dec 24 16:43:22 2012 -0800 +++ b/src/Types.h Tue Dec 25 16:32:06 2012 -0800 @@ -1,484 +1,535 @@ -/* vim: set ts=4 sw=4 tw=99 et: - * - * Copyright (C) 2012 David Anderson - * - * This file is part of JITCraft. - * - * JITCraft is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * Foobar 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * JITCraft. If not, see http://www.gnu.org/licenses/. - */ -#ifndef _include_jc_types_h_ -#define _include_jc_types_h_ - -#include "Heap.h" -#include "Barriers.h" -#include "FixedArray.h" -#include "compiler/Token.h" - -namespace ke { - -class String; -class Descriptor; -class StructMap; -class ArrayMap; - -#define MAX_ARRAY_DEPTH 5 - -enum PrimitiveType -{ - // A boolean type semantically represents 0 or 1. As an optimization, its - // internal storage type is the same as int32, and any non-zero value - // compares positively to "true". - PrimitiveType_Bool, - - // A character is an arbitrary 8-bit value. Characters are not supported - // as a normal storage class; they may only be used for arrays. When read - // from an array, they are immediately sign extended to 32 bits. Integers - // stored into an char array are truncated to 8 bits. - PrimitiveType_Char, // signed, 8-bit character - - // Enumerations and untyped variables are stored as signed, 32-bit integers. - PrimitiveType_Int32, - - // Floating point values are 32-bit IEEE-754 floats. This is required ro - // SourcePawn 1 compatibility. - PrimitiveType_Float, - - // This is a native-sized integer type (32-bit on 32-bit systems, 64-bit - // on 64-bit systems), and does not exist in language semantics. - PrimitiveType_Native, - - PrimitiveTypes_Total -}; - -class Type : public Object -{ - protected: - enum Kind { - // A primitive is a plain-old-data type. - PRIMITIVE, - - // Void is an internal type used to specify that a function returns no - // value. - VOID, - - // Enums are plain-old-data with int32 storage. They allow for extra - // type checking that would not be possible with integers. - ENUM, - - // Unchecked is a magic type that has implicit, bitwise coercion to - // int32, float, bool, or an enum. - UNCHECKED, - - // ------ Add traceable types below ------- - - // An immutable type that is a primitive in terms of language - // semantics, but gets a special type here to make internal - // logic easier. - STRING, - - // An array is a fixed-length vector of any other type. - ARRAY, - EXTERNAL_ARRAY, - - // A reference type may only be specified on parameters, and - // references may only be computed to primitives or enums. - REFERENCE, - - // A function type encapsulates a function signature. - FUNCTION, - - // Structs are composite records that may contain primitives, arrays, - // functions, enums, and other structs. - STRUCT - }; - - private: - Kind kind() { - return kind_; - } - - public: - static Type *NewVoid(Zone *zone); - static Type *NewUnchecked(Zone *zone); - static Type *NewPrimitive(Zone *zone, PrimitiveType type); - static Type *NewString(Zone *zone); - - static Type *cast(Object *obj) { - assert(!obj || - obj->is(MapKind_Type) || - obj->is(MapKind_FunctionType) || - obj->is(MapKind_StructType) || - obj->is(MapKind_ArrayType) || - obj->is(MapKind_ReferenceType) || - obj->is(MapKind_EnumType)); - return (Type *)obj; - } - - bool isPrimitive() { - return kind() == PRIMITIVE; - } - bool isArray() { - return kind() == ARRAY || kind() == EXTERNAL_ARRAY; - } - bool isReference() { - return kind() == REFERENCE; - } - bool isFunction() { - return kind() == FUNCTION; - } - bool isVoid() { - return kind() == VOID; - } - bool isUnchecked() { - return kind() == UNCHECKED; - } - bool isStruct() { - return kind() == STRUCT; - } - PrimitiveType primitive() { - assert(isPrimitive()); - return primitive_; - } - bool isPod() { - return (isPrimitive() && !isString()) || isEnum() || isUnchecked(); - } - PrimitiveType pod() { - assert(isPod()); - return isPrimitive() - ? (primitive() == PrimitiveType_Bool) - ? PrimitiveType_Int32 - : primitive() - : PrimitiveType_Int32; - } - bool isChar() { - return isPrimitive() && primitive() == PrimitiveType_Char; - } - bool isFloat() { - return isPrimitive() && primitive() == PrimitiveType_Float; - } - bool isInt32() { - return isPrimitive() && primitive() == PrimitiveType_Int32; - } - bool isInt32OrEnum() { - return isInt32() || isEnum(); - } - bool isBool() { - return isPrimitive() && primitive() == PrimitiveType_Bool; - } - bool isString() { - return kind() == STRING; - } - bool isExternalArray() { - return kind() == EXTERNAL_ARRAY; - } - bool isTraceable() { - return kind_ >= STRING; - } - bool isConst() { - assert(isPrimitive() || - isArray() || - isReference()); - return const_; - } - bool isEnum() { - return kind() == ENUM; - } - - protected: - Kind kind_; - PrimitiveType primitive_; - - // Primitives, arrays, and references. - bool const_; -}; - -class EnumType : public Type -{ - public: - static EnumType *New(Zone *Zone, Handle name); - - String *name() { - return name_; - } - - // GC Descriptor. - static inline size_t offsetOfName() { - return OFFSETOF(EnumType, name_); - } - // End GC Descriptor. - - static EnumType *cast(Object *obj) { - assert(!obj || obj->is(MapKind_EnumType)); - return (EnumType *)obj; - } - - private: - Barriered name_; -}; - -class ReferenceType : public Type -{ - public: - static ReferenceType *New(Zone *zone, Handle contained); - - Type *contained() { - return contained_; - } - - // GC Descriptor. - static inline size_t offsetOfContained() { - return OFFSETOF(ReferenceType, contained_); - } - // End GC Descriptor. - - static ReferenceType *cast(Object *obj) { - assert(!obj || obj->is(MapKind_ReferenceType)); - return (ReferenceType *)obj; - } - - private: - Barriered contained_; -}; - -class ArrayType : public Type -{ - public: - static const int DYNAMIC_ARRAY_SIZE = -1; - - static ArrayType *New(Zone *zone, Handle contained, int elements); - static ArrayType *NewExternal(Zone *zone, Handle contained); - - Type *innermost() { - Type *temp = contained(); - while (temp->isArray()) - temp = ArrayType::cast(temp)->contained(); - return temp; - } - - Type *contained() { - return contained_; - } - bool isFixedLength() { - return elements_ > 0; - } - bool isCharArray() { - return contained()->isPrimitive() && - contained()->primitive() == PrimitiveType_Char; - } - unsigned fixedLength() { - assert(isFixedLength()); - return elements_; - } - unsigned levels() { - return levels_; - } - bool hasInlineElements() { - // We don't allocate traceable elements inline, since there's no - // point to the optimization; we're going to be allocating lots of - // objects anyway (in theory). - return isFixedLength() && !contained()->isTraceable(); - } - - // Arrays of this type can be created with this cached map. - ArrayMap *newMap() { - return newMap_; - } - void setNewMap(ArrayMap *map) { - assert(!newMap()); - newMap_ = map; - } - - // GC Descriptor. - static inline size_t offsetOfContained() { - return OFFSETOF(ArrayType, contained_); - } - static inline size_t offsetOfNewMap() { - return OFFSETOF(ArrayType, newMap_); - } - // End GC Descriptor. - - static ArrayType *cast(Object *obj) { - assert(!obj || obj->is(MapKind_ArrayType)); - return (ArrayType *)obj; - } - - private: - int32 elements_; - unsigned levels_; - Barriered contained_; - Barriered newMap_; -}; - -class StructType : public Type -{ - public: - static StructType *New(Zone *zone, Handle name, Handle fields); - - FixedArray *fields() { - assert(isStruct()); - return fields_; - } - Descriptor *lookupField(Handle name, unsigned *index = NULL); - - // Objects of this type can be created with this cached map. - StructMap *newMap() { - return newMap_; - } - void setNewMap(StructMap *map) { - assert(!newMap()); - newMap_ = map; - } - - String *name() { - return name_; - } - - // GC Descriptor. - static inline size_t offsetOfFields() { - return OFFSETOF(StructType, fields_); - } - static inline size_t offsetOfNewMap() { - return OFFSETOF(StructType, newMap_); - } - static inline size_t offsetOfName() { - return OFFSETOF(StructType, name_); - } - // End GC Descriptor. - - static StructType *cast(Object *obj) { - assert(!obj || obj->is(MapKind_StructType)); - return (StructType *)obj; - } - - private: - // Structs only. - Barriered fields_; - Barriered newMap_; - Barriered name_; -}; - -class FunctionType : public Type -{ - public: - static FunctionType *New(Zone *zone, Handle name, TokenKind kind); - - Type *parameterAt(size_t i) { - return Type::cast(parameters()->at(i)); - } - Type *returnType() { - assert(isFunction()); - return returnType_; - } - FixedArray *parameters() { - assert(isFunction()); - return parameters_; - } - FixedArray *defaults() { - assert(isFunction()); - return defaults_; - } - bool isNative() { - return token_ == TOK_NATIVE; - } - bool isForward() { - return token_ == TOK_FORWARD; - } - bool isNativeVariadic() { - assert(isNative()); - return variadicNative_; - } - void setReturnType(Handle returnType) { - assert(!returnType_); - returnType_ = returnType; - } - void setParameterTypes(Handle types) { - assert(!parameters_); - parameters_ = types; - } - TokenKind token() { - return token_; - } - String *name() { - return name_; - } - - // GC Descriptor. - static inline size_t offsetOfReturnType() { - return OFFSETOF(FunctionType, returnType_); - } - static inline size_t offsetOfParameters() { - return OFFSETOF(FunctionType, parameters_); - } - static inline size_t offsetOfDefaults() { - return OFFSETOF(FunctionType, defaults_); - } - static inline size_t offsetOfName() { - return OFFSETOF(FunctionType, name_); - } - // End GC Descriptor. - - static FunctionType *cast(Object *obj) { - assert(!obj || obj->is(MapKind_FunctionType)); - return (FunctionType *)obj; - } - - private: - // Functions only. - Barriered returnType_; - Barriered parameters_; - Barriered defaults_; - Barriered name_; - TokenKind token_; - bool variadicNative_; -}; - -class BoxedPrimitive -{ - PrimitiveType type_; - union { - int i_; - float f_; - }; - - public: - static BoxedPrimitive Int(int i) { - BoxedPrimitive b; - b.type_ = PrimitiveType_Int32; - b.i_ = i; - return b; - } - static BoxedPrimitive Float(float f) { - BoxedPrimitive b; - b.type_ = PrimitiveType_Float; - b.f_ = f; - return b; - } - - PrimitiveType type() const { - return type_; - } - int toInt() const { - assert(type() == PrimitiveType_Int32); - return i_; - } - float toFloat() const { - assert(type() == PrimitiveType_Float); - return f_; - } -}; - -const char *GetTypeName(Type *type); - -} - -#endif // _include_jc_types_h_ +/* vim: set ts=4 sw=4 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of JITCraft. + * + * JITCraft is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Foobar 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * JITCraft. If not, see http://www.gnu.org/licenses/. + */ +#ifndef _include_jc_types_h_ +#define _include_jc_types_h_ + +#include "Heap.h" +#include "Barriers.h" +#include "FixedArray.h" +#include "compiler/Token.h" + +namespace ke { + +class String; +class Descriptor; +class StructMap; +class ArrayMap; + +#define MAX_ARRAY_DEPTH 5 + +enum PrimitiveType +{ + // A boolean type semantically represents 0 or 1. As an optimization, its + // internal storage type is the same as int32, and any non-zero value + // compares positively to "true". + PrimitiveType_Bool, + + // A character is an arbitrary 8-bit value. Characters are not supported + // as a normal storage class; they may only be used for arrays. When read + // from an array, they are immediately sign extended to 32 bits. Integers + // stored into an char array are truncated to 8 bits. + PrimitiveType_Char, // signed, 8-bit character + + // Enumerations and untyped variables are stored as signed, 32-bit integers. + PrimitiveType_Int32, + + // Floating point values are 32-bit IEEE-754 floats. This is required ro + // SourcePawn 1 compatibility. + PrimitiveType_Float, + + // This is a native-sized integer type (32-bit on 32-bit systems, 64-bit + // on 64-bit systems), and does not exist in language semantics. + PrimitiveType_Native, + + PrimitiveTypes_Total +}; + +enum TypeQualifiers +{ + TypeQual_None = 0, + + // Const qualifier that has not been determined yet. + TypeQual_UnkConst = (1 << 0), + + // For simplification, SP2 differentiates between two meanings of const. + // "StoreConst" means that the value itself may not be changed. For + // example, + // const a = 5; + // + // Specifies that the storage of "a" is immutable. + // + // In addition, "RefConst" means that the memory at a reference may not + // be changed. For example, + // + // const char:text[] = "asdfasdfasdf"; + // + // Specifies a readonly view of a character array, however, |text| itself + // may be repointed to another readonly character array. + // + // The meaning of "const" is inferred based on the scope and type: + // + // +---------+---------+-------+ + // | Array | Struct | Other | + // +---------------+---------+---------+-------+ + // | GLOBAL/STATIC | Ref|Str | Ref|Str | Str | + // | LOCAL | Ref | Ref|Str | Str | + // +---------------+---------+---------+-------+ + TypeQual_StoreConst = (1 << 1), + TypeQual_RefConst = (1 << 2) +}; + +class Type : public Object +{ + protected: + enum Kind { + // A primitive is a plain-old-data type. + PRIMITIVE, + + // Void is an internal type used to specify that a function returns no + // value. + VOID, + + // Enums are plain-old-data with int32 storage. They allow for extra + // type checking that would not be possible with integers. + ENUM, + + // Unchecked is a magic type that has implicit, bitwise coercion to + // int32, float, bool, or an enum. + UNCHECKED, + + // ------ Add traceable types below ------- + + // An immutable type that is a primitive in terms of language + // semantics, but gets a special type here to make internal + // logic easier. + STRING, + + // An array is a fixed-length vector of any other type. + ARRAY, + EXTERNAL_ARRAY, + + // A reference type may only be specified on parameters, and + // references may only be computed to primitives or enums. + REFERENCE, + + // A function type encapsulates a function signature. + FUNCTION, + + // Structs are composite records that may contain primitives, arrays, + // functions, enums, and other structs. + STRUCT, + + // Contains type qualifiers, and a back pointer to the actual + // unqualified type. + QUALTYPE + }; + + void init(Kind kind); + + private: + Kind kind() { + return root_->kind_; + } + + public: + static Type *NewVoid(Zone *zone); + static Type *NewUnchecked(Zone *zone); + static Type *NewPrimitive(Zone *zone, PrimitiveType type); + static Type *NewString(Zone *zone); + + static Type *cast(Object *obj) { + assert(!obj || + obj->is(MapKind_Type) || + obj->is(MapKind_FunctionType) || + obj->is(MapKind_StructType) || + obj->is(MapKind_ArrayType) || + obj->is(MapKind_ReferenceType) || + obj->is(MapKind_EnumType)); + return (Type *)obj; + } + + bool isPrimitive() { + return kind() == PRIMITIVE; + } + bool isArray() { + return kind() == ARRAY || kind() == EXTERNAL_ARRAY; + } + bool isReference() { + return kind() == REFERENCE; + } + bool isFunction() { + return kind() == FUNCTION; + } + bool isVoid() { + return kind() == VOID; + } + bool isUnchecked() { + return kind() == UNCHECKED; + } + bool isStruct() { + return kind() == STRUCT; + } + PrimitiveType primitive() { + assert(isPrimitive()); + return root_->primitive_; + } + bool isPod() { + return (isPrimitive() && !isString()) || isEnum() || isUnchecked(); + } + PrimitiveType pod() { + assert(isPod()); + return isPrimitive() + ? (primitive() == PrimitiveType_Bool) + ? PrimitiveType_Int32 + : primitive() + : PrimitiveType_Int32; + } + bool isChar() { + return isPrimitive() && primitive() == PrimitiveType_Char; + } + bool isFloat() { + return isPrimitive() && primitive() == PrimitiveType_Float; + } + bool isInt32() { + return isPrimitive() && primitive() == PrimitiveType_Int32; + } + bool isInt32OrEnum() { + return isInt32() || isEnum(); + } + bool isBool() { + return isPrimitive() && primitive() == PrimitiveType_Bool; + } + bool isString() { + return kind() == STRING; + } + bool isExternalArray() { + return kind() == EXTERNAL_ARRAY; + } + bool isTraceable() { + return kind() >= STRING; + } + bool isEnum() { + return kind() == ENUM; + } + bool hasTypeQualifiers() { + return kind_ == QUALTYPE; + } + + TypeQualifiers quals() { + if (hasTypeQualifiers()) + return TypeQual_None; + return quals_; + } + + // GC Descriptor. + static inline size_t offsetOfRoot() { + return OFFSETOF(Type, root_); + } + // End GC Descriptor. + + protected: + Kind kind_; + PrimitiveType primitive_; + TypeQualifiers quals_; + + // For unqualified types, this points to |this|. For qualified types, it + // points to the unqualified original type. + Barriered root_; +}; + +class EnumType : public Type +{ + public: + static EnumType *New(Zone *Zone, Handle name); + + String *name() { + return name_; + } + + // GC Descriptor. + static inline size_t offsetOfName() { + return OFFSETOF(EnumType, name_); + } + // End GC Descriptor. + + static EnumType *cast(Object *obj) { + assert(!obj || obj->is(MapKind_EnumType)); + return (EnumType *)obj; + } + + private: + Barriered name_; +}; + +class ReferenceType : public Type +{ + public: + static ReferenceType *New(Zone *zone, Handle contained); + + Type *contained() { + return contained_; + } + + // GC Descriptor. + static inline size_t offsetOfContained() { + return OFFSETOF(ReferenceType, contained_); + } + // End GC Descriptor. + + static ReferenceType *cast(Object *obj) { + assert(!obj || obj->is(MapKind_ReferenceType)); + return (ReferenceType *)obj; + } + + private: + Barriered contained_; +}; + +class ArrayType : public Type +{ + public: + static const int DYNAMIC_ARRAY_SIZE = -1; + + static ArrayType *New(Zone *zone, Handle contained, int elements); + static ArrayType *NewExternal(Zone *zone, Handle contained); + + Type *innermost() { + Type *temp = contained(); + while (temp->isArray()) + temp = ArrayType::cast(temp)->contained(); + return temp; + } + + Type *contained() { + return contained_; + } + bool isFixedLength() { + return elements_ > 0; + } + bool isCharArray() { + return contained()->isPrimitive() && + contained()->primitive() == PrimitiveType_Char; + } + unsigned fixedLength() { + assert(isFixedLength()); + return elements_; + } + unsigned levels() { + return levels_; + } + bool hasInlineElements() { + // We don't allocate traceable elements inline, since there's no + // point to the optimization; we're going to be allocating lots of + // objects anyway (in theory). + return isFixedLength() && !contained()->isTraceable(); + } + + // Arrays of this type can be created with this cached map. + ArrayMap *newMap() { + return newMap_; + } + void setNewMap(ArrayMap *map) { + assert(!newMap()); + newMap_ = map; + } + + // GC Descriptor. + static inline size_t offsetOfContained() { + return OFFSETOF(ArrayType, contained_); + } + static inline size_t offsetOfNewMap() { + return OFFSETOF(ArrayType, newMap_); + } + // End GC Descriptor. + + static ArrayType *cast(Object *obj) { + assert(!obj || obj->is(MapKind_ArrayType)); + return (ArrayType *)obj; + } + + private: + int32 elements_; + unsigned levels_; + Barriered contained_; + Barriered newMap_; +}; + +class StructType : public Type +{ + public: + static StructType *New(Zone *zone, Handle name, Handle fields); + + FixedArray *fields() { + assert(isStruct()); + return fields_; + } + Descriptor *lookupField(Handle name, unsigned *index = NULL); + + // Objects of this type can be created with this cached map. + StructMap *newMap() { + return newMap_; + } + void setNewMap(StructMap *map) { + assert(!newMap()); + newMap_ = map; + } + + String *name() { + return name_; + } + + // GC Descriptor. + static inline size_t offsetOfFields() { + return OFFSETOF(StructType, fields_); + } + static inline size_t offsetOfNewMap() { + return OFFSETOF(StructType, newMap_); + } + static inline size_t offsetOfName() { + return OFFSETOF(StructType, name_); + } + // End GC Descriptor. + + static StructType *cast(Object *obj) { + assert(!obj || obj->is(MapKind_StructType)); + return (StructType *)obj; + } + + private: + // Structs only. + Barriered fields_; + Barriered newMap_; + Barriered name_; +}; + +class FunctionType : public Type +{ + public: + static FunctionType *New(Zone *zone, Handle name, TokenKind kind); + + Type *parameterAt(size_t i) { + return Type::cast(parameters()->at(i)); + } + Type *returnType() { + assert(isFunction()); + return returnType_; + } + FixedArray *parameters() { + assert(isFunction()); + return parameters_; + } + FixedArray *defaults() { + assert(isFunction()); + return defaults_; + } + bool isNative() { + return token_ == TOK_NATIVE; + } + bool isForward() { + return token_ == TOK_FORWARD; + } + bool isNativeVariadic() { + assert(isNative()); + return variadicNative_; + } + void setReturnType(Handle returnType) { + assert(!returnType_); + returnType_ = returnType; + } + void setParameterTypes(Handle types) { + assert(!parameters_); + parameters_ = types; + } + TokenKind token() { + return token_; + } + String *name() { + return name_; + } + + // GC Descriptor. + static inline size_t offsetOfReturnType() { + return OFFSETOF(FunctionType, returnType_); + } + static inline size_t offsetOfParameters() { + return OFFSETOF(FunctionType, parameters_); + } + static inline size_t offsetOfDefaults() { + return OFFSETOF(FunctionType, defaults_); + } + static inline size_t offsetOfName() { + return OFFSETOF(FunctionType, name_); + } + // End GC Descriptor. + + static FunctionType *cast(Object *obj) { + assert(!obj || obj->is(MapKind_FunctionType)); + return (FunctionType *)obj; + } + + private: + // Functions only. + Barriered returnType_; + Barriered parameters_; + Barriered defaults_; + Barriered name_; + TokenKind token_; + bool variadicNative_; +}; + +class BoxedPrimitive +{ + PrimitiveType type_; + union { + int i_; + float f_; + }; + + public: + static BoxedPrimitive Int(int i) { + BoxedPrimitive b; + b.type_ = PrimitiveType_Int32; + b.i_ = i; + return b; + } + static BoxedPrimitive Float(float f) { + BoxedPrimitive b; + b.type_ = PrimitiveType_Float; + b.f_ = f; + return b; + } + + PrimitiveType type() const { + return type_; + } + int toInt() const { + assert(type() == PrimitiveType_Int32); + return i_; + } + float toFloat() const { + assert(type() == PrimitiveType_Float); + return f_; + } +}; + +const char *GetTypeName(Type *type); + +} + +#endif // _include_jc_types_h_