src/Structures.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jan 06 13:52:21 2013 -0800 (2013-01-06)
changeset 256 3c184218462d
parent 241 18f3010a358c
child 263 ba85a47ee414
permissions -rw-r--r--
Initial implementation of module imports.
     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, Visibility visibility)
    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     desc->visibility_ = visibility;
    70     return desc;
    71 }
    72 
    73 StructMap *
    74 StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
    75 {
    76     Vector<unsigned> composedIndexes;
    77     for (size_t i = 0; i < type->fields()->length(); i++) {
    78         Descriptor *desc = Descriptor::cast(type->fields()->at(i));
    79         if (desc->type()->isArray() || desc->type()->isStruct()) {
    80             if (!composedIndexes.append(i))
    81                 return NULL;
    82         }
    83     }
    84 
    85     Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
    86     if (!composed)
    87         return NULL;
    88 
    89     for (size_t i = 0; i < composedIndexes.length(); i++) {
    90         Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
    91         composed->set(zone, i, desc);
    92     }
    93 
    94     size_t bytesNeeded = sizeof(StructMap) +
    95                          (builder.traceableOffsetCount() * sizeof(unsigned));
    96 
    97     Local<StructMap> map(zone);
    98     map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
    99     if (!map)
   100         return NULL;
   101 
   102     map->structureSize_ = builder.structureSize();
   103     map->traceOffsetCount_ = builder.traceableOffsetCount();
   104     map->type_ = type;
   105     map->composed_ = composed;
   106     memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
   107            sizeof(unsigned) * builder.traceableOffsetCount());
   108 
   109     return map;
   110 }
   111 
   112 Struct *
   113 Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
   114 {
   115     size_t bytesNeeded = SizeFor(map);
   116 
   117     Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
   118     if (!obj)
   119         return NULL;
   120 
   121     memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
   122 
   123     // Initialize any sub-structures. Right now, this is performed as part of
   124     // struct allocation, rather than inlined in bytecode, for simplicity.
   125     if (map->composed()) {
   126         Local<Descriptor> desc(zone);
   127         Local<Object> child(zone);
   128         Local<StructMap> childStructMap(zone);
   129         Local<ArrayMap> childArrayMap(zone);
   130 
   131         for (unsigned i = 0; i < map->composed()->length(); i++) {
   132             desc = Descriptor::cast(map->composed()->at(i));
   133 
   134             if (desc->type()->isStruct()) {
   135                 childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
   136                 child = Struct::New(zone, childStructMap, tenure);
   137             } else if (desc->type()->isArray()) {
   138                 // :TODO: don't create empty arrays for ref slots here.
   139                 // Instead, make a separate Initialize function, so we
   140                 // can avoid double-creating arrays for module globals.
   141                 //  (const char:x[] = "x")
   142                 ArrayType *type = ArrayType::cast(desc->type());
   143                 childArrayMap = ArrayMap::cast(type->newMap());
   144                 if (type->isFixedLength())
   145                     child = Array::NewFixed(zone, childArrayMap, tenure);
   146                 else
   147                     child = Array::NewEmpty(zone, childArrayMap, tenure);
   148             }
   149             if (!child)
   150                 return NULL;
   151 
   152             obj->set(zone, desc, child);
   153         }
   154     }
   155 
   156     return obj;
   157 }
   158 
   159 bool
   160 Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
   161 {
   162     assert(left->map()->type() == right->map()->type());
   163 
   164     Local<StructType> type(zone, StructType::cast(left->map()->type()));
   165     Local<Struct> leftStruct(zone);
   166     Local<Struct> rightStruct(zone);
   167     Local<Array> leftArray(zone);
   168     Local<Array> rightArray(zone);
   169     for (unsigned i = 0; i < type->fields()->length(); i++) {
   170         Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   171 
   172         // If the field is a struct, we need to deep-copy.
   173         if (desc->type()->isStruct()) {
   174             leftStruct = Struct::cast(left->get<Object *>(desc));
   175             rightStruct = Struct::cast(right->get<Object *>(desc));
   176             if (!Struct::Copy(zone, leftStruct, rightStruct))
   177                 return false;
   178         } else if (desc->type()->isArray()) {
   179             leftArray = Array::cast(left->get<Object *>(desc));
   180             rightArray = Array::cast(right->get<Object *>(desc));
   181             if (!Array::ShallowCopy(zone, leftArray, rightArray))
   182                 return false;
   183         } else if (desc->type()->isTraceable()) {
   184             Object *obj = right->get<Object *>(desc);
   185             left->set(zone, desc, obj);
   186         } else {
   187             switch (desc->type()->pod()) {
   188               case PrimitiveType_Int32:
   189               case PrimitiveType_Char:
   190               case PrimitiveType_Bool:
   191                 left->set(desc, right->get<int>(desc));
   192                 break;
   193 
   194               case PrimitiveType_Float:
   195                 left->set(desc, right->get<float>(desc));
   196                 break;
   197                 
   198               default:
   199                 assert(false);
   200             }
   201         }
   202     }
   203 
   204     return true;
   205 }