template <MWORD ImageNullTerms> HRESULT ObjectMemory::LoadPointers(ibinstream& imageFile, const ImageHeader* pHeader, size_t& cbRead) { ASSERT(pHeader->nGlobalPointers == NumPointers); ::ZeroMemory(m_pConstObjs, CONSTSPACESIZE); size_t cbPerm = 0; BYTE* pNextConst = reinterpret_cast<BYTE*>(m_pConstObjs); int i; for (i = 0; i < NumPermanent; i++) { VariantObject* pConstObj = reinterpret_cast<VariantObject*>(pNextConst); OTE* ote = m_pOT + i; MWORD bytesToRead; MWORD allocSize; if (ote->isNullTerminated()) { MWORD byteSize = ote->getSize(); allocSize = byteSize + NULLTERMSIZE; bytesToRead = byteSize + ImageNullTerms; } else { allocSize = bytesToRead = ote->getSize(); } if (bytesToRead > 0) { // Now load the rest of the object (size includes itself) if (!imageFile.read(&(pConstObj->m_fields), bytesToRead)) return ImageReadError(imageFile); } else { if (allocSize == 0) pConstObj = NULL; } cbPerm += bytesToRead; pNextConst += _ROUND2(allocSize, 4); markObject(ote); Oop* oldLocation = reinterpret_cast<Oop*>(ote->m_location); ote->m_location = pConstObj; ote->beSticky(); // Repair the object FixupObject(ote, oldLocation, pHeader); } #ifdef _DEBUG TRACESTREAM << i<< L" permanent objects loaded totalling " << cbPerm<< L" bytes" << std::endl; #endif memcpy(const_cast<VMPointers*>(&Pointers), &_Pointers, sizeof(Pointers)); cbRead += cbPerm; return S_OK; }
BytesOTE* __fastcall ObjectMemory::shallowCopy(BytesOTE* ote) { ASSERT(ote->isBytes()); // Copying byte objects is simple and fast VariantByteObject& bytes = *ote->m_location; BehaviorOTE* classPointer = ote->m_oteClass; MWORD objectSize = ote->sizeOf(); OTE* copyPointer; // Allocate an uninitialized object ... VariantByteObject* pLocation = static_cast<VariantByteObject*>(allocObject(objectSize, copyPointer)); ASSERT((objectSize > MaxSizeOfPoolObject && copyPointer->heapSpace() == OTEFlags::NormalSpace) || copyPointer->heapSpace() == OTEFlags::PoolSpace); ASSERT(copyPointer->getSize() == objectSize); // This set does not want to copy over the immutability bit - i.e. even if the original was immutable, the // copy will never be. copyPointer->setSize(ote->getSize()); copyPointer->m_dwFlags = (copyPointer->m_dwFlags & ~OTEFlags::WeakMask) | (ote->m_dwFlags & OTEFlags::WeakMask); ASSERT(copyPointer->isBytes()); copyPointer->m_oteClass = classPointer; classPointer->countUp(); // Copy the entire object over the other one, including any null terminator and object header memcpy(pLocation, &bytes, objectSize); return reinterpret_cast<BytesOTE*>(copyPointer); }
PointersOTE* __fastcall ObjectMemory::newUninitializedPointerObject(BehaviorOTE* classPointer, MWORD oops) { // Total size must fit in a DWORD bits ASSERT(oops < ((DWORD(1) << 30) - ObjectHeaderSize)); // Don't worry, compiler will not really use multiply instruction here MWORD objectSize = SizeOfPointers(oops); OTE* ote; allocObject(objectSize, ote); ASSERT((objectSize > MaxSizeOfPoolObject && ote->heapSpace() == OTEFlags::NormalSpace) || ote->heapSpace() == OTEFlags::PoolSpace); // These are stored in the object itself ASSERT(ote->getSize() == objectSize); classPointer->countUp(); ote->m_oteClass = classPointer; // DO NOT Initialise the fields to nils ASSERT(ote->isPointers()); return reinterpret_cast<PointersOTE*>(ote); }
template <MWORD ImageNullTerms> HRESULT ObjectMemory::LoadObjects(ibinstream & imageFile, const ImageHeader * pHeader, size_t & cbRead) { // Other free OTEs will be threaded in front of the first OTE off the end // of the currently committed table space. We set the free list pointer // to that OTE rather than NULL to distinguish attemps to access off the // end of the current table, which then allows us to dynamically grow it // on demand OTE* pEnd = m_pOT + pHeader->nTableSize; m_pFreePointerList = reinterpret_cast<OTE*>(pEnd); #ifdef _DEBUG unsigned numObjects = NumPermanent; // Allow for VM registry, etc! m_nFreeOTEs = m_nOTSize - pHeader->nTableSize; #endif size_t nDataSize = 0; for (OTE* ote = m_pOT + NumPermanent; ote < pEnd; ote++) { if (!ote->isFree()) { MWORD byteSize = ote->getSize(); MWORD* oldLocation = reinterpret_cast<MWORD*>(ote->m_location); Object* pBody; // Allocate space for the object, and copy into that space if (ote->heapSpace() == OTEFlags::VirtualSpace) { MWORD dwMaxAlloc; if (!imageFile.read(&dwMaxAlloc, sizeof(MWORD))) return ImageReadError(imageFile); cbRead += sizeof(MWORD); pBody = reinterpret_cast<Object*>(AllocateVirtualSpace(dwMaxAlloc, byteSize)); ote->m_location = pBody; } else { if (ote->isNullTerminated()) { ASSERT(!ote->isPointers()); pBody = AllocObj(ote, byteSize + NULLTERMSIZE); if (NULLTERMSIZE > ImageNullTerms) { // Ensure we have a full null-terminator *reinterpret_cast<NULLTERMTYPE*>(static_cast<VariantByteObject*>(pBody)->m_fields+byteSize) = 0; } byteSize += ImageNullTerms; } else { pBody = AllocObj(ote, byteSize); } } markObject(ote); if (!imageFile.read(pBody, byteSize)) return ImageReadError(imageFile); cbRead += byteSize; FixupObject(ote, oldLocation, pHeader); #ifdef _DEBUG numObjects++; #endif } else { // Thread onto the free list ote->m_location = (reinterpret_cast<POBJECT>(m_pFreePointerList)); m_pFreePointerList = ote; #ifdef _DEBUG m_nFreeOTEs++; #endif } } // Note that we don't terminate the free list with a null, because // it must point off into space in order to get a GPF when it // needs to be expanded (at which point we commit more pages) #ifdef _DEBUG ASSERT(numObjects + m_nFreeOTEs == m_nOTSize); ASSERT(m_nFreeOTEs = CountFreeOTEs()); TRACESTREAM << std::dec << numObjects<< L", " << m_nFreeOTEs<< L" free" << std::endl; #endif cbRead += nDataSize; return S_OK; }
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); }