diff -r c4b1341297e5 -r ba85a47ee414 src/Structures.cpp --- a/src/Structures.cpp Mon Jun 10 00:46:29 2013 +0100 +++ b/src/Structures.cpp Mon Jun 10 01:04:43 2013 +0100 @@ -1,205 +1,205 @@ -/* vim: set ts=4 sw=4 tw=99 et: - * - * Copyright (C) 2012 David Anderson - * - * This file is part of SourcePawn. - * - * SourcePawn is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * SourcePawn. If not, see http://www.gnu.org/licenses/. - */ -#include -#include "Structures.h" -#include "Zone.h" -#include "Types.h" -#include "Array.h" -#include "Spaces-inl.h" -#include "Heap-inl.h" - -using namespace ke; - -StructureBufferBuilder::StructureBufferBuilder() - : size_(0) -{ -} - -bool -StructureBufferBuilder::add(Handle type, unsigned *offset) -{ - *offset = size_; - - if (!type->isTraceable()) { - // For now, assume the alignment of all primitive storage is 4 bytes, - // and that all need <= 4 bytes of storage. - assert(type->isInt32() || - type->isFloat() || - type->isBool() || - type->isChar() || - type->isEnum()); - size_ += 4; - return true; - } - - if (!offsets_.append(size_)) - return false; - - size_ += sizeof(Object *); - return true; -} - -Descriptor * -Descriptor::New(Zone *zone, Handle name, Handle type, Visibility visibility) -{ - Local desc(zone, - Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old))); - if (!desc) - return NULL; - - desc->name_ = name; - desc->type_ = type; - desc->offset_ = unsigned(-1); - desc->visibility_ = visibility; - return desc; -} - -StructMap * -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle type) -{ - Vector composedIndexes; - for (size_t i = 0; i < type->fields()->length(); i++) { - Descriptor *desc = Descriptor::cast(type->fields()->at(i)); - if (desc->type()->isArray() || desc->type()->isStruct()) { - if (!composedIndexes.append(i)) - return NULL; - } - } - - Local composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old)); - if (!composed) - return NULL; - - for (size_t i = 0; i < composedIndexes.length(); i++) { - Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i])); - composed->set(zone, i, desc); - } - - size_t bytesNeeded = sizeof(StructMap) + - (builder.traceableOffsetCount() * sizeof(unsigned)); - - Local map(zone); - map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct)); - if (!map) - return NULL; - - map->structureSize_ = builder.structureSize(); - map->traceOffsetCount_ = builder.traceableOffsetCount(); - map->type_ = type; - map->composed_ = composed; - memcpy(const_cast(map->traceOffsets()), builder.offsets(), - sizeof(unsigned) * builder.traceableOffsetCount()); - - return map; -} - -Struct * -Struct::New(Zone *zone, Handle map, Heap::Tenure tenure) -{ - size_t bytesNeeded = SizeFor(map); - - Local obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure))); - if (!obj) - return NULL; - - memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct))); - - // Initialize any sub-structures. Right now, this is performed as part of - // struct allocation, rather than inlined in bytecode, for simplicity. - if (map->composed()) { - Local desc(zone); - Local child(zone); - Local childStructMap(zone); - Local childArrayMap(zone); - - for (unsigned i = 0; i < map->composed()->length(); i++) { - desc = Descriptor::cast(map->composed()->at(i)); - - if (desc->type()->isStruct()) { - childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap()); - child = Struct::New(zone, childStructMap, tenure); - } else if (desc->type()->isArray()) { - // :TODO: don't create empty arrays for ref slots here. - // Instead, make a separate Initialize function, so we - // can avoid double-creating arrays for module globals. - // (const char:x[] = "x") - ArrayType *type = ArrayType::cast(desc->type()); - childArrayMap = ArrayMap::cast(type->newMap()); - if (type->isFixedLength()) - child = Array::NewFixed(zone, childArrayMap, tenure); - else - child = Array::NewEmpty(zone, childArrayMap, tenure); - } - if (!child) - return NULL; - - obj->set(zone, desc, child); - } - } - - return obj; -} - -bool -Struct::Copy(Zone *zone, Handle left, Handle right) -{ - assert(left->map()->type() == right->map()->type()); - - Local type(zone, StructType::cast(left->map()->type())); - Local leftStruct(zone); - Local rightStruct(zone); - Local leftArray(zone); - Local rightArray(zone); - for (unsigned i = 0; i < type->fields()->length(); i++) { - Descriptor *desc = Descriptor::cast(type->fields()->at(i)); - - // If the field is a struct, we need to deep-copy. - if (desc->type()->isStruct()) { - leftStruct = Struct::cast(left->get(desc)); - rightStruct = Struct::cast(right->get(desc)); - if (!Struct::Copy(zone, leftStruct, rightStruct)) - return false; - } else if (desc->type()->isArray()) { - leftArray = Array::cast(left->get(desc)); - rightArray = Array::cast(right->get(desc)); - if (!Array::ShallowCopy(zone, leftArray, rightArray)) - return false; - } else if (desc->type()->isTraceable()) { - Object *obj = right->get(desc); - left->set(zone, desc, obj); - } else { - switch (desc->type()->pod()) { - case PrimitiveType_Int32: - case PrimitiveType_Char: - case PrimitiveType_Bool: - left->set(desc, right->get(desc)); - break; - - case PrimitiveType_Float: - left->set(desc, right->get(desc)); - break; - - default: - assert(false); - } - } - } - - return true; +/* vim: set ts=4 sw=4 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of SourcePawn. + * + * SourcePawn is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * SourcePawn. If not, see http://www.gnu.org/licenses/. + */ +#include +#include "Structures.h" +#include "Zone.h" +#include "Types.h" +#include "Array.h" +#include "Spaces-inl.h" +#include "Heap-inl.h" + +using namespace ke; + +StructureBufferBuilder::StructureBufferBuilder() + : size_(0) +{ +} + +bool +StructureBufferBuilder::add(Handle type, unsigned *offset) +{ + *offset = size_; + + if (!type->isTraceable()) { + // For now, assume the alignment of all primitive storage is 4 bytes, + // and that all need <= 4 bytes of storage. + assert(type->isInt32() || + type->isFloat() || + type->isBool() || + type->isChar() || + type->isEnum()); + size_ += 4; + return true; + } + + if (!offsets_.append(size_)) + return false; + + size_ += sizeof(Object *); + return true; +} + +Descriptor * +Descriptor::New(Zone *zone, Handle name, Handle type, Visibility visibility) +{ + Local desc(zone, + Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old))); + if (!desc) + return NULL; + + desc->name_ = name; + desc->type_ = type; + desc->offset_ = unsigned(-1); + desc->visibility_ = visibility; + return desc; +} + +StructMap * +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle type) +{ + Vector composedIndexes; + for (size_t i = 0; i < type->fields()->length(); i++) { + Descriptor *desc = Descriptor::cast(type->fields()->at(i)); + if (desc->type()->isArray() || desc->type()->isStruct()) { + if (!composedIndexes.append(i)) + return NULL; + } + } + + Local composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old)); + if (!composed) + return NULL; + + for (size_t i = 0; i < composedIndexes.length(); i++) { + Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i])); + composed->set(zone, i, desc); + } + + size_t bytesNeeded = sizeof(StructMap) + + (builder.traceableOffsetCount() * sizeof(unsigned)); + + Local map(zone); + map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct)); + if (!map) + return NULL; + + map->structureSize_ = builder.structureSize(); + map->traceOffsetCount_ = builder.traceableOffsetCount(); + map->type_ = type; + map->composed_ = composed; + memcpy(const_cast(map->traceOffsets()), builder.offsets(), + sizeof(unsigned) * builder.traceableOffsetCount()); + + return map; +} + +Struct * +Struct::New(Zone *zone, Handle map, Heap::Tenure tenure) +{ + size_t bytesNeeded = SizeFor(map); + + Local obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure))); + if (!obj) + return NULL; + + memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct))); + + // Initialize any sub-structures. Right now, this is performed as part of + // struct allocation, rather than inlined in bytecode, for simplicity. + if (map->composed()) { + Local desc(zone); + Local child(zone); + Local childStructMap(zone); + Local childArrayMap(zone); + + for (unsigned i = 0; i < map->composed()->length(); i++) { + desc = Descriptor::cast(map->composed()->at(i)); + + if (desc->type()->isStruct()) { + childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap()); + child = Struct::New(zone, childStructMap, tenure); + } else if (desc->type()->isArray()) { + // :TODO: don't create empty arrays for ref slots here. + // Instead, make a separate Initialize function, so we + // can avoid double-creating arrays for module globals. + // (const char:x[] = "x") + ArrayType *type = ArrayType::cast(desc->type()); + childArrayMap = ArrayMap::cast(type->newMap()); + if (type->isFixedLength()) + child = Array::NewFixed(zone, childArrayMap, tenure); + else + child = Array::NewEmpty(zone, childArrayMap, tenure); + } + if (!child) + return NULL; + + obj->set(zone, desc, child); + } + } + + return obj; +} + +bool +Struct::Copy(Zone *zone, Handle left, Handle right) +{ + assert(left->map()->type() == right->map()->type()); + + Local type(zone, StructType::cast(left->map()->type())); + Local leftStruct(zone); + Local rightStruct(zone); + Local leftArray(zone); + Local rightArray(zone); + for (unsigned i = 0; i < type->fields()->length(); i++) { + Descriptor *desc = Descriptor::cast(type->fields()->at(i)); + + // If the field is a struct, we need to deep-copy. + if (desc->type()->isStruct()) { + leftStruct = Struct::cast(left->get(desc)); + rightStruct = Struct::cast(right->get(desc)); + if (!Struct::Copy(zone, leftStruct, rightStruct)) + return false; + } else if (desc->type()->isArray()) { + leftArray = Array::cast(left->get(desc)); + rightArray = Array::cast(right->get(desc)); + if (!Array::ShallowCopy(zone, leftArray, rightArray)) + return false; + } else if (desc->type()->isTraceable()) { + Object *obj = right->get(desc); + left->set(zone, desc, obj); + } else { + switch (desc->type()->pod()) { + case PrimitiveType_Int32: + case PrimitiveType_Char: + case PrimitiveType_Bool: + left->set(desc, right->get(desc)); + break; + + case PrimitiveType_Float: + left->set(desc, right->get(desc)); + break; + + default: + assert(false); + } + } + } + + return true; } \ No newline at end of file