void APCHandle::deleteShared() { assert(!isUncounted()); switch (m_type) { case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfUninit: case KindOfNull: case KindOfStaticString: delete APCTypedValue::fromHandle(this); break; case KindOfString: delete APCString::fromHandle(this); break; case KindOfArray: APCArray::Delete(this); break; case KindOfObject: APCObject::Delete(this); break; default: assert(false); } }
// 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. ALWAYS_INLINE StringData* StringData::MakeShared(StringSlice sl, bool trueStatic) { if (UNLIKELY(sl.len > StringData::MaxSize)) { throw_string_too_large(sl.len); } auto const cc = CapCode::ceil(sl.len); auto const need = cc.decode() + kCapOverhead; auto const sd = static_cast<StringData*>( trueStatic ? low_malloc(need) : malloc(need) ); auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; auto const count = trueStatic ? StaticValue : UncountedValue; sd->m_hdr.init(cc, HeaderKind::String, count); sd->m_len = sl.len; // m_hash is computed soon. 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. ret->preCompute(); // get m_hash right assert(ret == sd); assert(ret->isFlat()); assert(trueStatic ? ret->isStatic() : ret->isUncounted()); assert(ret->checkSane()); return ret; }
Cell lookupClassConstantTv(TypedValue* cache, const NamedEntity* ne, const StringData* cls, const StringData* cns) { Cell clsCns = g_vmContext->lookupClsCns(ne, cls, cns); assert(isUncounted(clsCns)); cellDup(clsCns, *cache); return clsCns; }
void StringData::dump() const { auto s = slice(); printf("StringData(%d) (%s%s%s%d): [", m_hdr.count, isProxy() ? "proxy " : "", isStatic() ? "static " : "", isUncounted() ? "uncounted " : "", static_cast<int>(s.size())); for (uint32_t i = 0; i < s.size(); i++) { char ch = s.data()[i]; if (isprint(ch)) { printf("%c", ch); } else { printf("\\x%02x", ch); } } printf("]\n"); }
void APCHandle::deleteShared() { assert(!isUncounted()); switch (m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: return; case KindOfInt64: case KindOfDouble: case KindOfStaticString: case KindOfPersistentArray: delete APCTypedValue::fromHandle(this); return; case KindOfString: APCString::Delete(APCString::fromHandle(this)); return; case KindOfArray: APCArray::Delete(this); return; case KindOfObject: if (isAPCCollection()) { APCCollection::Delete(this); return; } APCObject::Delete(this); return; case KindOfResource: case KindOfRef: case KindOfClass: break; } not_reached(); }
// 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. ALWAYS_INLINE StringData* StringData::MakeShared(StringSlice sl, bool trueStatic) { if (UNLIKELY(sl.len > StringData::MaxSize)) { throw_string_too_large(sl.len); } auto const cc = CapCode::ceil(sl.len); auto const need = cc.decode() + kCapOverhead; auto const sd = static_cast<StringData*>( trueStatic ? low_malloc(need) : malloc(need) ); auto const data = reinterpret_cast<char*>(sd + 1); sd->m_data = data; sd->m_hdr.init(cc, HeaderKind::String, 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->getCount() == 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; }
// 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; }
void StringData::destructUncounted() { assert(checkSane() && isUncounted()); assert(isFlat()); free(this); }