void tvCastToResourceInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); switch (tv->m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: break; case KindOfString: case KindOfArray: case KindOfObject: tvDecRef(tv); break; case KindOfResource: // no op, return return; default: assert(false); break; } tv->m_type = KindOfResource; tv->m_data.pres = NEWOBJ(DummyResource); tv->m_data.pres->incRefCount(); return; }
void tvCastToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); ArrayData * a; switch (tv->m_type) { case KindOfUninit: case KindOfNull: a = ArrayData::Create(); break; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: a = ArrayData::Create(tvAsVariant(tv)); break; case KindOfString: { a = ArrayData::Create(tvAsVariant(tv)); tvDecRefStr(tv); break; } case KindOfArray: return; case KindOfObject: { // For objects, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pobj->o_toArray(); return; } case KindOfResource: { // For resources, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pres->o_toArray(); return; } default: assert(false); a = ArrayData::Create(); break; } tv->m_data.parr = a; tv->m_type = KindOfArray; tv->m_data.parr->incRefCount(); }
void tvCastToObjectInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); ObjectData* o; switch (tv->m_type) { case KindOfUninit: case KindOfNull: o = SystemLib::AllocStdClassObject(); break; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: { o = SystemLib::AllocStdClassObject(); o->o_set(s_scalar, tvAsVariant(tv)); break; } case KindOfString: { o = SystemLib::AllocStdClassObject(); o->o_set(s_scalar, tvAsVariant(tv)); tvDecRefStr(tv); break; } case KindOfArray: { // For arrays, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.parr->toObject(); return; } case KindOfObject: return; case KindOfResource: return; default: assert(false); o = SystemLib::AllocStdClassObject(); break; } tv->m_data.pobj = o; tv->m_type = KindOfObject; tv->m_data.pobj->incRefCount(); }
void tvCastToDoubleInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); double d; switch (tv->m_type) { case KindOfUninit: case KindOfNull: d = 0.0; break; case KindOfBoolean: assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL); case KindOfInt64: d = (double)(tv->m_data.num); break; case KindOfDouble: return; case KindOfStaticString: d = tv->m_data.pstr->toDouble(); break; case KindOfString: d = tv->m_data.pstr->toDouble(); tvDecRefStr(tv); break; case KindOfArray: { d = (double)(tv->m_data.parr->empty() ? 0LL : 1LL); tvDecRefArr(tv); break; } case KindOfObject: { d = tv->m_data.pobj->o_toDouble(); tvDecRefObj(tv); break; } case KindOfResource: { d = tv->m_data.pres->o_toDouble(); tvDecRefRes(tv); break; } default: assert(false); d = 0.0; break; } tv->m_data.dbl = d; tv->m_type = KindOfDouble; }
double tvCastToDouble(TypedValue* tv) { assert(tvIsPlausible(*tv)); if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } switch(tv->m_type) { case KindOfUninit: case KindOfNull: return 0; case KindOfBoolean: assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL); // Fall through case KindOfInt64: return (double)(tv->m_data.num); case KindOfDouble: return tv->m_data.dbl; case KindOfStaticString: case KindOfString: return tv->m_data.pstr->toDouble(); case KindOfArray: return tv->m_data.parr->empty() ? 0.0 : 1.0; case KindOfObject: return tv->m_data.pobj->o_toDouble(); case KindOfResource: return tv->m_data.pres->o_toDouble(); default: not_reached(); } }
void checkFrame(ActRec* fp, Cell* sp, bool checkLocals) { const Func* func = fp->m_func; func->validate(); if (func->cls()) { assert(!func->cls()->isZombie()); } if (fp->hasVarEnv()) { assert(fp->getVarEnv()->getCfp() == fp); } // TODO: validate this pointer from actrec int numLocals = func->numLocals(); assert(sp <= (Cell*)fp - func->numSlotsInFrame() || func->isGenerator()); if (checkLocals) { int numParams = func->numParams(); for (int i=0; i < numLocals; i++) { if (i >= numParams && func->isGenerator() && i < func->numNamedLocals()) { continue; } assert(tvIsPlausible(*frame_local(fp, i))); } } // We unfortunately can't do the same kind of check for the stack // without knowing about FPI regions, because it may contain // ActRecs. }
bool tvCoerceParamToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); switch (tv->m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfPersistentString: case KindOfString: return false; case KindOfPersistentArray: case KindOfArray: return true; case KindOfObject: if (LIKELY(tv->m_data.pobj->isCollection())) { tvAsVariant(tv) = tv->m_data.pobj->toArray(); return true; } return false; case KindOfResource: return false; case KindOfRef: case KindOfClass: break; } not_reached(); }
bool tvCoerceParamToBooleanInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); switch (tv->m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfPersistentString: case KindOfString: // In PHP 7 mode handling of null types is stricter if (tv->m_type == KindOfNull && RuntimeOption::PHP7_ScalarTypes) { return false; } tvCastToBooleanInPlace(tv); return true; case KindOfPersistentArray: case KindOfArray: case KindOfObject: case KindOfResource: return false; case KindOfRef: case KindOfClass: break; } not_reached(); }
void tvCastToStringInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); StringData* s; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: s = staticEmptyString(); goto static_string; case KindOfBoolean: s = tv->m_data.num ? s_1.get() : staticEmptyString(); goto static_string; case KindOfInt64: s = buildStringData(tv->m_data.num); continue; case KindOfDouble: s = buildStringData(tv->m_data.dbl); continue; case KindOfStaticString: case KindOfString: return; case KindOfArray: raise_notice("Array to string conversion"); s = array_string.get(); tvDecRefArr(tv); goto static_string; case KindOfObject: // For objects, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pobj->invokeToString(); return; case KindOfResource: // For resources, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pres->o_toString(); return; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); s->incRefCount(); tv->m_data.pstr = s; tv->m_type = KindOfString; return; static_string: tv->m_data.pstr = s; tv->m_type = KindOfStaticString; }
void tvCastToBooleanInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); bool b; switch (tv->m_type) { case KindOfUninit: case KindOfNull: b = false; break; case KindOfBoolean: return; case KindOfInt64: b = (tv->m_data.num != 0LL); break; case KindOfDouble: b = (tv->m_data.dbl != 0); break; case KindOfStaticString: b = tv->m_data.pstr->toBoolean(); break; case KindOfString: b = tv->m_data.pstr->toBoolean(); tvDecRefStr(tv); break; // Note that this is intentionally incorrect for NameValueTableWrapper, for // which getSize() will always return -1, empty or not. case KindOfArray: b = !!tv->m_data.parr->getSize(); tvDecRefArr(tv); break; case KindOfObject: b = tv->m_data.pobj->o_toBoolean(); tvDecRefObj(tv); break; case KindOfResource: b = tv->m_data.pres->o_toBoolean(); tvDecRefRes(tv); break; default: assert(false); b = false; break; } tv->m_data.num = b; tv->m_type = KindOfBoolean; }
StringData* tvCastToString(const TypedValue* tv) { assert(tvIsPlausible(*tv)); if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } StringData* s; switch (tv->m_type) { case KindOfUninit: case KindOfNull: return empty_string.get(); case KindOfBoolean: return tv->m_data.num ? s_1.get() : empty_string.get(); case KindOfInt64: s = buildStringData(tv->m_data.num); break; case KindOfDouble: s = buildStringData(tv->m_data.dbl); break; case KindOfStaticString: return tv->m_data.pstr; case KindOfString: s = tv->m_data.pstr; break; case KindOfArray: raise_notice("Array to string conversion"); return array_string.get(); case KindOfObject: return tv->m_data.pobj->invokeToString().detach(); case KindOfResource: return tv->m_data.pres->o_toString().detach(); default: not_reached(); } s->incRefCount(); return s; }
void tvCastToDoubleInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); double d; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: d = 0.0; continue; case KindOfBoolean: assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL); // fallthru case KindOfInt64: d = (double)(tv->m_data.num); continue; case KindOfDouble: return; case KindOfPersistentString: d = tv->m_data.pstr->toDouble(); continue; case KindOfString: d = tv->m_data.pstr->toDouble(); tvDecRefStr(tv); continue; case KindOfPersistentArray: d = tv->m_data.parr->empty() ? 0 : 1; continue; case KindOfArray: d = tv->m_data.parr->empty() ? 0 : 1; tvDecRefArr(tv); continue; case KindOfObject: d = tv->m_data.pobj->toDouble(); tvDecRefObj(tv); continue; case KindOfResource: d = tv->m_data.pres->data()->o_toDouble(); tvDecRefRes(tv); continue; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); tv->m_data.dbl = d; tv->m_type = KindOfDouble; }
Type typeFromTV(const TypedValue* tv) { assertx(tv->m_type == KindOfClass || tvIsPlausible(*tv)); if (tv->m_type == KindOfObject) { auto const cls = tv->m_data.pobj->getVMClass(); // We only allow specialization on classes that can't be overridden for // now. If this changes, then this will need to specialize on sub object // types instead. if (!cls || !(cls->attrs() & AttrNoOverride)) return TObj; return Type::ExactObj(cls); } if (isArrayType(tv->m_type)) { auto const ar = tv->m_data.parr; if (ar->kind() == ArrayData::kStructKind) { return Type::Array(StructArray::asStructArray(ar)->shape()); } return Type::Array(tv->m_data.parr->kind()); } auto outer = tv->m_type; auto inner = KindOfUninit; if (outer == KindOfPersistentString) outer = KindOfString; if (outer == KindOfRef) { inner = tv->m_data.pref->tv()->m_type; if (inner == KindOfPersistentString) inner = KindOfString; else if (inner == KindOfPersistentArray) inner = KindOfArray; } return Type(outer, inner); }
bool tvCoerceParamToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); switch (tv->m_type) { DT_UNCOUNTED_CASE: case KindOfString: return false; case KindOfArray: return true; case KindOfObject: if (LIKELY(tv->m_data.pobj->isCollection())) { tvAsVariant(tv) = tv->m_data.pobj->toArray(); return true; } return false; case KindOfResource: return false; case KindOfRef: case KindOfClass: break; } not_reached(); }
void tvCastToResourceInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); do { switch (tv->m_type) { DT_UNCOUNTED_CASE: continue; case KindOfString: case KindOfArray: case KindOfObject: tvDecRef(tv); continue; case KindOfResource: // no op, return return; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); tv->m_type = KindOfResource; tv->m_data.pres = newres<DummyResource>(); }
void tvCastToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); ArrayData* a; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: a = ArrayData::Create(); continue; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfPersistentString: a = ArrayData::Create(tvAsVariant(tv)); continue; case KindOfString: a = ArrayData::Create(tvAsVariant(tv)); tvDecRefStr(tv); continue; case KindOfPersistentArray: case KindOfArray: { ArrayData* adIn = tv->m_data.parr; if (adIn->isVecArray()) { tv->m_data.parr = PackedArray::MakeFromVec(adIn, adIn->cowCheck()); tv->m_type = KindOfArray; } else if (adIn->isDict()) { tv->m_data.parr = MixedArray::MakeFromDict(adIn, adIn->cowCheck()); tv->m_type = KindOfArray; } return; } case KindOfObject: // For objects, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pobj->toArray(); return; case KindOfResource: a = ArrayData::Create(tvAsVariant(tv)); tvDecRefRes(tv); continue; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); assert(!a->isRefCounted() || a->hasExactlyOneRef()); tv->m_data.parr = a; tv->m_type = KindOfArray; }
void tvCastToBooleanInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); bool b; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: b = false; continue; case KindOfBoolean: return; case KindOfInt64: b = (tv->m_data.num != 0LL); continue; case KindOfDouble: b = (tv->m_data.dbl != 0); continue; case KindOfStaticString: b = tv->m_data.pstr->toBoolean(); continue; case KindOfString: b = tv->m_data.pstr->toBoolean(); tvDecRefStr(tv); continue; case KindOfArray: b = !!tv->m_data.parr->size(); tvDecRefArr(tv); continue; case KindOfObject: b = tv->m_data.pobj->toBoolean(); tvDecRefObj(tv); continue; case KindOfResource: b = tv->m_data.pres->o_toBoolean(); tvDecRefRes(tv); continue; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); tv->m_data.num = b; tv->m_type = KindOfBoolean; }
bool tvCoerceParamToDoubleInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (!tvCanBeCoercedToNumber(tv)) { return false; } tvCastToDoubleInPlace(tv); return true; }
bool tvCoerceParamToBooleanInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (tv->m_type == KindOfArray || tv->m_type == KindOfObject || tv->m_type == KindOfResource) { return false; } tvCastToBooleanInPlace(tv); return true; }
bool tvCoerceParamToNullableObjectInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (IS_NULL_TYPE(tv->m_type)) { // See comment in tvCastToNullableObjectInPlace tv->m_data.pobj = nullptr; return true; } return tv->m_type == KindOfObject; }
void tvCastToObjectInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); ObjectData* o; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: o = SystemLib::AllocStdClassObject().detach(); continue; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfPersistentString: case KindOfResource: o = SystemLib::AllocStdClassObject().detach(); o->o_set(s_scalar, tvAsVariant(tv)); continue; case KindOfString: o = SystemLib::AllocStdClassObject().detach(); o->o_set(s_scalar, tvAsVariant(tv)); tvDecRefStr(tv); continue; case KindOfPersistentVec: case KindOfVec: case KindOfPersistentDict: case KindOfDict: case KindOfPersistentKeyset: case KindOfKeyset: tvCastToArrayInPlace(tv); // Fall-through to array case case KindOfPersistentArray: case KindOfArray: // For arrays, we fall back on the Variant machinery tvAsVariant(tv) = ObjectData::FromArray(tv->m_data.parr); return; case KindOfObject: return; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); tv->m_data.pobj = o; tv->m_type = KindOfObject; assert(cellIsPlausible(*tv)); }
void NameValueTable::rehash(Elm* const oldTab, const size_t oldMask) { for (Elm* srcElm = &oldTab[oldMask]; srcElm != &oldTab[-1]; --srcElm) { if (srcElm->m_name) { assert(srcElm->m_tv.m_type == KindOfNamedLocal || tvIsPlausible(srcElm->m_tv)); Elm* dstElm = insertImpl(srcElm->m_name); dstElm->m_name = srcElm->m_name; dstElm->m_tv = srcElm->m_tv; } } }
void tvCastToStringInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); auto string = [&](StringData* s) { tv->m_type = KindOfString; tv->m_data.pstr = s; }; auto persistentString = [&](StringData* s) { assert(!s->isRefCounted()); tv->m_type = KindOfPersistentString; tv->m_data.pstr = s; }; switch (tv->m_type) { case KindOfUninit: case KindOfNull: return persistentString(staticEmptyString()); case KindOfBoolean: return persistentString(tv->m_data.num ? s_1.get() : staticEmptyString()); case KindOfInt64: return string(buildStringData(tv->m_data.num)); case KindOfDouble: return string(buildStringData(tv->m_data.dbl)); case KindOfPersistentString: case KindOfString: return; case KindOfArray: case KindOfPersistentArray: raise_notice("Array to string conversion"); if (tv->m_type == KindOfArray) tvDecRefArr(tv); return persistentString(array_string.get()); case KindOfObject: // For objects, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pobj->invokeToString(); return; case KindOfResource: // For resources, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pres->data()->o_toString(); return; case KindOfRef: case KindOfClass: break; } not_reached(); }
bool tvCoerceParamToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (tv->m_type == KindOfArray) { return true; } else if (tv->m_type == KindOfObject) { tvAsVariant(tv) = tv->m_data.pobj->o_toArray(); return true; } else if (tv->m_type == KindOfResource) { tvAsVariant(tv) = tv->m_data.pres->o_toArray(); return true; } return false; }
void tvCastToArrayInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); ArrayData* a; do { switch (tv->m_type) { case KindOfUninit: case KindOfNull: a = ArrayData::Create(); continue; case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: a = ArrayData::Create(tvAsVariant(tv)); continue; case KindOfString: a = ArrayData::Create(tvAsVariant(tv)); tvDecRefStr(tv); continue; case KindOfArray: return; case KindOfObject: // For objects, we fall back on the Variant machinery tvAsVariant(tv) = tv->m_data.pobj->toArray(); return; case KindOfResource: a = ArrayData::Create(tvAsVariant(tv)); tvDecRefRes(tv); continue; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); assert(a->isStatic() || a->hasExactlyOneRef()); tv->m_data.parr = a; tv->m_type = KindOfArray; }
bool tvCoerceParamToInt64InPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (!tvCanBeCoercedToNumber(tv)) { return false; } // In PHP 7 mode doubles only convert to integers when the conversion is non- // narrowing if (RuntimeOption::PHP7_ScalarTypes && tv->m_type == KindOfDouble) { if (tv->m_data.dbl < std::numeric_limits<int64_t>::min()) return false; if (tv->m_data.dbl > std::numeric_limits<int64_t>::max()) return false; if (std::isnan(tv->m_data.dbl)) return false; } tvCastToInt64InPlace(tv); return true; }
double tvCastToDouble(TypedValue* tv) { assert(tvIsPlausible(*tv)); if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } switch (tv->m_type) { case KindOfUninit: case KindOfNull: return 0; case KindOfBoolean: assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL); // fallthru case KindOfInt64: return (double)(tv->m_data.num); case KindOfDouble: return tv->m_data.dbl; case KindOfPersistentString: case KindOfString: return tv->m_data.pstr->toDouble(); case KindOfPersistentVec: case KindOfVec: case KindOfPersistentDict: case KindOfDict: case KindOfPersistentKeyset: case KindOfKeyset: case KindOfPersistentArray: case KindOfArray: return tv->m_data.parr->empty() ? 0.0 : 1.0; case KindOfObject: return tv->m_data.pobj->toDouble(); case KindOfResource: return tv->m_data.pres->data()->o_toDouble(); case KindOfRef: case KindOfClass: break; } not_reached(); }
StringData* tvCastToString(const TypedValue* tv) { assert(tvIsPlausible(*tv)); if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } switch (tv->m_type) { case KindOfUninit: case KindOfNull: return staticEmptyString(); case KindOfBoolean: return tv->m_data.num ? s_1.get() : staticEmptyString(); case KindOfInt64: return buildStringData(tv->m_data.num); case KindOfDouble: return buildStringData(tv->m_data.dbl); case KindOfPersistentString: return tv->m_data.pstr; case KindOfString: { auto s = tv->m_data.pstr; s->incRefCount(); return s; } case KindOfPersistentArray: case KindOfArray: raise_notice("Array to string conversion"); return array_string.get(); case KindOfObject: return tv->m_data.pobj->invokeToString().detach(); case KindOfResource: return tv->m_data.pres->data()->o_toString().detach(); case KindOfRef: case KindOfClass: not_reached(); } not_reached(); }
bool tvCoerceParamToStringInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); switch (tv->m_type) { case KindOfArray: return false; case KindOfObject: if (tv->m_data.pobj->hasToString()) { tvAsVariant(tv) = tv->m_data.pobj->invokeToString(); return true; } return false; case KindOfResource: return false; default: break; } tvCastToStringInPlace(tv); return true; }
bool PackedArray::checkInvariants(const ArrayData* arr) { assert(arr->isPacked()); assert(arr->m_packedCap < kMaxPackedCap); assert(arr->m_size <= arr->m_packedCap); static_assert(ArrayData::kPackedKind == 0, ""); // Note that m_pos < m_size is not an invariant, because an array // that grows will only adjust m_size to zero on the old array. // This loop is too slow for normal use, but can be enabled to debug // packed arrays. if (false) { auto ptr = reinterpret_cast<const TypedValue*>(arr + 1); auto const stop = ptr + arr->m_size; for (; ptr != stop; ptr++) { assert(ptr->m_type != KindOfUninit); assert(tvIsPlausible(*ptr)); } } return true; }