src/Types.h
author David Anderson <dvander@alliedmods.net>
Tue Jan 01 20:07:09 2013 -0800 (2013-01-01)
changeset 254 cd167be62cbe
parent 247 7721042bdb67
child 256 3c184218462d
permissions -rw-r--r--
Fix Linux build.
     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 << 2)
    69 };
    70 
    71 class Type : public Object
    72 {
    73   protected:
    74     enum Kind {
    75         // A primitive is a plain-old-data type.
    76         PRIMITIVE,
    77 
    78         // Void is an internal type used to specify that a function returns no
    79         // value.
    80         VOID,
    81 
    82         // Enums are plain-old-data with int32 storage. They allow for extra
    83         // type checking that would not be possible with integers.
    84         ENUM,
    85 
    86         // Unchecked is a magic type that has implicit, bitwise coercion to
    87         // int32, float, bool, or an enum.
    88         UNCHECKED,
    89 
    90         // Contains type qualifiers, and a back pointer to the actual
    91         // unqualified type.
    92         QUALTYPE,
    93 
    94         // ------ Add traceable types below (STRING FIRST!) -------
    95 
    96         // An immutable type that is a primitive in terms of language
    97         // semantics, but gets a special type here to make internal
    98         // logic easier.
    99         STRING,
   100 
   101         // An array is a fixed-length vector of any other type.
   102         ARRAY,
   103         EXTERNAL_ARRAY,
   104 
   105         // A reference type may only be specified on parameters, and
   106         // references may only be computed to primitives or enums.
   107         REFERENCE,
   108 
   109         // A function type encapsulates a function signature.
   110         FUNCTION,
   111 
   112         // Structs are composite records that may contain primitives, arrays,
   113         // functions, enums, and other structs.
   114         STRUCT
   115     };
   116 
   117     void init(Kind kind, Type *root = NULL);
   118 
   119   private:
   120     Kind kind() {
   121         return root_->kind_;
   122     }
   123 
   124   public:   
   125     static Type *NewVoid(Zone *zone);
   126     static Type *NewUnchecked(Zone *zone);
   127     static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   128     static Type *NewString(Zone *zone);
   129     static Type *NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> type);
   130 
   131     static Type *cast(Object *obj) {
   132         assert(!obj ||
   133                obj->is(MapKind_Type) ||
   134                obj->is(MapKind_FunctionType) ||
   135                obj->is(MapKind_StructType) ||
   136                obj->is(MapKind_ArrayType) ||
   137                obj->is(MapKind_ReferenceType) ||
   138                obj->is(MapKind_EnumType));
   139         return (Type *)obj;
   140     }
   141 
   142     bool isPrimitive() {
   143         return kind() == PRIMITIVE;
   144     }
   145     bool isArray() {
   146         return kind() == ARRAY || kind() == EXTERNAL_ARRAY;
   147     }
   148     bool isReference() {
   149         return kind() == REFERENCE;
   150     }
   151     bool isFunction() {
   152         return kind() == FUNCTION;
   153     }
   154     bool isVoid() {
   155         return kind() == VOID;
   156     }
   157     bool isUnchecked() {
   158         return kind() == UNCHECKED;
   159     }
   160     bool isStruct() {
   161         return kind() == STRUCT;
   162     }
   163     PrimitiveType primitive() {
   164         assert(isPrimitive());
   165         return root_->primitive_;
   166     }
   167     bool isPod() {
   168         return (isPrimitive() && !isString()) || isEnum() || isUnchecked();
   169     }
   170     PrimitiveType pod() {
   171         assert(isPod());
   172         return isPrimitive()
   173                ? (primitive() == PrimitiveType_Bool)
   174                  ? PrimitiveType_Int32
   175                  : primitive()
   176                : PrimitiveType_Int32;
   177     }
   178     bool isChar() {
   179         return isPrimitive() && primitive() == PrimitiveType_Char;
   180     }
   181     bool isFloat() {
   182         return isPrimitive() && primitive() == PrimitiveType_Float;
   183     }
   184     bool isInt32() {
   185         return isPrimitive() && primitive() == PrimitiveType_Int32;
   186     }
   187     bool isInt32OrEnum() {
   188         return isInt32() || isEnum();
   189     }
   190     bool isBool() {
   191         return isPrimitive() && primitive() == PrimitiveType_Bool;
   192     }
   193     bool isString() {
   194         return kind() == STRING;
   195     }
   196     bool isExternalArray() {
   197         return kind() == EXTERNAL_ARRAY;
   198     }
   199     bool isTraceable() {
   200         return kind() >= STRING;
   201     }
   202     bool isEnum() {
   203         return kind() == ENUM;
   204     }
   205     bool hasTypeQualifiers() {
   206         return kind_ == QUALTYPE;
   207     }
   208 
   209     TypeQualifiers quals() {
   210         if (!hasTypeQualifiers())
   211             return TypeQual_None;
   212         return quals_;
   213     }
   214     Type *unqualified() {
   215         return root_;
   216     }
   217 
   218     // GC Descriptor.
   219     static inline size_t offsetOfRoot() {
   220         return OFFSETOF(Type, root_);
   221     }
   222     // End GC Descriptor.
   223 
   224   protected:
   225     Kind kind_;
   226     PrimitiveType primitive_;
   227     TypeQualifiers quals_;
   228 
   229     // For unqualified types, this points to |this|. For qualified types, it
   230     // points to the unqualified original type.
   231     Barriered<Type> root_;
   232 };
   233 
   234 class EnumType : public Type
   235 {
   236   public:
   237     static EnumType *New(Zone *Zone, Handle<String> name);
   238 
   239     String *name() {
   240         return name_;
   241     }
   242 
   243     // GC Descriptor.
   244     static inline size_t offsetOfName() {
   245         return OFFSETOF(EnumType, name_);
   246     }
   247     // End GC Descriptor.
   248 
   249     static EnumType *cast(Object *obj) {
   250         assert(!obj || obj->is(MapKind_EnumType));
   251         return (EnumType *)obj;
   252     }
   253 
   254   private:
   255     Barriered<String> name_;
   256 };
   257 
   258 class ReferenceType : public Type
   259 {
   260   public:
   261     static ReferenceType *New(Zone *zone, Handle<Type> contained);
   262     
   263     Type *contained() {
   264         return contained_;
   265     }
   266 
   267     // GC Descriptor.
   268     static inline size_t offsetOfContained() {
   269         return OFFSETOF(ReferenceType, contained_);
   270     }
   271     // End GC Descriptor.
   272 
   273     static ReferenceType *cast(Type *obj) {
   274         if (!obj)
   275             return NULL;
   276         obj = obj->unqualified();
   277         assert(obj->is(MapKind_ReferenceType));
   278         return (ReferenceType *)obj;
   279     }
   280 
   281   private:
   282     Barriered<Type> contained_;
   283 };
   284 
   285 class ArrayType : public Type
   286 {
   287   public:
   288     static const int DYNAMIC_ARRAY_SIZE = -1;
   289 
   290     static ArrayType *New(Zone *zone, Handle<Type> contained, int elements);
   291     static ArrayType *NewExternal(Zone *zone, Handle<Type> contained);
   292 
   293     Type *innermost() {
   294         Type *temp = contained();
   295         while (temp->isArray())
   296             temp = ArrayType::cast(temp)->contained();
   297         return temp;
   298     }
   299 
   300     bool isDynamic() {
   301         return elements_ == DYNAMIC_ARRAY_SIZE;
   302     }
   303     bool isExtensible() {
   304         return isDynamic() && !(quals_ & TypeQual_Const);
   305     }
   306     Type *contained() {
   307         return contained_;
   308     }
   309     bool isFixedLength() {
   310         return elements_ > 0;
   311     }
   312     bool isCharArray() {
   313         return contained()->isPrimitive() &&
   314                contained()->primitive() == PrimitiveType_Char;
   315     }
   316     unsigned fixedLength() {
   317         assert(isFixedLength());
   318         return elements_;
   319     }
   320     unsigned levels() {
   321         return levels_;
   322     }
   323     bool hasInlineElements() {
   324         // We don't allocate traceable elements inline, since there's no
   325         // point to the optimization; we're going to be allocating lots of
   326         // objects anyway (in theory).
   327         return isFixedLength() && !contained()->isTraceable();
   328     }
   329 
   330     // Arrays of this type can be created with this cached map.
   331     ArrayMap *newMap() {
   332         return newMap_;
   333     }
   334     void setNewMap(ArrayMap *map) {
   335         assert(!newMap());
   336         newMap_ = map;
   337     }
   338 
   339     // GC Descriptor.
   340     static inline size_t offsetOfContained() {
   341         return OFFSETOF(ArrayType, contained_);
   342     }
   343     static inline size_t offsetOfNewMap() {
   344         return OFFSETOF(ArrayType, newMap_);
   345     }
   346     // End GC Descriptor.
   347 
   348     static ArrayType *cast(Type *obj) {
   349         if (!obj)
   350             return NULL;
   351         obj = obj->unqualified();
   352         assert(obj->is(MapKind_ArrayType));
   353         return (ArrayType *)obj;
   354     }
   355 
   356   private:
   357     int32 elements_;
   358     unsigned levels_;
   359     Barriered<Type> contained_;
   360     Barriered<ArrayMap> newMap_;
   361 };
   362 
   363 class StructType : public Type
   364 {
   365   public:
   366     static StructType *New(Zone *zone, Handle<String> name, Handle<FixedArray> fields);
   367 
   368     FixedArray *fields() {
   369         assert(isStruct());
   370         return fields_;
   371     }
   372     Descriptor *lookupField(Handle<String> name, unsigned *index = NULL);
   373 
   374     // Objects of this type can be created with this cached map.
   375     StructMap *newMap() {
   376         return newMap_;
   377     }
   378     void setNewMap(StructMap *map) {
   379         assert(!newMap());
   380         newMap_ = map;
   381     }
   382 
   383     String *name() {
   384         return name_;
   385     }
   386 
   387     // GC Descriptor.
   388     static inline size_t offsetOfFields() {
   389         return OFFSETOF(StructType, fields_);
   390     }
   391     static inline size_t offsetOfNewMap() {
   392         return OFFSETOF(StructType, newMap_);
   393     }
   394     static inline size_t offsetOfName() {
   395         return OFFSETOF(StructType, name_);
   396     }
   397     // End GC Descriptor.
   398 
   399     static StructType *cast(Type *obj) {
   400         if (!obj)
   401             return NULL;
   402         obj = obj->unqualified();
   403         assert(obj->is(MapKind_StructType));
   404         return (StructType *)obj;
   405     }
   406 
   407   private:
   408     // Structs only.
   409     Barriered<FixedArray> fields_;
   410     Barriered<StructMap> newMap_;
   411     Barriered<String> name_;
   412 };
   413 
   414 class FunctionType : public Type
   415 {
   416   public:
   417     static FunctionType *New(Zone *zone, Handle<String> name, TokenKind kind);
   418 
   419     Type *parameterAt(size_t i) {
   420         return Type::cast(parameters()->at(i));
   421     }
   422     Type *returnType() {
   423         assert(isFunction());
   424         return returnType_;
   425     }
   426     FixedArray *parameters() {
   427         assert(isFunction());
   428         return parameters_;
   429     }
   430     FixedArray *defaults() {
   431         assert(isFunction());
   432         return defaults_;
   433     }
   434     bool isNative() {
   435         return token_ == TOK_NATIVE;
   436     }
   437     bool isForward() {
   438         return token_ == TOK_FORWARD;
   439     }
   440     bool isNativeVariadic() {
   441         assert(isNative());
   442         return variadicNative_;
   443     }
   444     void setVariadic() {
   445         assert(isNative());
   446         variadicNative_ = true;
   447     }
   448     void setReturnType(Handle<Type> returnType) {
   449         assert(!returnType_);
   450         returnType_ = returnType;
   451     }
   452     void setParameterTypes(Handle<FixedArray> types) {
   453         assert(!parameters_);
   454         parameters_ = types;
   455     }
   456     TokenKind token() {
   457         return token_;
   458     }
   459     String *name() {
   460         return name_;
   461     }
   462 
   463     // GC Descriptor.
   464     static inline size_t offsetOfReturnType() {
   465         return OFFSETOF(FunctionType, returnType_);
   466     }
   467     static inline size_t offsetOfParameters() {
   468         return OFFSETOF(FunctionType, parameters_);
   469     }
   470     static inline size_t offsetOfDefaults() {
   471         return OFFSETOF(FunctionType, defaults_);
   472     }
   473     static inline size_t offsetOfName() {
   474         return OFFSETOF(FunctionType, name_);
   475     }
   476     // End GC Descriptor.
   477 
   478     static FunctionType *cast(Type *obj) {
   479         if (!obj)
   480             return NULL;
   481         obj = obj->unqualified();
   482         assert(obj->is(MapKind_FunctionType));
   483         return (FunctionType *)obj;
   484     }
   485 
   486   private:
   487     // Functions only.
   488     Barriered<Type> returnType_;
   489     Barriered<FixedArray> parameters_;
   490     Barriered<FixedArray> defaults_;
   491     Barriered<String> name_;
   492     TokenKind token_;
   493     bool variadicNative_;
   494 };
   495 
   496 class BoxedPrimitive
   497 {
   498     PrimitiveType type_;
   499     union {
   500         int i_;
   501         float f_;
   502     };
   503 
   504   public:
   505     static BoxedPrimitive Int(int i) {
   506         BoxedPrimitive b;
   507         b.type_ = PrimitiveType_Int32;
   508         b.i_ = i;
   509         return b;
   510     }
   511     static BoxedPrimitive Float(float f) {
   512         BoxedPrimitive b;
   513         b.type_ = PrimitiveType_Float;
   514         b.f_ = f;
   515         return b;
   516     }
   517 
   518     PrimitiveType type() const {
   519         return type_;
   520     }
   521     int toInt() const {
   522         assert(type() == PrimitiveType_Int32);
   523         return i_;
   524     }
   525     float toFloat() const {
   526         assert(type() == PrimitiveType_Float);
   527         return f_;
   528     }
   529 };
   530 
   531 const char *GetTypeName(Type *type, char *buffer, size_t maxlen);
   532 
   533 }
   534 
   535 #endif // _include_jc_types_h_