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