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: #ifndef _include_jitcraft_array_h_ asherkin@263: #define _include_jitcraft_array_h_ asherkin@263: asherkin@263: #include "Heap.h" asherkin@263: #include "Handles.h" asherkin@263: #include "Types.h" asherkin@263: #include "FixedArray.h" asherkin@263: asherkin@263: namespace ke { asherkin@263: asherkin@263: class ArrayMap; asherkin@263: asherkin@263: class Array : public Object asherkin@263: { asherkin@263: friend class ArrayMap; asherkin@263: asherkin@263: protected: asherkin@263: // Note: we do not write barrier |elements_|, since it can be set to asherkin@263: // arbitrary pointers. asherkin@263: uint32 length_; asherkin@263: union { asherkin@263: void *elements_; asherkin@263: Object *objelements_; asherkin@263: }; asherkin@263: asherkin@263: protected: asherkin@263: void updateLengthAndElements(Zone *zone, unsigned length, Object *array) { asherkin@263: length_ = length; asherkin@263: write(zone, &objelements_, array); asherkin@263: } asherkin@263: asherkin@263: public: asherkin@263: static Array *NewFixed(Zone *zone, Handle map, Heap::Tenure = Heap::Tenure_Default); asherkin@263: static Array *NewString(Zone *zone, Handle map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default); asherkin@263: static Array *NewSized(Zone *zone, Handle map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default); asherkin@263: asherkin@263: static Array *New1D(Zone *zone, Handle map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default); asherkin@263: static Array *NewEmpty(Zone *zone, Handle map, Heap::Tenure tenure = Heap::Tenure_Default); asherkin@263: static Array *NewRaw(Zone *zone, Handle map, unsigned nelements, Heap::Tenure tenure); asherkin@263: asherkin@263: static Array *NewExternal(Zone *zone, asherkin@263: Handle map, asherkin@263: void *buffer, asherkin@263: unsigned length, asherkin@263: Heap::Tenure tenure = Heap::Tenure_Default); asherkin@263: asherkin@263: // Copies an array from one reference to another, obeying language semantics. asherkin@263: static bool ShallowCopy(Zone *zone, Handle dest, Handle source); asherkin@263: asherkin@263: // Creates a full duplicate of an array, following all array references as if asherkin@263: // they were fixed. Array references inside structs or objects use ShallowCopy asherkin@263: // semantics, as this is only intended for duplicating array literals, which asherkin@263: // cannot contain structs. asherkin@263: static Array *DeepCopy(Zone *zone, Handle source, Heap::Tenure tenure); asherkin@263: asherkin@263: uint32 length() { asherkin@263: return length_; asherkin@263: } asherkin@263: asherkin@263: inline ArrayType *type(); asherkin@263: asherkin@263: inline int *int32Vec(); asherkin@263: inline float *floatVec(); asherkin@263: inline char *chars(); asherkin@263: inline void *bytes(); asherkin@263: asherkin@263: bool resize(Zone *zone, size_t newLength); asherkin@263: asherkin@263: static inline size_t SizeForElement(ArrayType *type) { asherkin@263: if (type->contained()->isTraceable()) asherkin@263: return sizeof(ke::Object *); asherkin@263: if (type->contained()->isInt32()) asherkin@263: return sizeof(int); asherkin@263: if (type->contained()->primitive() == PrimitiveType_Char) asherkin@263: return sizeof(char); asherkin@263: assert(type->contained()->isFloat()); asherkin@263: return sizeof(float); asherkin@263: } asherkin@263: asherkin@263: inline size_t objSize(ArrayMap *map); asherkin@263: asherkin@263: int readInt32(size_t index) { asherkin@263: assert(index < length()); asherkin@263: return int32Vec()[index]; asherkin@263: } asherkin@263: void writeInt32(size_t index, int i) { asherkin@263: assert(index < length()); asherkin@263: int32Vec()[index] = i; asherkin@263: } asherkin@263: char readChar(size_t index) { asherkin@263: assert(index < length()); asherkin@263: return chars()[index]; asherkin@263: } asherkin@263: void writeChar(size_t index, char c) { asherkin@263: assert(index < length()); asherkin@263: chars()[index] = c; asherkin@263: } asherkin@263: float readFloat(size_t index) { asherkin@263: assert(index < length()); asherkin@263: return floatVec()[index]; asherkin@263: } asherkin@263: void writeFloat(size_t index, float f) { asherkin@263: assert(index < length()); asherkin@263: floatVec()[index] = f; asherkin@263: } asherkin@263: Object *readObject(size_t index) { asherkin@263: return FixedArray::cast(objelements_)->at(index); asherkin@263: } asherkin@263: void writeObject(Zone *zone, size_t index, Object *ptr) { asherkin@263: FixedArray::cast(objelements_)->set(zone, index, ptr); asherkin@263: } asherkin@263: asherkin@263: // GC Descriptor. asherkin@263: static inline size_t offsetOfElements() { asherkin@263: return offsetof(Array, objelements_); asherkin@263: } asherkin@263: // End GC Descriptor. asherkin@263: asherkin@263: static Array *cast(Object *obj) { asherkin@263: assert(!obj || asherkin@263: obj->is(MapKind_Array) || asherkin@263: obj->is(MapKind_DependentArray)); asherkin@263: return reinterpret_cast(obj); asherkin@263: } asherkin@263: }; asherkin@263: asherkin@263: class DependentArray : public Array asherkin@263: { asherkin@263: Barriered root_; asherkin@263: asherkin@263: public: asherkin@263: static Array *New(Zone *zone, Handle source, Handle map, unsigned index); asherkin@263: asherkin@263: // GC Descriptor. asherkin@263: static inline size_t offsetOfRoot() { asherkin@263: return offsetof(DependentArray, root_); asherkin@263: } asherkin@263: // End GC Descriptor. asherkin@263: asherkin@263: static DependentArray *cast(Object *obj) { asherkin@263: assert(!obj || obj->is(MapKind_DependentArray)); asherkin@263: return reinterpret_cast(obj); asherkin@263: } asherkin@263: }; asherkin@263: asherkin@263: class ArrayMap : public Map asherkin@263: { asherkin@263: Barriered type_; asherkin@263: asherkin@263: public: asherkin@263: static ArrayMap *New(Zone *zone, Handle type); asherkin@263: asherkin@263: // DependentArray maps are never attached, and are just free-floating, asherkin@263: // rooted ultimately by the bytecode. A :TODO: that we might need to asherkin@263: // cache these, or attach them somewhere saner like ArrayType, which asherkin@263: // itself will eventually be cached. asherkin@263: static ArrayMap *NewDependent(Zone *zone, Handle type); asherkin@263: asherkin@263: ArrayType *type() { asherkin@263: return type_; asherkin@263: } asherkin@263: asherkin@263: // GC Descriptor. asherkin@263: static inline size_t offsetOfType() { asherkin@263: return OFFSETOF(ArrayMap, type_); asherkin@263: } asherkin@263: // End GC Descriptor. asherkin@263: asherkin@263: static ArrayMap *cast(Object *obj) { asherkin@263: assert(!obj || obj->is(MapKind_MetaArray)); asherkin@263: return reinterpret_cast(obj); asherkin@263: } asherkin@263: }; asherkin@263: asherkin@263: inline void * asherkin@263: Array::bytes() asherkin@263: { asherkin@263: assert(!type()->contained()->isTraceable()); asherkin@263: assert(type()->hasInlineElements() || asherkin@263: type()->isExternalArray() || asherkin@263: is(MapKind_DependentArray) || asherkin@263: !length() || asherkin@263: ByteArray::cast((Object *)elements_)); asherkin@263: asherkin@263: return Address(elements_) + ByteArray::offsetToElements(); asherkin@263: } asherkin@263: asherkin@263: inline int * asherkin@263: Array::int32Vec() asherkin@263: { asherkin@263: assert(type()->contained()->isInt32()); asherkin@263: return reinterpret_cast(bytes()); asherkin@263: } asherkin@263: asherkin@263: inline float * asherkin@263: Array::floatVec() asherkin@263: { asherkin@263: assert(type()->contained()->isFloat()); asherkin@263: return reinterpret_cast(bytes()); asherkin@263: } asherkin@263: asherkin@263: inline char * asherkin@263: Array::chars() asherkin@263: { asherkin@263: assert(type()->isCharArray()); asherkin@263: return reinterpret_cast(bytes()); asherkin@263: } asherkin@263: asherkin@263: inline ArrayType * asherkin@263: Array::type() asherkin@263: { asherkin@263: return ArrayMap::cast(map())->type(); asherkin@263: } asherkin@263: asherkin@263: inline size_t asherkin@263: Array::objSize(ArrayMap *map) asherkin@263: { asherkin@263: assert(this->map() == map); asherkin@263: if (map->type()->hasInlineElements()) asherkin@263: return sizeof(Array) + Array::SizeForElement(map->type()) * length(); asherkin@263: return sizeof(Array); asherkin@263: } asherkin@263: asherkin@263: } asherkin@263: asherkin@263: #endif // _include_jitcraft_array_h_