OTE* ObjectMemory::CopyElements(OTE* oteObj, MWORD startingAt, MWORD count) { // Note that startingAt is expected to be a zero-based index ASSERT(startingAt >= 0); OTE* oteSlice; if (oteObj->isBytes()) { BytesOTE* oteBytes = reinterpret_cast<BytesOTE*>(oteObj); size_t elementSize = ObjectMemory::GetBytesElementSize(oteBytes); if (count == 0 || ((startingAt + count) * elementSize <= oteBytes->bytesSize())) { MWORD objectSize = elementSize * count; if (oteBytes->m_flags.m_weakOrZ) { // TODO: Allocate the correct number of null term bytes based on the encoding auto newBytes = static_cast<VariantByteObject*>(allocObject(objectSize + NULLTERMSIZE, oteSlice)); // When copying strings, the slices has the same string class (oteSlice->m_oteClass = oteBytes->m_oteClass)->countUp(); memcpy(newBytes->m_fields, oteBytes->m_location->m_fields + (startingAt * elementSize), objectSize); *reinterpret_cast<NULLTERMTYPE*>(&newBytes->m_fields[objectSize]) = 0; oteSlice->beNullTerminated(); return oteSlice; } else { VariantByteObject* newBytes = static_cast<VariantByteObject*>(allocObject(objectSize, oteSlice)); // When copying bytes, the slice is always a ByteArray oteSlice->m_oteClass = Pointers.ClassByteArray; oteSlice->beBytes(); memcpy(newBytes->m_fields, oteBytes->m_location->m_fields + (startingAt * elementSize), objectSize); return oteSlice; } } } else { // Pointers PointersOTE* otePointers = reinterpret_cast<PointersOTE*>(oteObj); BehaviorOTE* oteClass = otePointers->m_oteClass; InstanceSpecification instSpec = oteClass->m_location->m_instanceSpec; if (instSpec.m_indexable) { startingAt += instSpec.m_fixedFields; if (count == 0 || (startingAt + count) <= otePointers->pointersSize()) { MWORD objectSize = SizeOfPointers(count); auto pSlice = static_cast<VariantObject*>(allocObject(objectSize, oteSlice)); // When copying pointers, the slice is always an Array oteSlice->m_oteClass = Pointers.ClassArray; VariantObject* pSrc = otePointers->m_location; for (MWORD i = 0; i < count; i++) { countUp(pSlice->m_fields[i] = pSrc->m_fields[startingAt + i]); } return oteSlice; } } } return nullptr; }
template <bool MaybeZ, bool Initialized> BytesOTE* ObjectMemory::newByteObject(BehaviorOTE* classPointer, MWORD elementCount) { Behavior& byteClass = *classPointer->m_location; OTE* ote; if (!MaybeZ || !byteClass.m_instanceSpec.m_nullTerminated) { ASSERT(!classPointer->m_location->m_instanceSpec.m_nullTerminated); VariantByteObject* newBytes = static_cast<VariantByteObject*>(allocObject(elementCount + SizeOfPointers(0), ote)); ASSERT((elementCount > MaxSizeOfPoolObject && ote->heapSpace() == OTEFlags::NormalSpace) || ote->heapSpace() == OTEFlags::PoolSpace); ASSERT(ote->getSize() == elementCount + SizeOfPointers(0)); if (Initialized) { // Byte objects are initialized to zeros (but not the header) // Note that we round up to initialize to the next DWORD // This can be useful when working on a 32-bit word machine ZeroMemory(newBytes->m_fields, _ROUND2(elementCount, sizeof(DWORD))); classPointer->countUp(); } ote->m_oteClass = classPointer; ote->beBytes(); } else { ASSERT(classPointer->m_location->m_instanceSpec.m_nullTerminated); MWORD objectSize; switch (reinterpret_cast<const StringClass&>(byteClass).Encoding) { case StringEncoding::Ansi: case StringEncoding::Utf8: objectSize = elementCount * sizeof(AnsiString::CU); break; case StringEncoding::Utf16: objectSize = elementCount * sizeof(Utf16String::CU); break; case StringEncoding::Utf32: objectSize = elementCount * sizeof(Utf32String::CU); break; default: __assume(false); break; } // TODO: Allocate the correct number of null term bytes based on the encoding objectSize += NULLTERMSIZE; VariantByteObject* newBytes = static_cast<VariantByteObject*>(allocObject(objectSize + SizeOfPointers(0), ote)); ASSERT((objectSize > MaxSizeOfPoolObject && ote->heapSpace() == OTEFlags::NormalSpace) || ote->heapSpace() == OTEFlags::PoolSpace); ASSERT(ote->getSize() == objectSize + SizeOfPointers(0)); if (Initialized) { // Byte objects are initialized to zeros (but not the header) // Note that we round up to initialize to the next DWORD // This can be useful when working on a 32-bit word machine ZeroMemory(newBytes->m_fields, _ROUND2(objectSize, sizeof(DWORD))); classPointer->countUp(); } else { // We still want to ensure the null terminator is set, even if not initializing the rest of the object *reinterpret_cast<NULLTERMTYPE*>(&newBytes->m_fields[objectSize - NULLTERMSIZE]) = 0; } ote->m_oteClass = classPointer; ote->beNullTerminated(); HARDASSERT(ote->isBytes()); } return reinterpret_cast<BytesOTE*>(ote); }