Пример #1
0
bool cellLessOrEqual(Cell c1, Cell c2) {
  assert(cellIsPlausible(c1));
  assert(cellIsPlausible(c2));

  if ((c1.m_type == KindOfArray && c2.m_type == KindOfArray) ||
      (c1.m_type == KindOfObject && c2.m_type == KindOfObject)) {
    return cellLess(c1, c2) || cellEqual(c1, c2);
  }
  return !cellGreater(c1, c2);
}
Пример #2
0
bool cellGreaterOrEqual(const Cell* c1, const Cell* c2) {
  assert(cellIsPlausible(c1));
  assert(cellIsPlausible(c2));

  if ((c1->m_type == KindOfArray && c2->m_type == KindOfArray) ||
      (c1->m_type == KindOfObject && c2->m_type == KindOfObject)) {
    return cellGreater(c1, c2) || cellEqual(c1, c2);
  }
  return !cellLess(c1, c2);
}
Пример #3
0
bool cellGreaterOrEqual(Cell c1, Cell c2) {
    assert(cellIsPlausible(c1));
    assert(cellIsPlausible(c2));

    if ((c1.m_type == KindOfArray && c2.m_type == KindOfArray) ||
            (c1.m_type == KindOfObject && c2.m_type == KindOfObject) ||
            (c1.m_type == KindOfResource && c2.m_type == KindOfResource)) {
        return cellGreater(c1, c2) || cellEqual(c1, c2);
    }
    if ((c1.m_type == KindOfDouble && std::isnan(c1.m_data.dbl)) ||
            (c2.m_type == KindOfDouble && std::isnan(c2.m_data.dbl))) {
        return cellGreater(c1, c2) || cellEqual(c1, c2);
    }
    return !cellLess(c1, c2);
}
Пример #4
0
// Helper for converting String, Array, Bool, Null or Obj to Dbl|Int.
// Other types (i.e. Int and Double) must be handled outside of this.
TypedNum numericConvHelper(Cell cell) {
  assert(cellIsPlausible(cell));

  switch (cell.m_type) {
    case KindOfUninit:
    case KindOfNull:
      return make_int(0);

    case KindOfBoolean:
      return make_int(cell.m_data.num);

    case KindOfString:
    case KindOfStaticString:
      return stringToNumeric(cell.m_data.pstr);

    case KindOfArray:
      throw_bad_array_operand();

    case KindOfObject:
      return make_int(cell.m_data.pobj->o_toInt64());

    case KindOfResource:
      return make_int(cell.m_data.pres->o_toInt64());

    case KindOfInt64:
    case KindOfDouble:
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}
Пример #5
0
void tvCastToResourceInPlace(TypedValue* tv) {
  assert(tvIsPlausible(*tv));
  tvUnboxIfNeeded(tv);

  do {
    switch (tv->m_type) {
      DT_UNCOUNTED_CASE:
        continue;
      case KindOfString:
      case KindOfVec:
      case KindOfDict:
      case KindOfKeyset:
      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 = req::make<DummyResource>().detach()->hdr();
  assert(cellIsPlausible(*tv));
}
void c_ExternalThreadEventWaitHandle::process() {
  assert(getState() == STATE_WAITING);

  if (isInContext()) {
    unregisterFromContext();
  }

  // clean up once event is processed
  auto exit_guard = folly::makeGuard([&] { destroyEvent(); });

  Cell result;
  try {
    m_event->unserialize(result);
  } catch (const Object& exception) {
    setException(exception.get());
    return;
  } catch (...) {
    setException(AsioSession::Get()->getAbruptInterruptException().get());
    throw;
  }

  assert(cellIsPlausible(result));
  setResult(result);
  tvRefcountedDecRefCell(&result);
}
Пример #7
0
void cellCastToInt64InPlace(Cell* cell) {
  assert(cellIsPlausible(*cell));
  int64_t i;

  do {
    switch (cell->m_type) {
      case KindOfUninit:
      case KindOfNull:
        cell->m_data.num = 0LL;
        // fallthru
      case KindOfBoolean:
        assert(cell->m_data.num == 0LL || cell->m_data.num == 1LL);
        cell->m_type = KindOfInt64;
        // fallthru
      case KindOfInt64:
        return;

      case KindOfDouble:
        i = toInt64(cell->m_data.dbl);
        continue;

      case KindOfPersistentString:
        i = cell->m_data.pstr->toInt64();
        continue;

      case KindOfString:
        i = cell->m_data.pstr->toInt64();
        tvDecRefStr(cell);
        continue;

      case KindOfPersistentArray:
        i = cell->m_data.parr->empty() ? 0 : 1;
        continue;

      case KindOfArray:
        i = cell->m_data.parr->empty() ? 0 : 1;
        tvDecRefArr(cell);
        continue;

      case KindOfObject:
        i = cell->m_data.pobj->toInt64();
        tvDecRefObj(cell);
        continue;

      case KindOfResource:
        i = cell->m_data.pres->data()->o_toInt64();
        tvDecRefRes(cell);
        continue;

      case KindOfRef:
      case KindOfClass:
        break;
    }
    not_reached();
  } while (0);

  cell->m_data.num = i;
  cell->m_type = KindOfInt64;
}
Пример #8
0
bool cellSame(Cell c1, Cell c2) {
  assert(cellIsPlausible(c1));
  assert(cellIsPlausible(c2));

  bool const null1 = isNullType(c1.m_type);
  bool const null2 = isNullType(c2.m_type);
  if (null1 && null2) return true;
  if (null1 || null2) return false;

  switch (c1.m_type) {
    case KindOfBoolean:
    case KindOfInt64:
      if (c2.m_type != c1.m_type) return false;
      return c1.m_data.num == c2.m_data.num;

    case KindOfDouble:
      if (c2.m_type != c1.m_type) return false;
      return c1.m_data.dbl == c2.m_data.dbl;

    case KindOfPersistentString:
    case KindOfString:
      if (!isStringType(c2.m_type)) return false;
      return c1.m_data.pstr->same(c2.m_data.pstr);

    case KindOfPersistentArray:
    case KindOfArray:
      if (!isArrayType(c2.m_type)) return false;
      return c1.m_data.parr->equal(c2.m_data.parr, true);

    case KindOfObject:
      return c2.m_type == KindOfObject &&
        c1.m_data.pobj == c2.m_data.pobj;

    case KindOfResource:
      return c2.m_type == KindOfResource &&
        c1.m_data.pres == c2.m_data.pres;

    case KindOfUninit:
    case KindOfNull:
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}
Пример #9
0
bool tvIsPlausible(TypedValue tv) {
  if (tv.m_type == KindOfRef) {
    assert(tv.m_data.pref);
    assert(uintptr_t(tv.m_data.pref) % sizeof(void*) == 0);
    assert(check_refcount(tv.m_data.pref->getRealCount()));
    tv = *tv.m_data.pref->tv();
  }
  return cellIsPlausible(tv);
}
Пример #10
0
bool cellLessOrEqual(Cell c1, Cell c2) {
    assert(cellIsPlausible(c1));
    assert(cellIsPlausible(c2));

    if ((c1.m_type == KindOfArray && c2.m_type == KindOfArray) ||
            (c1.m_type == KindOfObject && c2.m_type == KindOfObject) ||
            (c1.m_type == KindOfResource && c2.m_type == KindOfResource)) {
        return cellLess(c1, c2) || cellEqual(c1, c2);
    }

    // We have to treat NaN specially: NAN <= NAN is false, for example, so we
    // can't just say !(NAN > NAN).
    if ((c1.m_type == KindOfDouble && std::isnan(c1.m_data.dbl)) ||
            (c2.m_type == KindOfDouble && std::isnan(c2.m_data.dbl))) {
        return cellLess(c1, c2) || cellEqual(c1, c2);
    }
    return !cellGreater(c1, c2);
}
Пример #11
0
void c_WaitableWaitHandle::done() {
  assert(isFinished());
  assert(cellIsPlausible(m_resultOrException));

  // unblock parents
  while (m_firstParent) {
    m_firstParent = m_firstParent->unblock();
  }
}
Пример #12
0
bool tvIsPlausible(const TypedValue* tv) {
  assert(tv);
  if (tv->m_type == KindOfRef) {
    assert(tv->m_data.pref);
    assert(uintptr_t(tv->m_data.pref) % sizeof(void*) == 0);
    assert(is_refcount_realistic(tv->m_data.pref->getCount()));
    tv = tv->m_data.pref->tv();
  }
  return cellIsPlausible(tv);
}
Пример #13
0
bool tvIsPlausible(TypedValue tv) {
  if (isRefType(tv.m_type)) {
    assertx(tv.m_data.pref);
    assertx(uintptr_t(tv.m_data.pref) % sizeof(void*) == 0);
    assertx(tv.m_data.pref->kindIsValid());
    assertx(tv.m_data.pref->checkCountZ());
    tv = *tv.m_data.pref->cell();
  }
  return cellIsPlausible(tv);
}
Пример #14
0
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));
}
Пример #15
0
bool APCLocalArray::checkInvariants(const ArrayData* ad) {
  assert(ad->isApcArray());
  assert(ad->checkCount());
  DEBUG_ONLY auto const local = static_cast<const APCLocalArray*>(ad);
  DEBUG_ONLY auto p = local->localCache();
  for (auto end = p + local->getSize(); p < end; ++p) {
    // Elements in the local cache must not be KindOfRef.
    assert(cellIsPlausible(*p));
  }
  return true;
}
Пример #16
0
bool cellSame(Cell c1, Cell c2) {
    assert(cellIsPlausible(c1));
    assert(cellIsPlausible(c2));

    bool const null1 = IS_NULL_TYPE(c1.m_type);
    bool const null2 = IS_NULL_TYPE(c2.m_type);
    if (null1 && null2) return true;
    if (null1 || null2) return false;

    switch (c1.m_type) {
    case KindOfInt64:
    case KindOfBoolean:
        if (c2.m_type != c1.m_type) return false;
        return c1.m_data.num == c2.m_data.num;
    case KindOfDouble:
        if (c2.m_type != c1.m_type) return false;
        return c1.m_data.dbl == c2.m_data.dbl;

    case KindOfStaticString:
    case KindOfString:
        if (!IS_STRING_TYPE(c2.m_type)) return false;
        return c1.m_data.pstr->same(c2.m_data.pstr);

    case KindOfArray:
        if (c2.m_type != KindOfArray) return false;
        return c1.m_data.parr->equal(c2.m_data.parr, true);

    case KindOfObject:
        return c2.m_type == KindOfObject &&
               c1.m_data.pobj == c2.m_data.pobj;

    case KindOfResource:
        return c2.m_type == KindOfResource &&
               c1.m_data.pres == c2.m_data.pres;

    default:
        break;
    }
    not_reached();
}
Пример #17
0
bool APCLocalArray::checkInvariants(const ArrayData* ad) {
  assert(ad->isApcArray());
  DEBUG_ONLY auto const shared = static_cast<const APCLocalArray*>(ad);
  if (auto ptr = shared->m_localCache) {
    auto const cap = shared->m_arr->capacity();
    auto const stop = ptr + cap;
    for (; ptr != stop; ++ptr) {
      // Elements in the local cache must not be KindOfRef.
      assert(cellIsPlausible(*ptr));
    }
  }
  return true;
}
Пример #18
0
void incDecBodySlow(IncDecOp op, Cell* fr, TypedValue* to) {
  assert(cellIsPlausible(*fr));
  assert(fr->m_type != KindOfUninit);

  auto dup = [&]() { cellDup(*fr, *to); };

  switch (op) {
  case IncDecOp::PreInc:
    cellInc(*fr);
    dup();
    return;
  case IncDecOp::PostInc:
    dup();
    cellInc(*fr);
    return;
  case IncDecOp::PreDec:
    cellDec(*fr);
    dup();
    return;
  case IncDecOp::PostDec:
    dup();
    cellDec(*fr);
    return;
  default: break;
  }

  switch (op) {
  case IncDecOp::PreIncO:
    cellIncO(*fr);
    dup();
    return;
  case IncDecOp::PostIncO:
    dup();
    cellIncO(*fr);
    return;
  case IncDecOp::PreDecO:
    cellDecO(*fr);
    dup();
    return;
  case IncDecOp::PostDecO:
    dup();
    cellDecO(*fr);
    return;
  default: break;
  }
  not_reached();
}
Пример #19
0
Cell incDecBodySlow(IncDecOp op, Cell* fr) {
  assert(cellIsPlausible(*fr));
  assert(fr->m_type != KindOfUninit);

  auto dup = [&]() { tvRefcountedIncRef(fr); return *fr; };

  switch (op) {
  case IncDecOp::PreInc:
    cellInc(*fr);
    return dup();
  case IncDecOp::PostInc: {
    auto const tmp = dup();
    cellInc(*fr);
    return tmp;
  }
  case IncDecOp::PreDec:
    cellDec(*fr);
    return dup();
  case IncDecOp::PostDec: {
    auto const tmp = dup();
    cellDec(*fr);
    return tmp;
  }
  default: break;
  }

  switch (op) {
  case IncDecOp::PreIncO:
    cellIncO(*fr);
    return dup();
  case IncDecOp::PostIncO: {
    auto const tmp = dup();
    cellIncO(*fr);
    return tmp;
  }
  case IncDecOp::PreDecO:
    cellDecO(*fr);
    return dup();
  case IncDecOp::PostDecO: {
    auto const tmp = dup();
    cellDecO(*fr);
    return tmp;
  }
  default: break;
  }
  not_reached();
}
void c_WaitableWaitHandle::setResult(const Cell& result) {
  assert(cellIsPlausible(result));

  setState(STATE_SUCCEEDED);
  cellDup(result, m_resultOrException);

  // unref creator
  if (m_creator) {
    decRefObj(m_creator);
    m_creator = nullptr;
  }

  // unblock parents
  while (m_firstParent) {
    m_firstParent = m_firstParent->unblock();
  }
}
void c_ExternalThreadEventWaitHandle::process() {
  assert(getState() == STATE_WAITING);

  if (isInContext()) {
    unregisterFromContext();
  }

  // clean up once event is processed
  auto exit_guard = folly::makeGuard([&] { destroyEvent(); });

  Cell result;
  try {
    m_event->unserialize(result);
  } catch (const Object& exception) {
    assert(exception->instanceof(SystemLib::s_ExceptionClass));
    auto const parentChain = getFirstParent();
    setState(STATE_FAILED);
    tvWriteObject(exception.get(), &m_resultOrException);
    c_BlockableWaitHandle::UnblockChain(parentChain);

    auto session = AsioSession::Get();
    if (UNLIKELY(session->hasOnExternalThreadEventFailCallback())) {
      session->onExternalThreadEventFail(this, exception);
    }
    return;
  } catch (...) {
    auto const parentChain = getFirstParent();
    setState(STATE_FAILED);
    tvWriteObject(AsioSession::Get()->getAbruptInterruptException(),
                  &m_resultOrException);
    c_BlockableWaitHandle::UnblockChain(parentChain);
    throw;
  }

  assert(cellIsPlausible(result));
  auto const parentChain = getFirstParent();
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
  c_BlockableWaitHandle::UnblockChain(parentChain);

  auto session = AsioSession::Get();
  if (UNLIKELY(session->hasOnExternalThreadEventSuccessCallback())) {
    session->onExternalThreadEventSuccess(this, tvAsCVarRef(&result));
  }
}
Пример #22
0
void cellCastToInt64InPlace(Cell* cell) {
  assert(cellIsPlausible(*cell));

  int64_t i;
  switch (cell->m_type) {
  case KindOfUninit:
  case KindOfNull:
    cell->m_data.num = 0LL;
    // Fall through
  case KindOfBoolean:
    assert(cell->m_data.num == 0LL || cell->m_data.num == 1LL);
    cell->m_type = KindOfInt64;
    // Fall through
  case KindOfInt64:
    return;
  case KindOfDouble:  {
    i = toInt64(cell->m_data.dbl);
    break;
  }
  case KindOfStaticString: i = (cell->m_data.pstr->toInt64()); break;
  case KindOfString:  {
    i = cell->m_data.pstr->toInt64();
    tvDecRefStr(cell);
    break;
  }
  case KindOfArray:
    i = cell->m_data.parr->empty() ? 0 : 1;
    tvDecRefArr(cell);
    break;
  case KindOfObject:
    i = cell->m_data.pobj->o_toInt64();
    tvDecRefObj(cell);
    break;
  case KindOfResource:
    i = cell->m_data.pres->o_toInt64();
    tvDecRefRes(cell);
    break;
  default:
    not_reached();
  }
  cell->m_data.num = i;
  cell->m_type = KindOfInt64;
}
Пример #23
0
void tvCastToKeysetInPlace(TypedValue* tv) {
  assert(tvIsPlausible(*tv));
  tvUnboxIfNeeded(tv);
  ArrayData* a;

  do {
    switch (tv->m_type) {
      case KindOfUninit:
      case KindOfNull:
        raise_warning("Null to keyset conversion");
        a = staticEmptyKeysetArray();
        continue;

      case KindOfBoolean:
        raise_warning("Bool to keyset conversion");
        a = staticEmptyKeysetArray();
        continue;

      case KindOfInt64:
        raise_warning("Int to keyset conversion");
        a = staticEmptyKeysetArray();
        continue;

      case KindOfDouble:
        raise_warning("Double to keyset conversion");
        a = staticEmptyKeysetArray();
        continue;

      case KindOfPersistentString:
      case KindOfString:
        raise_warning("String to keyset conversion");
        a = staticEmptyKeysetArray();
        decRefStr(tv->m_data.pstr);
        continue;

      case KindOfResource:
        raise_warning("Resource to keyset conversion");
        a = staticEmptyKeysetArray();
        decRefRes(tv->m_data.pres);
        continue;

      case KindOfPersistentVec:
      case KindOfVec: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isVecArray());
        a = PackedArray::ToKeysetVec(adIn, adIn->cowCheck());
        assert(a != adIn);
        decRefArr(adIn);
        continue;
      }

      case KindOfPersistentDict:
      case KindOfDict: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isDict());
        a = MixedArray::ToKeysetDict(adIn, adIn->cowCheck());
        if (a != adIn) decRefArr(adIn);
        continue;
      }

      case KindOfPersistentArray:
      case KindOfArray: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isPHPArray());
        a = adIn->toKeyset(adIn->cowCheck());
        if (a != adIn) decRefArr(adIn);
        continue;
      }

      case KindOfPersistentKeyset:
      case KindOfKeyset:
        assert(tv->m_data.parr->isKeyset());
        return;

      case KindOfObject: {
        auto* obj = tv->m_data.pobj;
        if (!obj->isCollection()) {
          raise_warning("Non-collection object conversion to keyset");
          a = staticEmptyKeysetArray();
        } else {
          auto keyset = collections::toArray(obj).toKeyset();
          decRefObj(obj);
          a = keyset.detach();
        }
        continue;
      }

      case KindOfRef:
      case KindOfClass:
        break;
    }
    not_reached();
  } while (0);

  assert(!a->isRefCounted() || a->hasExactlyOneRef());

  tv->m_data.parr = a;
  tv->m_type = KindOfKeyset;
  assert(cellIsPlausible(*tv));
}
void c_ExternalThreadEventWaitHandle::process() {
  assertx(getState() == STATE_WAITING);

  if (isInContext()) {
    unregisterFromContext();
  }

  // Store the finish time of the underlying IO operation
  // So we can pass it in the finish callbacks

  // clean up once event is processed
  auto exit_guard = folly::makeGuard([&] { destroyEvent(); });

  Cell result;
  try {
    try {
      m_event->unserialize(result);
    } catch (ExtendedException& exception) {
      exception.recomputeBacktraceFromWH(this);
      throw exception;
    }
  } catch (const Object& exception) {
    assertx(exception->instanceof(SystemLib::s_ThrowableClass));
    throwable_recompute_backtrace_from_wh(exception.get(), this);
    auto parentChain = getParentChain();
    setState(STATE_FAILED);
    tvWriteObject(exception.get(), &m_resultOrException);
    parentChain.unblock();

    auto session = AsioSession::Get();
    if (UNLIKELY(session->hasOnExternalThreadEventFail())) {
      session->onExternalThreadEventFail(
        this,
        exception,
        std::chrono::duration_cast<std::chrono::nanoseconds>(
          m_event->getFinishTime().time_since_epoch()
        ).count()
      );
    }
    return;
  } catch (...) {
    auto parentChain = getParentChain();
    setState(STATE_FAILED);
    tvWriteObject(AsioSession::Get()->getAbruptInterruptException(),
                  &m_resultOrException);
    parentChain.unblock();
    throw;
  }

  assertx(cellIsPlausible(result));
  auto parentChain = getParentChain();
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
  parentChain.unblock();

  auto session = AsioSession::Get();
  if (UNLIKELY(session->hasOnExternalThreadEventSuccess())) {
    session->onExternalThreadEventSuccess(
      this,
      tvAsCVarRef(&result),
      std::chrono::duration_cast<std::chrono::nanoseconds>(
        m_event->getFinishTime().time_since_epoch()
      ).count()
    );
  }
}
Пример #25
0
void Variant::setEvalScalar() {
  assertx(cellIsPlausible(*this));

  auto const do_array = [this]{
    auto parr = m_data.parr;
    if (!parr->isStatic()) {
      auto ad = ArrayData::GetScalarArray(parr);
      assert(ad->isStatic());
      m_data.parr = ad;
      decRefArr(parr);
    }
  };

  switch (m_type) {
    case KindOfUninit:
    case KindOfNull:
    case KindOfBoolean:
    case KindOfInt64:
    case KindOfDouble:
      return;

    case KindOfString:
      m_type = KindOfPersistentString;
    case KindOfPersistentString: {
      auto pstr = m_data.pstr;
      if (!pstr->isStatic()) {
        StringData *sd = makeStaticString(pstr);
        decRefStr(pstr);
        m_data.pstr = sd;
        assert(m_data.pstr->isStatic());
      }
      return;
    }

    case KindOfVec:
      m_type = KindOfPersistentVec;
    case KindOfPersistentVec:
      do_array();
      return;

    case KindOfDict:
      m_type = KindOfPersistentDict;
    case KindOfPersistentDict:
      do_array();
      return;

    case KindOfKeyset:
      m_type = KindOfPersistentKeyset;
    case KindOfPersistentKeyset:
      do_array();
      return;

    case KindOfArray:
      m_type = KindOfPersistentArray;
    case KindOfPersistentArray:
      do_array();
      return;

    case KindOfObject:
    case KindOfResource:
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}
Пример #26
0
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 KindOfPersistentVec: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isVecArray());
        a = PackedArray::ToPHPArrayVec(adIn, true);
        assert(a != adIn);
        continue;
      }

      case KindOfVec: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isVecArray());
        a = PackedArray::ToPHPArrayVec(adIn, adIn->cowCheck());
        if (a != adIn) tvDecRefArr(tv);
        continue;
      }

      case KindOfPersistentDict: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isDict());
        a = MixedArray::ToPHPArrayDict(adIn, true);
        assert(a != adIn);
        continue;
      }

      case KindOfDict: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isDict());
        a = MixedArray::ToPHPArrayDict(adIn, adIn->cowCheck());
        if (a != adIn) tvDecRefArr(tv);
        continue;
      }

      case KindOfPersistentKeyset: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isKeyset());
        a = MixedArray::ToPHPArrayKeyset(adIn, true);
        assert(a != adIn);
        continue;
      }

      case KindOfKeyset: {
        auto* adIn = tv->m_data.parr;
        assert(adIn->isKeyset());
        a = MixedArray::ToPHPArrayKeyset(adIn, adIn->cowCheck());
        if (a != adIn) tvDecRefArr(tv);
        continue;
      }

      case KindOfPersistentArray:
      case KindOfArray:
        assert(tv->m_data.parr->isPHPArray());
        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;
  assert(cellIsPlausible(*tv));
}
Пример #27
0
std::string escaped_long(Cell cell) {
  assert(cellIsPlausible(cell));
  auto const str = f_serialize(tvAsCVarRef(&cell));
  return escaped_long(str.get());
}
Пример #28
0
std::string member_tv_initializer(Cell cell) {
  assert(cellIsPlausible(cell));
  if (cell.m_type == KindOfUninit) return "uninit";
  return escaped_long(cell);
}