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