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); }
// 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; }
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); }