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