APCHandle* APCString::MakeShared( DataType type, StringData* data, size_t& size) { auto const len = data->size(); auto const cap = roundUpPackedCap(static_cast<uint32_t>(len)); auto const apcStr = new (cap + 1) APCString(type); auto const capCode = packedCapToCode(cap); size = cap + 1 + sizeof(APCString); apcStr->m_data.m_data = reinterpret_cast<char*>(apcStr + 1); apcStr->m_data.m_capAndCount = capCode; // count=0 apcStr->m_data.m_len = len; // don't store hash apcStr->m_data.m_data[len] = 0; auto const mcret = memcpy(apcStr->m_data.m_data, data->data(), len); auto const ret = reinterpret_cast<APCString*>(mcret) - 1; // Recalculating ret from mcret avoids a spill. ret->m_data.preCompute(); assert(ret == apcStr); assert(apcStr->m_data.m_hash != 0); assert(ret->m_data.m_data[len] == 0); assert(ret->m_data.m_count == 0); assert(ret->m_data.isFlat()); assert(ret->m_data.checkSane()); return ret->getHandle(); }
APCHandle::Pair APCString::MakeSharedString(DataType type, StringData* data) { auto const len = data->size(); auto const cap = roundUpPackedCap(static_cast<uint32_t>(len)); auto const capCode = packedCapToCode(cap); auto apcStr = new (cap + 1) APCString(type); auto size = cap + 1 + sizeof(APCString); apcStr->m_str.m_data = reinterpret_cast<char*>(apcStr + 1); apcStr->m_str.m_capAndCount = HeaderKind::String << 24 | capCode; // count=0 apcStr->m_str.m_len = len; // don't store hash apcStr->m_str.m_data[len] = 0; assert(apcStr == reinterpret_cast<APCString*>(apcStr->m_str.m_data) - 1); auto const mcret = memcpy(apcStr->m_str.m_data, data->data(), len); apcStr = reinterpret_cast<APCString*>(mcret) - 1; // Recalculating apcStr from mcret avoids a spill. apcStr->m_str.preCompute(); assert(apcStr->m_str.m_hash != 0); assert(apcStr->m_str.m_data[len] == 0); assert(apcStr->m_str.m_count == 0); assert(apcStr->m_str.isFlat()); assert(apcStr->m_str.checkSane()); return {apcStr->getHandle(), size}; }
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 < kPackedCapCodeThreshold, ""); auto const need = sizeof(StringData) + len + 1; auto const cap = MemoryManager::smartSizeClass(need); auto const sd = static_cast<StringData*>(MM().smartMallocSize(cap)); auto const pdst = reinterpret_cast<char*>(sd + 1); auto const capCode = cap - kCapOverhead; assert(capCode == packedCapToCode(cap - kCapOverhead)); sd->m_data = pdst; sd->m_capAndCount = HeaderKind::String << 24 | capCode; // count=0 sd->m_lenAndHash = len | int64_t{hash} << 32; pdst[len] = 0; auto const mcret = memcpy(pdst, psrc, len); 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->m_count == 0); assert(ret->m_hash == hash); assert(ret->isFlat()); assert(ret->checkSane()); return ret; }
// create either a static or an uncounted string. // Diffrence between static and uncounted is in the lifetime // of the string. Static are alive for the lifetime of the process. // Uncounted are not ref counted but will be deleted at some point. StringData* StringData::MakeShared(StringSlice sl, bool trueStatic) { if (UNLIKELY(sl.len > StringData::MaxSize)) { throw_string_too_large(sl.len); } auto const encodable = roundUpPackedCap(sl.len); auto const need = encodable + kCapOverhead; auto const sd = static_cast<StringData*>( trueStatic ? low_malloc(need) : malloc(need) ); auto const data = reinterpret_cast<char*>(sd + 1); auto const capCode = packedCapToCode(encodable); sd->m_data = data; sd->m_capAndCount = HeaderKind::String << 24 | capCode; // count=0 sd->m_lenAndHash = sl.len; // hash=0 data[sl.len] = 0; auto const mcret = memcpy(data, sl.ptr, sl.len); auto const ret = reinterpret_cast<StringData*>(mcret) - 1; // Recalculating ret from mcret avoids a spill. assert(ret->m_hash == 0); assert(ret->m_count == 0); if (trueStatic) { ret->setStatic(); } else { ret->setUncounted(); } assert(ret == sd); assert(ret->isFlat()); assert(trueStatic ? ret->isStatic() : ret->isUncounted()); assert(ret->checkSane()); return ret; }