src/Types.h
author Michael Busby <prodigysim@gmail.com>
Mon Jun 10 01:50:18 2013 +0100 (2013-06-10)
changeset 264 70b8f318c379
parent 261 219b49bf4a03
permissions -rw-r--r--
Parse assignment RTL instead of LTR, fixes multiple assignment (bug 5420).
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #ifndef _include_jc_types_h_
    20 #define _include_jc_types_h_
    21 
    22 #include "Heap.h"
    23 #include "Barriers.h"
    24 #include "FixedArray.h"
    25 #include "compiler/Token.h"
    26 
    27 namespace ke {
    28 
    29 class String;
    30 class Descriptor;
    31 class StructMap;
    32 class ArrayMap;
    33 
    34 #define MAX_ARRAY_DEPTH     5
    35 
    36 enum PrimitiveType
    37 {
    38     // A boolean type semantically represents 0 or 1. As an optimization, its
    39     // internal storage type is the same as int32, and any non-zero value
    40     // compares positively to "true".
    41     PrimitiveType_Bool,
    42 
    43     // A character is an arbitrary 8-bit value. Characters are not supported
    44     // as a normal storage class; they may only be used for arrays. When read
    45     // from an array, they are immediately sign extended to 32 bits. Integers
    46     // stored into an char array are truncated to 8 bits.
    47     PrimitiveType_Char,         // signed, 8-bit character
    48 
    49     // Enumerations and untyped variables are stored as signed, 32-bit integers.
    50     PrimitiveType_Int32,
    51 
    52     // Floating point values are 32-bit IEEE-754 floats. This is required ro
    53     // SourcePawn 1 compatibility.
    54     PrimitiveType_Float,
    55 
    56     // This is a native-sized integer type (32-bit on 32-bit systems, 64-bit
    57     // on 64-bit systems), and does not exist in language semantics.
    58     PrimitiveType_Native,
    59 
    60     PrimitiveTypes_Total
    61 };
    62 
    63 enum TypeQualifiers
    64 {
    65     TypeQual_None           = 0,
    66 
    67     // Values of this type cannot be modified.
    68     TypeQual_Const       = (1 << 0),
    69 
    70     // Values of this type can be treated as constant expressions. This allows
    71     // us to export compile-time constants from modules.
    72     TypeQual_ConstExpr   = (1 << 1)
    73 };
    74 
    75 class Type : public Object
    76 {
    77   protected:
    78     enum Kind {
    79         // A primitive is a plain-old-data type.
    80         PRIMITIVE,
    81 
    82         // Void is an internal type used to specify that a function returns no
    83         // value.
    84         VOID,
    85 
    86         // Enums are plain-old-data with int32 storage. They allow for extra
    87         // type checking that would not be possible with integers.
    88         ENUM,
    89 
    90         // Unchecked is a magic type that has implicit, bitwise coercion to
    91         // int32, float, bool, or an enum.
    92         UNCHECKED,
    93 
    94         // Contains type qualifiers, and a back pointer to the actual
    95         // unqualified type.
    96         QUALTYPE,
    97 
    98         // ------ Add traceable types below (STRING FIRST!) -------
    99 
   100         // An immutable type that is a primitive in terms of language
   101         // semantics, but gets a special type here to make internal
   102         // logic easier.
   103         STRING,
   104 
   105         // An array is a fixed-length vector of any other type.
   106         ARRAY,
   107         EXTERNAL_ARRAY,
   108 
   109         // A reference type may only be specified on parameters, and
   110         // references may only be computed to primitives or enums.
   111         REFERENCE,
   112 
   113         // A function type encapsulates a function signature.
   114         FUNCTION,
   115 
   116         // Structs are composite records that may contain primitives, arrays,
   117         // functions, enums, and other structs.
   118         STRUCT,
   119 
   120         // Importable types are mainly used during the compilation process
   121         // to distinguish between normal names and static imports.
   122         IMPORTABLE,
   123 
   124         // The type of types.
   125         TYPE
   126     };
   127 
   128     void init(Kind kind, Type *root = NULL);
   129 
   130   private:
   131     Kind kind() {
   132         return root_->kind_;
   133     }
   134 
   135   public:   
   136     static Type *NewVoid(Zone *zone);
   137     static Type *NewUnchecked(Zone *zone);
   138     static Type *NewType(Zone *zone);
   139     static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   140     static Type *NewString(Zone *zone);
   141     static Type *NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> type);
   142     static Type *NewImportable(Zone *zone);
   143 
   144     static Type *cast(Object *obj) {
   145         assert(!obj ||
   146                obj->is(MapKind_Type) ||
   147                obj->is(MapKind_FunctionType) ||
   148                obj->is(MapKind_StructType) ||
   149                obj->is(MapKind_ArrayType) ||
   150                obj->is(MapKind_ReferenceType) ||
   151                obj->is(MapKind_EnumType));
   152         return (Type *)obj;
   153     }
   154 
   155     bool isPrimitive() {
   156         return kind() == PRIMITIVE;
   157     }
   158     bool isArray() {
   159         return kind() == ARRAY || kind() == EXTERNAL_ARRAY;
   160     }
   161     bool isReference() {
   162         return kind() == REFERENCE;
   163     }
   164     bool isFunction() {
   165         return kind() == FUNCTION;
   166     }
   167     bool isVoid() {
   168         return kind() == VOID;
   169     }
   170     bool isUnchecked() {
   171         return kind() == UNCHECKED;
   172     }
   173     bool isStruct() {
   174         return kind() == STRUCT;
   175     }
   176     bool isImportable() {
   177         return kind() == IMPORTABLE;
   178     }
   179     PrimitiveType primitive() {
   180         assert(isPrimitive());
   181         return root_->primitive_;
   182     }
   183     bool isPod() {
   184         return (isPrimitive() && !isString()) || isEnum() || isUnchecked();
   185     }
   186     PrimitiveType pod() {
   187         assert(isPod());
   188         return isPrimitive()
   189                ? (primitive() == PrimitiveType_Bool)
   190                  ? PrimitiveType_Int32
   191                  : primitive()
   192                : PrimitiveType_Int32;
   193     }
   194     bool isChar() {
   195         return isPrimitive() && primitive() == PrimitiveType_Char;
   196     }
   197     bool isFloat() {
   198         return isPrimitive() && primitive() == PrimitiveType_Float;
   199     }
   200     bool isInt32() {
   201         return isPrimitive() && primitive() == PrimitiveType_Int32;
   202     }
   203     bool isInt32OrEnum() {
   204         return isInt32() || isEnum();
   205     }
   206     bool isBool() {
   207         return isPrimitive() && primitive() == PrimitiveType_Bool;
   208     }
   209     bool isString() {
   210         return kind() == STRING;
   211     }
   212     bool isExternalArray() {
   213         return kind() == EXTERNAL_ARRAY;
   214     }
   215     bool isTraceable() {
   216         return kind() >= STRING;
   217     }
   218     bool isEnum() {
   219         return kind() == ENUM;
   220     }
   221     bool isType() {
   222         return kind() == TYPE;
   223     }
   224     bool hasTypeQualifiers() {
   225         return kind_ == QUALTYPE;
   226     }
   227 
   228     TypeQualifiers quals() {
   229         if (!hasTypeQualifiers())
   230             return TypeQual_None;
   231         return quals_;
   232     }
   233     Type *unqualified() {
   234         return root_;
   235     }
   236 
   237     // GC Descriptor.
   238     static inline size_t offsetOfRoot() {
   239         return OFFSETOF(Type, root_);
   240     }
   241     // End GC Descriptor.
   242 
   243   protected:
   244     Kind kind_;
   245     PrimitiveType primitive_;
   246     TypeQualifiers quals_;
   247 
   248     // For unqualified types, this points to |this|. For qualified types, it
   249     // points to the unqualified original type.
   250     Barriered<Type> root_;
   251 };
   252 
   253 class EnumType : public Type
   254 {
   255   public:
   256     static EnumType *New(Zone *Zone, Handle<String> name);
   257 
   258     String *name() {
   259         return name_;
   260     }
   261 
   262     // GC Descriptor.
   263     static inline size_t offsetOfName() {
   264         return OFFSETOF(EnumType, name_);
   265     }
   266     static inline size_t offsetOfFields() {
   267         return OFFSETOF(EnumType, fields_);
   268     }
   269     // End GC Descriptor.
   270 
   271     static EnumType *cast(Object *obj) {
   272         assert(!obj || obj->is(MapKind_EnumType));
   273         return (EnumType *)obj;
   274     }
   275 
   276   private:
   277     Barriered<String> name_;
   278     Barriered<FixedArray> fields_;
   279 };
   280 
   281 class ReferenceType : public Type
   282 {
   283   public:
   284     static ReferenceType *New(Zone *zone, Handle<Type> contained);
   285     
   286     Type *contained() {
   287         return contained_;
   288     }
   289 
   290     // GC Descriptor.
   291     static inline size_t offsetOfContained() {
   292         return OFFSETOF(ReferenceType, contained_);
   293     }
   294     // End GC Descriptor.
   295 
   296     static ReferenceType *cast(Type *obj) {
   297         if (!obj)
   298             return NULL;
   299         obj = obj->unqualified();
   300         assert(obj->is(MapKind_ReferenceType));
   301         return (ReferenceType *)obj;
   302     }
   303 
   304   private:
   305     Barriered<Type> contained_;
   306 };
   307 
   308 class ArrayType : public Type
   309 {
   310   public:
   311     static const int DYNAMIC_ARRAY_SIZE = -1;
   312 
   313     static ArrayType *New(Zone *zone, Handle<Type> contained, int elements);
   314     static ArrayType *NewExternal(Zone *zone, Handle<Type> contained);
   315 
   316     Type *innermost() {
   317         Type *temp = contained();
   318         while (temp->isArray())
   319             temp = ArrayType::cast(temp)->contained();
   320         return temp;
   321     }
   322 
   323     bool isDynamic() {
   324         return elements_ == DYNAMIC_ARRAY_SIZE;
   325     }
   326     bool isExtensible() {
   327         return isDynamic() && !(quals_ & TypeQual_Const);
   328     }
   329     Type *contained() {
   330         return contained_;
   331     }
   332     bool isFixedLength() {
   333         return elements_ > 0;
   334     }
   335     bool isCharArray() {
   336         return contained()->isPrimitive() &&
   337                contained()->primitive() == PrimitiveType_Char;
   338     }
   339     unsigned fixedLength() {
   340         assert(isFixedLength());
   341         return elements_;
   342     }
   343     unsigned levels() {
   344         return levels_;
   345     }
   346     bool hasInlineElements() {
   347         // We don't allocate traceable elements inline, since there's no
   348         // point to the optimization; we're going to be allocating lots of
   349         // objects anyway (in theory).
   350         return isFixedLength() && !contained()->isTraceable();
   351     }
   352 
   353     // Arrays of this type can be created with this cached map.
   354     ArrayMap *newMap() {
   355         return newMap_;
   356     }
   357     void setNewMap(ArrayMap *map) {
   358         assert(!newMap());
   359         newMap_ = map;
   360     }
   361 
   362     // GC Descriptor.
   363     static inline size_t offsetOfContained() {
   364         return OFFSETOF(ArrayType, contained_);
   365     }
   366     static inline size_t offsetOfNewMap() {
   367         return OFFSETOF(ArrayType, newMap_);
   368     }
   369     // End GC Descriptor.
   370 
   371     static ArrayType *cast(Type *obj) {
   372         if (!obj)
   373             return NULL;
   374         obj = obj->unqualified();
   375         assert(obj->is(MapKind_ArrayType));
   376         return (ArrayType *)obj;
   377     }
   378 
   379   private:
   380     int32 elements_;
   381     unsigned levels_;
   382     Barriered<Type> contained_;
   383     Barriered<ArrayMap> newMap_;
   384 };
   385 
   386 class StructType : public Type
   387 {
   388   public:
   389     static StructType *New(Zone *zone, Handle<String> name, Handle<FixedArray> fields);
   390 
   391     FixedArray *fields() {
   392         assert(isStruct());
   393         return fields_;
   394     }
   395     Descriptor *lookupField(String *name, unsigned *index = NULL);
   396 
   397     // Objects of this type can be created with this cached map.
   398     StructMap *newMap() {
   399         return newMap_;
   400     }
   401     void setNewMap(StructMap *map) {
   402         assert(!newMap());
   403         newMap_ = map;
   404     }
   405 
   406     String *name() {
   407         return name_;
   408     }
   409 
   410     // GC Descriptor.
   411     static inline size_t offsetOfFields() {
   412         return OFFSETOF(StructType, fields_);
   413     }
   414     static inline size_t offsetOfNewMap() {
   415         return OFFSETOF(StructType, newMap_);
   416     }
   417     static inline size_t offsetOfName() {
   418         return OFFSETOF(StructType, name_);
   419     }
   420     // End GC Descriptor.
   421 
   422     static StructType *cast(Type *obj) {
   423         if (!obj)
   424             return NULL;
   425         obj = obj->unqualified();
   426         assert(obj->is(MapKind_StructType));
   427         return (StructType *)obj;
   428     }
   429 
   430   private:
   431     // Structs only.
   432     Barriered<FixedArray> fields_;
   433     Barriered<StructMap> newMap_;
   434     Barriered<String> name_;
   435 };
   436 
   437 class FunctionType : public Type
   438 {
   439   public:
   440     static FunctionType *New(Zone *zone, Handle<String> name, TokenKind kind);
   441 
   442     Type *parameterAt(size_t i) {
   443         return Type::cast(parameters()->at(i));
   444     }
   445     Type *returnType() {
   446         assert(isFunction());
   447         return returnType_;
   448     }
   449     FixedArray *parameters() {
   450         assert(isFunction());
   451         return parameters_;
   452     }
   453     FixedArray *defaults() {
   454         assert(isFunction());
   455         return defaults_;
   456     }
   457     bool isNative() {
   458         return token_ == TOK_NATIVE;
   459     }
   460     bool isForward() {
   461         return token_ == TOK_FORWARD;
   462     }
   463     bool isNativeVariadic() {
   464         assert(isNative());
   465         return variadicNative_;
   466     }
   467     void setVariadic() {
   468         assert(isNative());
   469         variadicNative_ = true;
   470     }
   471     void setReturnType(Handle<Type> returnType) {
   472         assert(!returnType_);
   473         returnType_ = returnType;
   474     }
   475     void setParameterTypes(Handle<FixedArray> types) {
   476         assert(!parameters_);
   477         parameters_ = types;
   478     }
   479     TokenKind token() {
   480         return token_;
   481     }
   482     String *name() {
   483         return name_;
   484     }
   485 
   486     // GC Descriptor.
   487     static inline size_t offsetOfReturnType() {
   488         return OFFSETOF(FunctionType, returnType_);
   489     }
   490     static inline size_t offsetOfParameters() {
   491         return OFFSETOF(FunctionType, parameters_);
   492     }
   493     static inline size_t offsetOfDefaults() {
   494         return OFFSETOF(FunctionType, defaults_);
   495     }
   496     static inline size_t offsetOfName() {
   497         return OFFSETOF(FunctionType, name_);
   498     }
   499     // End GC Descriptor.
   500 
   501     static FunctionType *cast(Type *obj) {
   502         if (!obj)
   503             return NULL;
   504         obj = obj->unqualified();
   505         assert(obj->is(MapKind_FunctionType));
   506         return (FunctionType *)obj;
   507     }
   508 
   509   private:
   510     // Functions only.
   511     Barriered<Type> returnType_;
   512     Barriered<FixedArray> parameters_;
   513     Barriered<FixedArray> defaults_;
   514     Barriered<String> name_;
   515     TokenKind token_;
   516     bool variadicNative_;
   517 };
   518 
   519 class BoxedPrimitive
   520 {
   521     PrimitiveType type_;
   522     union {
   523         int i_;
   524         float f_;
   525     };
   526 
   527   public:
   528     static BoxedPrimitive Int(int i) {
   529         BoxedPrimitive b;
   530         b.type_ = PrimitiveType_Int32;
   531         b.i_ = i;
   532         return b;
   533     }
   534     static BoxedPrimitive Float(float f) {
   535         BoxedPrimitive b;
   536         b.type_ = PrimitiveType_Float;
   537         b.f_ = f;
   538         return b;
   539     }
   540 
   541     PrimitiveType type() const {
   542         return type_;
   543     }
   544     int toInt() const {
   545         assert(type() == PrimitiveType_Int32);
   546         return i_;
   547     }
   548     float toFloat() const {
   549         assert(type() == PrimitiveType_Float);
   550         return f_;
   551     }
   552 };
   553 
   554 const char *GetTypeName(Type *type, char *buffer, size_t maxlen);
   555 
   556 }
   557 
   558 #endif // _include_jc_types_h_