src/Structures.cpp
author David Anderson <dvander@alliedmods.net>
Wed Dec 26 17:20:55 2012 -0800 (2012-12-26)
changeset 244 3c57bbf22aa2
parent 241 18f3010a358c
child 256 3c184218462d
permissions -rw-r--r--
Fix clang bustage.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of SourcePawn.
     6  *
     7  * SourcePawn 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  * SourcePawn 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  * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <string.h>
    20 #include "Structures.h"
    21 #include "Zone.h"
    22 #include "Types.h"
    23 #include "Array.h"
    24 #include "Spaces-inl.h"
    25 #include "Heap-inl.h"
    26 
    27 using namespace ke;
    28 
    29 StructureBufferBuilder::StructureBufferBuilder()
    30   : size_(0)
    31 {
    32 }
    33 
    34 bool
    35 StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
    36 {
    37     *offset = size_;
    38 
    39     if (!type->isTraceable()) {
    40         // For now, assume the alignment of all primitive storage is 4 bytes,
    41         // and that all need <= 4 bytes of storage.
    42         assert(type->isInt32() ||
    43                type->isFloat() ||
    44                type->isBool() ||
    45                type->isChar() ||
    46                type->isEnum());
    47         size_ += 4;
    48         return true;
    49     }
    50 
    51     if (!offsets_.append(size_))
    52         return false;
    53 
    54     size_ += sizeof(Object *);
    55     return true;
    56 }
    57 
    58 Descriptor *
    59 Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type)
    60 {
    61     Local<Descriptor> desc(zone,
    62         Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
    63     if (!desc)
    64         return NULL;
    65 
    66     desc->name_ = name;
    67     desc->type_ = type;
    68     desc->offset_ = unsigned(-1);
    69     return desc;
    70 }
    71 
    72 StructMap *
    73 StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
    74 {
    75     Vector<unsigned> composedIndexes;
    76     for (size_t i = 0; i < type->fields()->length(); i++) {
    77         Descriptor *desc = Descriptor::cast(type->fields()->at(i));
    78         if (desc->type()->isArray() || desc->type()->isStruct()) {
    79             if (!composedIndexes.append(i))
    80                 return NULL;
    81         }
    82     }
    83 
    84     Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
    85     if (!composed)
    86         return NULL;
    87 
    88     for (size_t i = 0; i < composedIndexes.length(); i++) {
    89         Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
    90         composed->set(zone, i, desc);
    91     }
    92 
    93     size_t bytesNeeded = sizeof(StructMap) +
    94                          (builder.traceableOffsetCount() * sizeof(unsigned));
    95 
    96     Local<StructMap> map(zone);
    97     map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
    98     if (!map)
    99         return NULL;
   100 
   101     map->structureSize_ = builder.structureSize();
   102     map->traceOffsetCount_ = builder.traceableOffsetCount();
   103     map->type_ = type;
   104     map->composed_ = composed;
   105     memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
   106            sizeof(unsigned) * builder.traceableOffsetCount());
   107 
   108     return map;
   109 }
   110 
   111 Struct *
   112 Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
   113 {
   114     size_t bytesNeeded = sizeof(Struct) + map->structureSize();
   115     Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
   116     if (!obj)
   117         return NULL;
   118 
   119     memset((Struct *)obj + 1, 0, map->structureSize());
   120 
   121     // Initialize any sub-structures. Right now, this is performed as part of
   122     // struct allocation, rather than inlined in bytecode, for simplicity.
   123     if (map->composed()) {
   124         Local<Descriptor> desc(zone);
   125         Local<Object> child(zone);
   126         Local<StructMap> childStructMap(zone);
   127         Local<ArrayMap> childArrayMap(zone);
   128 
   129         for (unsigned i = 0; i < map->composed()->length(); i++) {
   130             desc = Descriptor::cast(map->composed()->at(i));
   131 
   132             if (desc->type()->isStruct()) {
   133                 childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
   134                 child = Struct::New(zone, childStructMap, tenure);
   135             } else if (desc->type()->isArray()) {
   136                 // :TODO: don't create empty arrays for ref slots here.
   137                 // Instead, make a separate Initialize function, so we
   138                 // can avoid double-creating arrays for module globals.
   139                 //  (const char:x[] = "x")
   140                 ArrayType *type = ArrayType::cast(desc->type());
   141                 childArrayMap = ArrayMap::cast(type->newMap());
   142                 if (type->isFixedLength())
   143                     child = Array::NewFixed(zone, childArrayMap, tenure);
   144                 else
   145                     child = Array::NewEmpty(zone, childArrayMap, tenure);
   146             }
   147             if (!child)
   148                 return NULL;
   149 
   150             obj->set(zone, desc, child);
   151         }
   152     }
   153 
   154     return obj;
   155 }
   156 
   157 bool
   158 Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
   159 {
   160     assert(left->map()->type() == right->map()->type());
   161 
   162     Local<StructType> type(zone, StructType::cast(left->map()->type()));
   163     Local<Struct> leftStruct(zone);
   164     Local<Struct> rightStruct(zone);
   165     Local<Array> leftArray(zone);
   166     Local<Array> rightArray(zone);
   167     for (unsigned i = 0; i < type->fields()->length(); i++) {
   168         Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   169 
   170         // If the field is a struct, we need to deep-copy.
   171         if (desc->type()->isStruct()) {
   172             leftStruct = Struct::cast(left->get<Object *>(desc));
   173             rightStruct = Struct::cast(right->get<Object *>(desc));
   174             if (!Struct::Copy(zone, leftStruct, rightStruct))
   175                 return false;
   176         } else if (desc->type()->isArray()) {
   177             leftArray = Array::cast(left->get<Object *>(desc));
   178             rightArray = Array::cast(right->get<Object *>(desc));
   179             if (!Array::ShallowCopy(zone, leftArray, rightArray))
   180                 return false;
   181         } else if (desc->type()->isTraceable()) {
   182             Object *obj = right->get<Object *>(desc);
   183             left->set(zone, desc, obj);
   184         } else {
   185             switch (desc->type()->pod()) {
   186               case PrimitiveType_Int32:
   187               case PrimitiveType_Char:
   188               case PrimitiveType_Bool:
   189                 left->set(desc, right->get<int>(desc));
   190                 break;
   191 
   192               case PrimitiveType_Float:
   193                 left->set(desc, right->get<float>(desc));
   194                 break;
   195                 
   196               default:
   197                 assert(false);
   198             }
   199         }
   200     }
   201 
   202     return true;
   203 }