Beispiel #1
0
void DataWalker::traverseData(ArrayData* data,
                              DataFeature& features,
                              PointerSet& visited) const {
  for (ArrayIter iter(data); iter; ++iter) {
    const Variant& var = iter.secondRef();

    if (var.isReferenced()) {
      Variant *pvar = var.getRefData();
      if (markVisited(pvar, features, visited)) {
        if (canStopWalk(features)) return;
        continue; // don't recurse forever; we already went down this path
      }
      // Right now consider it circular even if the referenced variant only
      // showed up in one spot.  This could be revisted later.
      features.isCircular = true;
      if (canStopWalk(features)) return;
    }

    auto const type = var.getType();
    // cheap enough, do it always
    features.hasRefCountReference = isRefcountedType(type);
    if (type == KindOfObject) {
      features.hasObjectOrResource = true;
      traverseData(var.getObjectData(), features, visited);
    } else if (isArrayType(type)) {
      traverseData(var.getArrayData(), features, visited);
    } else if (type == KindOfResource) {
      features.hasObjectOrResource = true;
    }
    if (canStopWalk(features)) return;
  }
}
Beispiel #2
0
bool tvDecRefWillRelease(TypedValue* tv) {
  if (!isRefcountedType(tv->m_type)) {
    return false;
  }
  if (tv->m_type == KindOfRef) {
    return tv->m_data.pref->getRealCount() <= 1;
  }
  return TV_GENERIC_DISPATCH(*tv, decWillRelease);
}
Beispiel #3
0
ArrayData* deepCopyDict(ArrayData* arr) {
  assert(arr->isDict());
  Array ar(arr);
  MixedArray::IterateKV(
    MixedArray::asMixed(arr),
    [&](const TypedValue* k, const TypedValue* v) {
      if (!isRefcountedType(v->m_type)) return false;
      Variant value{tvAsCVarRef(v)};
      deepCopy(value.asTypedValue());
      if (value.asTypedValue()->m_data.num != v->m_data.num) {
        ar.set(tvAsCVarRef(k), value);
      }
      return false;
    }
  );
  return ar.detach();
}
Beispiel #4
0
ArrayData* deepCopyVecArray(ArrayData* arr) {
  assert(arr->isVecArray());
  Array ar(arr);
  PackedArray::IterateKV(
    arr,
    [&](const TypedValue* k, const TypedValue* v) {
      if (!isRefcountedType(v->m_type)) return false;
      Variant value{tvAsCVarRef(v)};
      deepCopy(value.asTypedValue());
      if (value.asTypedValue()->m_data.num != v->m_data.num) {
        assert(k->m_type == KindOfInt64);
        ar.set(k->m_data.num, value);
      }
      return false;
    }
  );
  return ar.detach();
}
bool ConcurrentTableSharedStore::constructPrime(const Variant& v,
                                                KeyValuePair& item) {
  if (s_apc_file_storage.getState() !=
      APCFileStorage::StorageState::Invalid &&
      (isRefcountedType(v.getType()))) {
    // Only do the storage for ref-counted type
    String s = apc_serialize(v);
    char *sAddr = s_apc_file_storage.put(s.data(), s.size());
    if (sAddr) {
      item.sAddr = sAddr;
      item.sSize = s.size();
      return false;
    }
  }
  auto pair = APCHandle::Create(v, false, APCHandleLevel::Outer, false);
  item.value = pair.handle;
  item.sSize = pair.size;
  return true;
}
Beispiel #6
0
void RepoQuery::getTypedValue(int iCol, TypedValue& tv) {
  const void* blob;
  size_t size;
  getBlob(iCol, blob, size);
  tvWriteUninit(&tv);
  if (size > 0) {
    String s = String((const char*)blob, size, CopyString);
    Variant v = unserialize_from_string(s);
    if (v.isString()) {
      v = String(makeStaticString(v.asCStrRef().get()));
    } else if (v.isArray()) {
      v = Array(ArrayData::GetScalarArray(v.asCArrRef().get()));
    } else {
      // Serialized variants and objects shouldn't ever make it into the repo.
      assert(!isRefcountedType(v.getType()));
    }
    tvAsVariant(&tv) = v;
  }
}
Beispiel #7
0
ssize_t APCArray::indexOf(const StringData* key) const {
  strhash_t h = key->hash();
  ssize_t bucket = hash()[h & m.m_capacity_mask];
  Bucket* b = buckets();
  while (bucket != -1) {
    if (!isRefcountedType(b[bucket].key->type())) {
      auto const k = APCTypedValue::fromHandle(b[bucket].key);
      if (b[bucket].key->type() != KindOfInt64 &&
          key->same(k->getStringData())) {
        return bucket;
      }
    } else {
      assert(b[bucket].key->type() == KindOfString);
      auto const k = APCString::fromHandle(b[bucket].key);
      if (key->same(k->getStringData())) {
        return bucket;
      }
    }
    bucket = b[bucket].next;
  }
  return -1;
}
Beispiel #8
0
void APCArray::add(APCHandle *key, APCHandle *val) {
  int pos = m.m_num;
  // NOTE: no check on duplication because we assume the original array has no
  // duplication
  Bucket* bucket = buckets() + pos;
  bucket->key = key;
  bucket->val = val;
  m.m_num++;
  int hash_pos;
  if (!isRefcountedType(key->type())) {
    auto const k = APCTypedValue::fromHandle(key);
    hash_pos = (key->type() == KindOfInt64 ?
        k->getInt64() : k->getStringData()->hash()) & m.m_capacity_mask;
  } else {
    assert(key->type() == KindOfString);
    auto const k = APCString::fromHandle(key);
    hash_pos = k->getStringData()->hash() & m.m_capacity_mask;
  }

  int& hp = hash()[hash_pos];
  bucket->next = hp;
  hp = pos;
}
Beispiel #9
0
int Variant::getRefCount() const noexcept {
    return isRefcountedType(m_type) ? tvGetCount(asTypedValue()) : 1;
}
Beispiel #10
0
Variant& Variant::setWithRef(const Variant& v) noexcept {
    setWithRefHelper(v, isRefcountedType(m_type));
    return *this;
}
Beispiel #11
0
bool tvMatchesRepoAuthType(TypedValue tv, RepoAuthType ty) {
  assert(tvIsPlausible(tv));

  bool const initNull = tv.m_type == KindOfNull;

  using T = RepoAuthType::Tag;
  switch (ty.tag()) {
  case T::Uninit:       return tv.m_type == KindOfUninit;
  case T::InitNull:     return initNull;

  case T::OptBool:      if (initNull) return true;
                        // fallthrough
  case T::Bool:         return tv.m_type == KindOfBoolean;
  case T::OptInt:       if (initNull) return true;
                        // fallthrough
  case T::Int:          return tv.m_type == KindOfInt64;
  case T::OptDbl:       if (initNull) return true;
                        // fallthrough
  case T::Dbl:          return tv.m_type == KindOfDouble;
  case T::OptRes:       if (initNull) return true;
                        // fallthrough
  case T::Res:          return tv.m_type == KindOfResource;
  case T::OptObj:       if (initNull) return true;
                        // fallthrough
  case T::Obj:          return tv.m_type == KindOfObject;

  case T::OptSStr:
    if (initNull) return true;
    // fallthrough
  case T::SStr:
    return isStringType(tv.m_type) && tv.m_data.pstr->isStatic();

  case T::OptStr:
    if (initNull) return true;
    // fallthrough
  case T::Str:
    return isStringType(tv.m_type);

  case T::OptSArr:
    if (initNull) return true;
    // fallthrough
  case T::SArr:
    if (!isArrayType(tv.m_type) || !tv.m_data.parr->isStatic()) {
      return false;
    }
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptArr:
    if (initNull) return true;
    // fallthrough
  case T::Arr:
    if (!isArrayType(tv.m_type)) return false;
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptSVArr:
    if (initNull) return true;
    // fallthrough
  case T::SVArr:
    if (!isArrayType(tv.m_type) ||
        !tv.m_data.parr->isStatic() ||
        !tv.m_data.parr->isVArray()) {
      return false;
    }
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptVArr:
    if (initNull) return true;
    // fallthrough
  case T::VArr:
    if (!isArrayType(tv.m_type) || !tv.m_data.parr->isVArray()) return false;
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptSDArr:
    if (initNull) return true;
    // fallthrough
  case T::SDArr:
    if (!isArrayType(tv.m_type) ||
        !tv.m_data.parr->isStatic() ||
        !tv.m_data.parr->isDArray()) {
      return false;
    }
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptDArr:
    if (initNull) return true;
    // fallthrough
  case T::DArr:
    if (!isArrayType(tv.m_type) || !tv.m_data.parr->isDArray()) return false;
    if (auto const arr = ty.array()) {
      if (!tvMatchesArrayType(tv, arr)) return false;
    }
    return true;

  case T::OptSVec:
    if (initNull) return true;
    // fallthrough
  case T::SVec:
    return isVecType(tv.m_type) && tv.m_data.parr->isStatic();

  case T::OptVec:
    if (initNull) return true;
    // fallthrough
  case T::Vec:
    return isVecType(tv.m_type);

  case T::OptSDict:
    if (initNull) return true;
    // fallthrough
  case T::SDict:
    return isDictType(tv.m_type) && tv.m_data.parr->isStatic();

  case T::OptDict:
    if (initNull) return true;
    // fallthrough
  case T::Dict:
    return isDictType(tv.m_type);

  case T::OptSKeyset:
    if (initNull) return true;
    // fallthrough
  case T::SKeyset:
    return isKeysetType(tv.m_type) && tv.m_data.parr->isStatic();

  case T::OptKeyset:
    if (initNull) return true;
    // fallthrough
  case T::Keyset:
    return isKeysetType(tv.m_type);

  case T::Null:
    return initNull || tv.m_type == KindOfUninit;

  case T::OptSubObj:
    if (initNull) return true;
    // fallthrough
  case T::SubObj:
    {
      auto const cls = Unit::lookupClass(ty.clsName());
      if (!cls) return false;
      return tv.m_type == KindOfObject &&
             tv.m_data.pobj->getVMClass()->classof(cls);
    }

  case T::OptExactObj:
    if (initNull) return true;
    // fallthrough
  case T::ExactObj:
    {
      auto const cls = Unit::lookupClass(ty.clsName());
      if (!cls) return false;
      return tv.m_type == KindOfObject && tv.m_data.pobj->getVMClass() == cls;
    }

  case T::InitUnc:
    if (tv.m_type == KindOfUninit) return false;
    // fallthrough
  case T::Unc:
    return !isRefcountedType(tv.m_type) ||
           (tv.m_type == KindOfString && tv.m_data.pstr->isStatic()) ||
           (isArrayLikeType(tv.m_type) && tv.m_data.parr->isStatic());

  case T::OptArrKey:
    if (initNull) return true;
    // fallthrough
  case T::ArrKey:
    return isStringType(tv.m_type) || tv.m_type == KindOfInt64;

  case T::OptUncArrKey:
    if (initNull) return true;
    // fallthrough
  case T::UncArrKey:
    return (isStringType(tv.m_type) && !tv.m_data.pstr->isRefCounted()) ||
      tv.m_type == KindOfInt64;

  case T::InitCell:
    if (tv.m_type == KindOfUninit) return false;
    // fallthrough
  case T::Cell:
    return tv.m_type != KindOfRef;

  case T::Ref:
    return tv.m_type == KindOfRef;

  case T::InitGen:
    if (tv.m_type == KindOfUninit) return false;
    // fallthrough
  case T::Gen:
    return true;
  }
  not_reached();
}