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; }
// There are some fixups that we can only apply after all the objects are loaded, because // they involve reference from one object to other objects which may not be available // during the normal load process. These fixes are applied here void ObjectMemory::PostLoadFix() { // Special case handling for Contexts because we store // the sp's as integers in the image file, but at // run-time they are expected to be direct pointers const OTE* pEnd = m_pOT + m_nOTSize; // Loop invariant for (OTE* ote = m_pOT; ote < pEnd; ote++) { if (!ote->isFree()) { if (ote->isBytes()) { #ifdef _DEBUG { // Its a byte object, and may be null terminated const Behavior* behavior = ote->m_oteClass->m_location; const BytesOTE* oteBytes = reinterpret_cast<const BytesOTE*>(ote); const VariantByteObject* object = oteBytes->m_location; ASSERT(behavior->m_instanceSpec.m_nullTerminated == ote->isNullTerminated()); } #endif } else if (ote->m_oteClass == _Pointers.ClassProcess) { ASSERT(ote->heapSpace() == OTEFlags::VirtualSpace); ProcessOTE* oteProcess = reinterpret_cast<ProcessOTE*>(ote); Process* process = oteProcess->m_location; process->PostLoadFix(oteProcess); } } } ProtectConstSpace(PAGE_READONLY); #if defined(_DEBUG) && 0 { // Dump out the pointers TRACESTREAM << NumPointers<< L" VM Pointers..." << std::endl; for (int i = 0; i < NumPointers; i++) { VariantObject* obj = static_cast<VariantObject*>(m_pConstObjs); POTE pote = POTE(obj->m_fields[i]); TRACESTREAM << i<< L": " << pote << std::endl; } } #endif }
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; }