src/Structures.cpp
changeset 263 ba85a47ee414
parent 256 3c184218462d
     1.1 --- a/src/Structures.cpp	Mon Jun 10 00:46:29 2013 +0100
     1.2 +++ b/src/Structures.cpp	Mon Jun 10 01:04:43 2013 +0100
     1.3 @@ -1,205 +1,205 @@
     1.4 -/* vim: set ts=4 sw=4 tw=99 et:
     1.5 - *
     1.6 - * Copyright (C) 2012 David Anderson
     1.7 - *
     1.8 - * This file is part of SourcePawn.
     1.9 - *
    1.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    1.11 - * the terms of the GNU General Public License as published by the Free
    1.12 - * Software Foundation, either version 3 of the License, or (at your option)
    1.13 - * any later version.
    1.14 - * 
    1.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    1.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    1.18 - *
    1.19 - * You should have received a copy of the GNU General Public License along with
    1.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    1.21 - */
    1.22 -#include <string.h>
    1.23 -#include "Structures.h"
    1.24 -#include "Zone.h"
    1.25 -#include "Types.h"
    1.26 -#include "Array.h"
    1.27 -#include "Spaces-inl.h"
    1.28 -#include "Heap-inl.h"
    1.29 -
    1.30 -using namespace ke;
    1.31 -
    1.32 -StructureBufferBuilder::StructureBufferBuilder()
    1.33 -  : size_(0)
    1.34 -{
    1.35 -}
    1.36 -
    1.37 -bool
    1.38 -StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
    1.39 -{
    1.40 -    *offset = size_;
    1.41 -
    1.42 -    if (!type->isTraceable()) {
    1.43 -        // For now, assume the alignment of all primitive storage is 4 bytes,
    1.44 -        // and that all need <= 4 bytes of storage.
    1.45 -        assert(type->isInt32() ||
    1.46 -               type->isFloat() ||
    1.47 -               type->isBool() ||
    1.48 -               type->isChar() ||
    1.49 -               type->isEnum());
    1.50 -        size_ += 4;
    1.51 -        return true;
    1.52 -    }
    1.53 -
    1.54 -    if (!offsets_.append(size_))
    1.55 -        return false;
    1.56 -
    1.57 -    size_ += sizeof(Object *);
    1.58 -    return true;
    1.59 -}
    1.60 -
    1.61 -Descriptor *
    1.62 -Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
    1.63 -{
    1.64 -    Local<Descriptor> desc(zone,
    1.65 -        Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
    1.66 -    if (!desc)
    1.67 -        return NULL;
    1.68 -
    1.69 -    desc->name_ = name;
    1.70 -    desc->type_ = type;
    1.71 -    desc->offset_ = unsigned(-1);
    1.72 -    desc->visibility_ = visibility;
    1.73 -    return desc;
    1.74 -}
    1.75 -
    1.76 -StructMap *
    1.77 -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
    1.78 -{
    1.79 -    Vector<unsigned> composedIndexes;
    1.80 -    for (size_t i = 0; i < type->fields()->length(); i++) {
    1.81 -        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
    1.82 -        if (desc->type()->isArray() || desc->type()->isStruct()) {
    1.83 -            if (!composedIndexes.append(i))
    1.84 -                return NULL;
    1.85 -        }
    1.86 -    }
    1.87 -
    1.88 -    Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
    1.89 -    if (!composed)
    1.90 -        return NULL;
    1.91 -
    1.92 -    for (size_t i = 0; i < composedIndexes.length(); i++) {
    1.93 -        Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
    1.94 -        composed->set(zone, i, desc);
    1.95 -    }
    1.96 -
    1.97 -    size_t bytesNeeded = sizeof(StructMap) +
    1.98 -                         (builder.traceableOffsetCount() * sizeof(unsigned));
    1.99 -
   1.100 -    Local<StructMap> map(zone);
   1.101 -    map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
   1.102 -    if (!map)
   1.103 -        return NULL;
   1.104 -
   1.105 -    map->structureSize_ = builder.structureSize();
   1.106 -    map->traceOffsetCount_ = builder.traceableOffsetCount();
   1.107 -    map->type_ = type;
   1.108 -    map->composed_ = composed;
   1.109 -    memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
   1.110 -           sizeof(unsigned) * builder.traceableOffsetCount());
   1.111 -
   1.112 -    return map;
   1.113 -}
   1.114 -
   1.115 -Struct *
   1.116 -Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
   1.117 -{
   1.118 -    size_t bytesNeeded = SizeFor(map);
   1.119 -
   1.120 -    Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
   1.121 -    if (!obj)
   1.122 -        return NULL;
   1.123 -
   1.124 -    memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
   1.125 -
   1.126 -    // Initialize any sub-structures. Right now, this is performed as part of
   1.127 -    // struct allocation, rather than inlined in bytecode, for simplicity.
   1.128 -    if (map->composed()) {
   1.129 -        Local<Descriptor> desc(zone);
   1.130 -        Local<Object> child(zone);
   1.131 -        Local<StructMap> childStructMap(zone);
   1.132 -        Local<ArrayMap> childArrayMap(zone);
   1.133 -
   1.134 -        for (unsigned i = 0; i < map->composed()->length(); i++) {
   1.135 -            desc = Descriptor::cast(map->composed()->at(i));
   1.136 -
   1.137 -            if (desc->type()->isStruct()) {
   1.138 -                childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
   1.139 -                child = Struct::New(zone, childStructMap, tenure);
   1.140 -            } else if (desc->type()->isArray()) {
   1.141 -                // :TODO: don't create empty arrays for ref slots here.
   1.142 -                // Instead, make a separate Initialize function, so we
   1.143 -                // can avoid double-creating arrays for module globals.
   1.144 -                //  (const char:x[] = "x")
   1.145 -                ArrayType *type = ArrayType::cast(desc->type());
   1.146 -                childArrayMap = ArrayMap::cast(type->newMap());
   1.147 -                if (type->isFixedLength())
   1.148 -                    child = Array::NewFixed(zone, childArrayMap, tenure);
   1.149 -                else
   1.150 -                    child = Array::NewEmpty(zone, childArrayMap, tenure);
   1.151 -            }
   1.152 -            if (!child)
   1.153 -                return NULL;
   1.154 -
   1.155 -            obj->set(zone, desc, child);
   1.156 -        }
   1.157 -    }
   1.158 -
   1.159 -    return obj;
   1.160 -}
   1.161 -
   1.162 -bool
   1.163 -Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
   1.164 -{
   1.165 -    assert(left->map()->type() == right->map()->type());
   1.166 -
   1.167 -    Local<StructType> type(zone, StructType::cast(left->map()->type()));
   1.168 -    Local<Struct> leftStruct(zone);
   1.169 -    Local<Struct> rightStruct(zone);
   1.170 -    Local<Array> leftArray(zone);
   1.171 -    Local<Array> rightArray(zone);
   1.172 -    for (unsigned i = 0; i < type->fields()->length(); i++) {
   1.173 -        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   1.174 -
   1.175 -        // If the field is a struct, we need to deep-copy.
   1.176 -        if (desc->type()->isStruct()) {
   1.177 -            leftStruct = Struct::cast(left->get<Object *>(desc));
   1.178 -            rightStruct = Struct::cast(right->get<Object *>(desc));
   1.179 -            if (!Struct::Copy(zone, leftStruct, rightStruct))
   1.180 -                return false;
   1.181 -        } else if (desc->type()->isArray()) {
   1.182 -            leftArray = Array::cast(left->get<Object *>(desc));
   1.183 -            rightArray = Array::cast(right->get<Object *>(desc));
   1.184 -            if (!Array::ShallowCopy(zone, leftArray, rightArray))
   1.185 -                return false;
   1.186 -        } else if (desc->type()->isTraceable()) {
   1.187 -            Object *obj = right->get<Object *>(desc);
   1.188 -            left->set(zone, desc, obj);
   1.189 -        } else {
   1.190 -            switch (desc->type()->pod()) {
   1.191 -              case PrimitiveType_Int32:
   1.192 -              case PrimitiveType_Char:
   1.193 -              case PrimitiveType_Bool:
   1.194 -                left->set(desc, right->get<int>(desc));
   1.195 -                break;
   1.196 -
   1.197 -              case PrimitiveType_Float:
   1.198 -                left->set(desc, right->get<float>(desc));
   1.199 -                break;
   1.200 -                
   1.201 -              default:
   1.202 -                assert(false);
   1.203 -            }
   1.204 -        }
   1.205 -    }
   1.206 -
   1.207 -    return true;
   1.208 +/* vim: set ts=4 sw=4 tw=99 et:
   1.209 + *
   1.210 + * Copyright (C) 2012 David Anderson
   1.211 + *
   1.212 + * This file is part of SourcePawn.
   1.213 + *
   1.214 + * SourcePawn is free software: you can redistribute it and/or modify it under
   1.215 + * the terms of the GNU General Public License as published by the Free
   1.216 + * Software Foundation, either version 3 of the License, or (at your option)
   1.217 + * any later version.
   1.218 + * 
   1.219 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   1.220 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   1.221 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   1.222 + *
   1.223 + * You should have received a copy of the GNU General Public License along with
   1.224 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   1.225 + */
   1.226 +#include <string.h>
   1.227 +#include "Structures.h"
   1.228 +#include "Zone.h"
   1.229 +#include "Types.h"
   1.230 +#include "Array.h"
   1.231 +#include "Spaces-inl.h"
   1.232 +#include "Heap-inl.h"
   1.233 +
   1.234 +using namespace ke;
   1.235 +
   1.236 +StructureBufferBuilder::StructureBufferBuilder()
   1.237 +  : size_(0)
   1.238 +{
   1.239 +}
   1.240 +
   1.241 +bool
   1.242 +StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
   1.243 +{
   1.244 +    *offset = size_;
   1.245 +
   1.246 +    if (!type->isTraceable()) {
   1.247 +        // For now, assume the alignment of all primitive storage is 4 bytes,
   1.248 +        // and that all need <= 4 bytes of storage.
   1.249 +        assert(type->isInt32() ||
   1.250 +               type->isFloat() ||
   1.251 +               type->isBool() ||
   1.252 +               type->isChar() ||
   1.253 +               type->isEnum());
   1.254 +        size_ += 4;
   1.255 +        return true;
   1.256 +    }
   1.257 +
   1.258 +    if (!offsets_.append(size_))
   1.259 +        return false;
   1.260 +
   1.261 +    size_ += sizeof(Object *);
   1.262 +    return true;
   1.263 +}
   1.264 +
   1.265 +Descriptor *
   1.266 +Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
   1.267 +{
   1.268 +    Local<Descriptor> desc(zone,
   1.269 +        Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
   1.270 +    if (!desc)
   1.271 +        return NULL;
   1.272 +
   1.273 +    desc->name_ = name;
   1.274 +    desc->type_ = type;
   1.275 +    desc->offset_ = unsigned(-1);
   1.276 +    desc->visibility_ = visibility;
   1.277 +    return desc;
   1.278 +}
   1.279 +
   1.280 +StructMap *
   1.281 +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
   1.282 +{
   1.283 +    Vector<unsigned> composedIndexes;
   1.284 +    for (size_t i = 0; i < type->fields()->length(); i++) {
   1.285 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   1.286 +        if (desc->type()->isArray() || desc->type()->isStruct()) {
   1.287 +            if (!composedIndexes.append(i))
   1.288 +                return NULL;
   1.289 +        }
   1.290 +    }
   1.291 +
   1.292 +    Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
   1.293 +    if (!composed)
   1.294 +        return NULL;
   1.295 +
   1.296 +    for (size_t i = 0; i < composedIndexes.length(); i++) {
   1.297 +        Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
   1.298 +        composed->set(zone, i, desc);
   1.299 +    }
   1.300 +
   1.301 +    size_t bytesNeeded = sizeof(StructMap) +
   1.302 +                         (builder.traceableOffsetCount() * sizeof(unsigned));
   1.303 +
   1.304 +    Local<StructMap> map(zone);
   1.305 +    map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
   1.306 +    if (!map)
   1.307 +        return NULL;
   1.308 +
   1.309 +    map->structureSize_ = builder.structureSize();
   1.310 +    map->traceOffsetCount_ = builder.traceableOffsetCount();
   1.311 +    map->type_ = type;
   1.312 +    map->composed_ = composed;
   1.313 +    memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
   1.314 +           sizeof(unsigned) * builder.traceableOffsetCount());
   1.315 +
   1.316 +    return map;
   1.317 +}
   1.318 +
   1.319 +Struct *
   1.320 +Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
   1.321 +{
   1.322 +    size_t bytesNeeded = SizeFor(map);
   1.323 +
   1.324 +    Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
   1.325 +    if (!obj)
   1.326 +        return NULL;
   1.327 +
   1.328 +    memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
   1.329 +
   1.330 +    // Initialize any sub-structures. Right now, this is performed as part of
   1.331 +    // struct allocation, rather than inlined in bytecode, for simplicity.
   1.332 +    if (map->composed()) {
   1.333 +        Local<Descriptor> desc(zone);
   1.334 +        Local<Object> child(zone);
   1.335 +        Local<StructMap> childStructMap(zone);
   1.336 +        Local<ArrayMap> childArrayMap(zone);
   1.337 +
   1.338 +        for (unsigned i = 0; i < map->composed()->length(); i++) {
   1.339 +            desc = Descriptor::cast(map->composed()->at(i));
   1.340 +
   1.341 +            if (desc->type()->isStruct()) {
   1.342 +                childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
   1.343 +                child = Struct::New(zone, childStructMap, tenure);
   1.344 +            } else if (desc->type()->isArray()) {
   1.345 +                // :TODO: don't create empty arrays for ref slots here.
   1.346 +                // Instead, make a separate Initialize function, so we
   1.347 +                // can avoid double-creating arrays for module globals.
   1.348 +                //  (const char:x[] = "x")
   1.349 +                ArrayType *type = ArrayType::cast(desc->type());
   1.350 +                childArrayMap = ArrayMap::cast(type->newMap());
   1.351 +                if (type->isFixedLength())
   1.352 +                    child = Array::NewFixed(zone, childArrayMap, tenure);
   1.353 +                else
   1.354 +                    child = Array::NewEmpty(zone, childArrayMap, tenure);
   1.355 +            }
   1.356 +            if (!child)
   1.357 +                return NULL;
   1.358 +
   1.359 +            obj->set(zone, desc, child);
   1.360 +        }
   1.361 +    }
   1.362 +
   1.363 +    return obj;
   1.364 +}
   1.365 +
   1.366 +bool
   1.367 +Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
   1.368 +{
   1.369 +    assert(left->map()->type() == right->map()->type());
   1.370 +
   1.371 +    Local<StructType> type(zone, StructType::cast(left->map()->type()));
   1.372 +    Local<Struct> leftStruct(zone);
   1.373 +    Local<Struct> rightStruct(zone);
   1.374 +    Local<Array> leftArray(zone);
   1.375 +    Local<Array> rightArray(zone);
   1.376 +    for (unsigned i = 0; i < type->fields()->length(); i++) {
   1.377 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   1.378 +
   1.379 +        // If the field is a struct, we need to deep-copy.
   1.380 +        if (desc->type()->isStruct()) {
   1.381 +            leftStruct = Struct::cast(left->get<Object *>(desc));
   1.382 +            rightStruct = Struct::cast(right->get<Object *>(desc));
   1.383 +            if (!Struct::Copy(zone, leftStruct, rightStruct))
   1.384 +                return false;
   1.385 +        } else if (desc->type()->isArray()) {
   1.386 +            leftArray = Array::cast(left->get<Object *>(desc));
   1.387 +            rightArray = Array::cast(right->get<Object *>(desc));
   1.388 +            if (!Array::ShallowCopy(zone, leftArray, rightArray))
   1.389 +                return false;
   1.390 +        } else if (desc->type()->isTraceable()) {
   1.391 +            Object *obj = right->get<Object *>(desc);
   1.392 +            left->set(zone, desc, obj);
   1.393 +        } else {
   1.394 +            switch (desc->type()->pod()) {
   1.395 +              case PrimitiveType_Int32:
   1.396 +              case PrimitiveType_Char:
   1.397 +              case PrimitiveType_Bool:
   1.398 +                left->set(desc, right->get<int>(desc));
   1.399 +                break;
   1.400 +
   1.401 +              case PrimitiveType_Float:
   1.402 +                left->set(desc, right->get<float>(desc));
   1.403 +                break;
   1.404 +                
   1.405 +              default:
   1.406 +                assert(false);
   1.407 +            }
   1.408 +        }
   1.409 +    }
   1.410 +
   1.411 +    return true;
   1.412  }
   1.413 \ No newline at end of file