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