StringData* StringData::Make(const APCString* shared) { // No need to check if len > MaxSize, because if it were we'd never // have made the StringData in the APCVariant without throwing. assert(size_t(shared->getStringData()->size()) <= size_t(MaxSize)); auto const data = shared->getStringData(); auto const len = data->size(); if (UNLIKELY(len > SmallStringReserve)) { return MakeAPCSlowPath(shared); } // small-string path: make a flat copy. static_assert(SmallStringReserve + kCapOverhead <= CapCode::Threshold, ""); static_assert(SmallStringReserve + kCapOverhead == 64, ""); auto const sd = allocFlatSmallImpl(SmallStringReserve); sd->m_lenAndHash = data->m_lenAndHash; auto const psrc = data->data(); auto const pdst = reinterpret_cast<char*>(sd + 1); auto const mcret = memcpy(pdst, psrc, len + 1); // also copy the tailing 0 auto const ret = reinterpret_cast<StringData*>(mcret) - 1; // Recalculating ret from mcret avoids a spill. assert(ret == sd); assert(ret->m_len == len); assert(ret->hasExactlyOneRef()); assert(ret->m_hash == data->m_hash); assert(ret->isFlat()); assert(ret->checkSane()); return ret; }
StringData* StringData::Make(const APCString* shared) { // No need to check if len > MaxSize, because if it were we'd never // have made the StringData in the APCVariant without throwing. assert(size_t(shared->getStringData()->size()) <= size_t(MaxSize)); auto const data = shared->getStringData(); auto const len = data->size(); if (UNLIKELY(len > SmallStringReserve)) { return MakeAPCSlowPath(shared); } // small-string path auto const psrc = data->data(); auto const hash = data->m_hash & STRHASH_MASK; assert(hash != 0); static_assert(SmallStringReserve + sizeof(StringData) + 1 < CapCode::Threshold, ""); auto const need = sizeof(StringData) + len + 1; auto const cap = MemoryManager::smallSizeClass(need); auto const sd = static_cast<StringData*>(MM().mallocSmallSize(cap)); auto const pdst = reinterpret_cast<char*>(sd + 1); auto const cc = CapCode::ceil(cap - kCapOverhead); assert(cc.code == cap - kCapOverhead); sd->m_data = pdst; sd->m_hdr.init(cc, HeaderKind::String, 1); sd->m_lenAndHash = len | int64_t{hash} << 32; // pdst[len] = 0; auto const mcret = memcpy(pdst, psrc, len + 1); auto const ret = reinterpret_cast<StringData*>(mcret) - 1; // Recalculating ret from mcret avoids a spill. // Note: this return value thing is doing a dead lea into %rsi in // the caller for some reason. assert(ret == sd); assert(ret->m_len == len); assert(ret->hasExactlyOneRef()); assert(ret->m_hash == hash); assert(ret->isFlat()); assert(ret->checkSane()); return ret; }