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