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