NEVER_INLINE APCHandle::Pair APCObject::ConstructSlow(ObjectData* objectData, ClassOrName name) { Array odProps; objectData->o_getArray(odProps); auto const propCount = odProps.size(); auto size = sizeof(APCObject) + sizeof(Prop) * propCount; auto const apcObj = new (malloc_huge(size)) APCObject(name, propCount); if (!propCount) return {apcObj->getHandle(), size}; auto prop = apcObj->props(); for (ArrayIter it(odProps); !it.end(); it.next(), ++prop) { Variant key(it.first()); assert(key.isString()); auto const rval = it.secondRval(); if (!isNullType(tvToCell(rval).type())) { auto val = APCHandle::Create(VarNR(rval.tv()), false, APCHandleLevel::Inner, true); prop->val = val.handle; size += val.size; } else { prop->val = nullptr; } const String& keySD = key.asCStrRef(); if (!keySD.empty() && *keySD.data() == '\0') { int32_t subLen = keySD.find('\0', 1) + 1; String cls = keySD.substr(1, subLen - 2); if (cls.size() == 1 && cls[0] == '*') { // Protected. prop->ctx = nullptr; } else { // Private. auto* ctx = Unit::lookupClass(cls.get()); if (ctx && ctx->attrs() & AttrUnique) { prop->ctx = ctx; } else { prop->ctx = makeStaticString(cls.get()); } } prop->name = makeStaticString(keySD.substr(subLen)); } else { prop->ctx = nullptr; prop->name = makeStaticString(keySD.get()); } } assert(prop == apcObj->props() + propCount); return {apcObj->getHandle(), size}; }
void *cgc_malloc(cgc_size_t size) { if (size == 0) return NULL; if (size + HEADER_PADDING >= NEW_CHUNK_SIZE) return malloc_huge(size); #ifdef PATCHED if (size >= 0x80000000) return NULL; #endif if (size % ALIGNMENT != 0) size = (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1); if (size >= 0x80000000) return NULL; size += HEADER_PADDING; struct blk_t *blk = NULL; int sc_i = find_fit(size, &blk); /* Allocate a new block if no fit */ if (blk == NULL) { if (allocate_new_blk() != 0) { return NULL; } else { sc_i = NUM_FREE_LISTS - 1; blk = cgc_free_lists[sc_i]; } } /* Remove the block we're going to use from the free list */ cgc_remove_from_flist(blk); /* Split the block into two pieces if possible */ cgc_size_t sdiff = blk->size - size; if (sdiff > 2 * HEADER_PADDING) { struct blk_t *nb = (struct blk_t *)((intptr_t)blk + size); nb->size = sdiff; nb->free = 1; nb->fsucc = NULL; nb->fpred = NULL; blk->size = size; /* Patch up blk list pointers */ nb->prev = blk; nb->next = blk->next; if (blk->next) blk->next->prev = nb; blk->next = nb; /* Put the new block into the free list */ cgc_insert_into_flist(nb); } return (void *)((intptr_t)blk + HEADER_PADDING); }
APCHandle::Pair APCObject::Construct(ObjectData* objectData) { // This function assumes the object and object/array down the tree have no // internal references and do not implement the serializable interface. assert(!objectData->instanceof(SystemLib::s_SerializableClass)); auto cls = objectData->getVMClass(); auto clsOrName = make_class(cls); if (clsOrName.right()) return ConstructSlow(objectData, clsOrName); // We have a persistent Class. Build an array of APCHandle* to mirror the // declared properties in the object. auto const propInfo = cls->declProperties(); auto const hasDynProps = objectData->hasDynProps(); auto const numRealProps = propInfo.size(); auto const numApcProps = numRealProps + hasDynProps; auto size = sizeof(APCObject) + sizeof(APCHandle*) * numApcProps; auto const apcObj = new (malloc_huge(size)) APCObject(clsOrName, numApcProps); apcObj->m_persistent = 1; // Set a few more flags for faster fetching: whether or not the object has a // wakeup method, and whether or not we can use a fast path that avoids // default-initializing properties before setting them to their APC values. if (!cls->lookupMethod(s___wakeup.get())) apcObj->m_no_wakeup = 1; if (!cls->instanceCtor()) { apcObj->m_fast_init = 1; } auto const apcPropVec = apcObj->persistentProps(); auto const objPropVec = objectData->propVec(); const TypedValueAux* propInit = nullptr; for (unsigned i = 0; i < numRealProps; ++i) { auto const attrs = propInfo[i].attrs; assert((attrs & AttrStatic) == 0); const TypedValue* objProp; if (attrs & AttrBuiltin) { // Special properties like the Memoize cache should be set to their // default value, not the current value. if (propInit == nullptr) { propInit = cls->pinitVec().empty() ? &cls->declPropInit()[0] : &(*cls->getPropData())[0]; } objProp = propInit + i; } else { objProp = objPropVec + i; } auto val = APCHandle::Create(tvAsCVarRef(objProp), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[i] = val.handle; } if (UNLIKELY(hasDynProps)) { auto val = APCHandle::Create(objectData->dynPropArray(), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[numRealProps] = val.handle; } return {apcObj->getHandle(), size}; }