예제 #1
0
ALWAYS_INLINE
void BaseMap::setImpl(int64_t h, const TypedValue* val) {
  if (!raw) {
    mutate();
  }
  assert(val->m_type != KindOfRef);
  assert(canMutateBuffer());
retry:
  auto p = findForInsert(h);
  assert(p);
  if (validPos(*p)) {
    auto& e = data()[*p];
    TypedValue old = e.data;
    cellDup(*val, e.data);
    tvRefcountedDecRef(old);
    return;
  }
  if (UNLIKELY(isFull())) {
    makeRoom();
    goto retry;
  }
  if (!raw) {
    ++m_version;
  }
  auto& e = allocElm(p);
  cellDup(*val, e.data);
  e.setIntKey(h);
  updateNextKI(h);
}
예제 #2
0
ALWAYS_INLINE
void BaseMap::setImpl(StringData* key, const TypedValue* val) {
  if (!raw) {
    mutate();
  }
  assert(val->m_type != KindOfRef);
  assert(canMutateBuffer());
retry:
  strhash_t h = key->hash();
  auto* p = findForInsert(key, h);
  assert(p);
  if (validPos(*p)) {
    auto& e = data()[*p];
    TypedValue old = e.data;
    cellDup(*val, e.data);
    tvRefcountedDecRef(old);
    return;
  }
  if (UNLIKELY(isFull())) {
    makeRoom();
    goto retry;
  }
  if (!raw) {
    ++m_version;
  }
  auto& e = allocElm(p);
  cellDup(*val, e.data);
  e.setStrKey(key, h);
  updateIntLikeStrKeys(key);
}
ALWAYS_INLINE
void BaseSet::addImpl(StringData *key) {
  if (!raw) {
    mutate();
  }
  strhash_t h = key->hash();
  auto p = findForInsert(key, h);
  assert(p);
  if (validPos(*p)) {
    return;
  }
  if (UNLIKELY(isFull())) {
    makeRoom();
    p = findForInsert(key, h);
  }
  auto& e = allocElm(p);
  // This increments the string's refcount twice, once for
  // the key and once for the value
  e.setStrKey(key, h);
  cellDup(make_tv<KindOfString>(key), e.data);
  updateIntLikeStrKeys(key);
  if (!raw) {
    ++m_version;
  }
}
예제 #4
0
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;
}
예제 #5
0
void c_ConditionWaitHandle::t_succeed(const Variant& result) {
  if (isFinished()) {
    failAlreadyFinished();
  }

  assert(getState() == STATE_BLOCKED);
  auto parentChain = getParentChain();
  setState(STATE_SUCCEEDED);
  cellDup(*result.asCell(), m_resultOrException);
  parentChain.unblock();
}
예제 #6
0
void HHVM_METHOD(ConditionWaitHandle, succeed, const Variant& result) {
  auto obj = wait_handle<c_ConditionWaitHandle>(this_);
  if (obj->isFinished()) {
    failAlreadyFinished();
  }

  assert(obj->getState() == c_ConditionWaitHandle::STATE_BLOCKED);
  auto parentChain = obj->getParentChain();
  obj->setState(c_ConditionWaitHandle::STATE_SUCCEEDED);
  cellDup(*result.asCell(), obj->m_resultOrException);
  parentChain.unblock();
}
예제 #7
0
void throwable_init_file_and_line_from_builtin(ObjectData* throwable) {
  assertx(vmfp_is_builtin());
  assertx(is_throwable(throwable));
  assertx(throwable_has_expected_props());

  assertx(throwable->propVec()[s_fileIdx].m_type == KindOfNull);
  assertx(throwable->propVec()[s_lineIdx].m_type == KindOfNull);
  assertx(throwable->propVec()[s_traceIdx].m_type == KindOfArray);
  auto const trace = throwable->propVec()[s_traceIdx].m_data.parr;
  for (ArrayIter iter(trace); iter; ++iter) {
    assertx(iter.second().asTypedValue()->m_type == KindOfArray);
    auto const frame = iter.second().asTypedValue()->m_data.parr;
    auto const file = frame->nvGet(s_file.get());
    auto const line = frame->nvGet(s_line.get());
    if (file || line) {
      if (file) cellDup(*tvAssertCell(file), throwable->propVec()[s_fileIdx]);
      if (line) cellDup(*tvAssertCell(line), throwable->propVec()[s_lineIdx]);
      return;
    }
  }
}
예제 #8
0
파일: event-hook.cpp 프로젝트: 2bj/hhvm
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->m_func;
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  // Intercept only original generator / async function calls, not resumption.
  if (ar->inGenerator()) return true;

  Variant *h = get_intercept_handler(func->fullNameRef(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  JIT::VMRegAnchor _;

  PC savePc = g_context->m_pc;

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Variant intArgs =
    PackedArrayInit(5)
      .append(ar->m_func->fullNameRef())
      .append(called_on)
      .append(get_frame_args_with_ref(ar))
      .append(h->asCArrRef()[1])
      .appendRef(doneFlag)
      .toArray();

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_context->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
    Stack& stack = g_context->getStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    g_context->m_fp = outer;
    g_context->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;

    return false;
  }
  g_context->m_fp = ar;
  g_context->m_pc = savePc;

  return true;
}
예제 #9
0
ArrayData* StructArray::SetStr(
  ArrayData* ad,
  StringData* k,
  Cell v,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto shape = structArray->shape();
  auto result = structArray;

  auto offset = shape->offsetFor(k);
  bool isNewProperty = offset == PropertyTable::kInvalidOffset;

  auto convertToMixedAndAdd = [&]() {
    auto mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
    return mixed->addValNoAsserts(k, v);
  };

  if (isNewProperty) {
    StringData* staticKey;
    // We don't support adding non-static strings yet.
    if (k->isStatic()) {
      staticKey = k;
    } else {
      staticKey = lookupStaticString(k);
      if (!staticKey) return convertToMixedAndAdd();
    }

    auto newShape = shape->transition(staticKey);
    if (!newShape) return convertToMixedAndAdd();
    result = copy ? CopyAndResizeIfNeeded(structArray, newShape)
                  : ResizeIfNeeded(structArray, newShape);
    offset = result->shape()->offsetFor(staticKey);
    assert(offset != PropertyTable::kInvalidOffset);
    TypedValue* dst = &result->data()[offset];
    // TODO(#3888164): we should restructure things so we don't have to
    // check KindOfUninit here.
    if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>();
    cellDup(v, *dst);
    return result;
  }

  if (copy) {
    result = asStructArray(Copy(structArray));
  }

  assert(offset != PropertyTable::kInvalidOffset);
  TypedValue* dst = &result->data()[offset];
  if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>();
  cellSet(v, *tvToCell(dst));
  return result;
}
예제 #10
0
 void unserialize(Cell& c) override {
     if (!m_exception.empty()) {
         throw mcr_getException(m_exception, m_op, m_replyCode, m_key);
     }
     if ((m_result.m_type == KindOfString) && !m_result.m_data.pstr) {
         // Deferred string init, see below
         m_result.m_data.pstr = StringData::Make(
                                    m_stringResult.c_str(), m_stringResult.size(), CopyString);
         m_result.m_data.pstr->setRefCount(1);
         m_stringResult.clear();
     }
     cellDup(m_result, c);
 }
예제 #11
0
void BaseVector::cow() {
  TypedValue* newData =
      (TypedValue*)smart_malloc(m_capacity * sizeof(TypedValue));

  assert(newData);

  for (uint i = 0; i < m_size; i++) {
    cellDup(m_data[i], newData[i]);
  }

  m_data = newData;
  m_frozenCopy.reset();
}
예제 #12
0
void throwable_init(ObjectData* throwable) {
  assertx(is_throwable(throwable));
  assertx(throwable_has_expected_props());

  auto trace = HHVM_FN(debug_backtrace)(exception_get_trace_options());
  cellMove(
    make_tv<KindOfArray>(trace.detach()), throwable->propVec()[s_traceIdx]);

  VMRegAnchor _;
  auto const fp = vmfp();
  if (UNLIKELY(!fp)) return;
  if (UNLIKELY(fp->func()->isBuiltin())) {
    throwable_init_file_and_line_from_builtin(throwable);
  } else {
    assertx(throwable->propVec()[s_fileIdx].m_type == KindOfNull);
    assertx(throwable->propVec()[s_lineIdx].m_type == KindOfNull);
    auto const unit = fp->func()->unit();
    auto const file = const_cast<StringData*>(unit->filepath());
    auto const line = unit->getLineNumber(unit->offsetOf(vmpc()));
    cellDup(make_tv<KindOfString>(file), throwable->propVec()[s_fileIdx]);
    cellDup(make_tv<KindOfInt64>(line), throwable->propVec()[s_lineIdx]);
  }
}
예제 #13
0
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->m_func;
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  Variant *h = get_intercept_handler(func->fullNameRef(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  Transl::VMRegAnchor _;

  PC savePc = g_vmContext->m_pc;

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Array intArgs =
    CREATE_VECTOR5(ar->m_func->fullNameRef(),
                   called_on,
                   get_frame_args_with_ref(ar),
                   h->asCArrRef()[1],
                   ref(doneFlag));

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
    Stack& stack = g_vmContext->getStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    g_vmContext->m_fp = outer;
    g_vmContext->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;

    return false;
  }
  g_vmContext->m_fp = ar;
  g_vmContext->m_pc = savePc;

  return true;
}
예제 #14
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();
}
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();
  }
}
예제 #16
0
void HHVM_METHOD(ConditionWaitHandle, fail, const Object& exception) {
  if (!exception->instanceof(SystemLib::s_ThrowableClass)) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Expected exception to be an instance of Throwable");
  }
  auto obj = wait_handle<c_ConditionWaitHandle>(this_);

  if (obj->isFinished()) {
    failAlreadyFinished();
  }

  assert(obj->getState() == c_ConditionWaitHandle::STATE_BLOCKED);
  auto parentChain = obj->getParentChain();
  obj->setState(c_ConditionWaitHandle::STATE_FAILED);
  cellDup(make_tv<KindOfObject>(exception.get()), obj->m_resultOrException);
  parentChain.unblock();
}
예제 #17
0
Cell lookupCnsHelperPersistent(rds::Handle tv_handle,
                               StringData* nm, bool error) {
  assertx(rds::isPersistentHandle(tv_handle));
  auto const tv = &rds::handleToRef<TypedValue>(tv_handle);
  assertx(tv->m_type == KindOfUninit);

  // Deferred system constants.
  if (UNLIKELY(tv->m_data.pref != nullptr)) {
    auto callback = (Native::ConstantCallback)(tv->m_data.pref);
    const Cell* cns = callback().asTypedValue();
    if (LIKELY(cns->m_type != KindOfUninit)) {
      Cell c1;
      cellDup(*cns, c1);
      return c1;
    }
  }
  return lookupCnsHelper(nm, error);
}
예제 #18
0
ArrayData* PackedArray::Append(ArrayData* adIn, const Variant& v, bool copy) {
  assert(checkInvariants(adIn));
  auto const ad = copy ? CopyAndResizeIfNeeded(adIn)
                       : ResizeIfNeeded(adIn);
  if (UNLIKELY(!ad)) {
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
    return MixedArray::Append(mixed, v, copy);
  }

  if (ad->m_pos == ArrayData::invalid_index) {
    ad->m_pos = ad->m_size;
  }
  auto& dst = packedData(ad)[ad->m_size++];
  cellDup(*v.asCell(), dst);
  // TODO(#3888164): restructure this so we don't need KindOfUninit checks.
  if (dst.m_type == KindOfUninit) dst.m_type = KindOfNull;
  return ad;
}
예제 #19
0
Cell lookupCnsHelper(const TypedValue* tv,
                     StringData* nm,
                     bool error) {
  assert(tv->m_type == KindOfUninit);

  // Deferred constants such as SID
  if (UNLIKELY(tv->m_data.pref != nullptr)) {
    ClassInfo::ConstantInfo* ci =
      (ClassInfo::ConstantInfo*)(void*)tv->m_data.pref;
    Cell *cns = const_cast<Variant&>(ci->getDeferredValue()).asTypedValue();
    if (LIKELY(cns->m_type != KindOfUninit)) {
      Cell c1;
      cellDup(*cns, c1);
      return c1;
    }
  }

  Cell *cns = nullptr;
  if (UNLIKELY(TargetCache::s_constants().get() != nullptr)) {
    cns = TargetCache::s_constants()->nvGet(nm);
  }
  if (!cns) {
    cns = Unit::loadCns(const_cast<StringData*>(nm));
  }
  if (LIKELY(cns != nullptr)) {
    Cell c1;
    c1.m_type = cns->m_type;
    c1.m_data = cns->m_data;
    return c1;
  }

  // Undefined constants
  if (error) {
    raise_error("Undefined constant '%s'", nm->data());
  } else {
    raise_notice(Strings::UNDEFINED_CONSTANT, nm->data(), nm->data());
    Cell c1;
    c1.m_data.pstr = const_cast<StringData*>(nm);
    c1.m_type = KindOfStaticString;
    return c1;
  }
  not_reached();
}
예제 #20
0
Cell lookupCnsHelper(StringData* nm, bool error) {
  auto const cns = lookupCnsImpl(nm);
  if (LIKELY(cns != nullptr)) {
    Cell c1;
    cellDup(*cns, c1);
    return c1;
  }

  // Undefined constants.
  if (error) {
    raise_error("Undefined constant '%s'", nm->data());
  } else {
    raise_notice(Strings::UNDEFINED_CONSTANT, nm->data(), nm->data());
    Cell c1;
    c1.m_data.pstr = const_cast<StringData*>(nm);
    c1.m_type = KindOfPersistentString;
    return c1;
  }
  not_reached();
}
예제 #21
0
void c_ConditionWaitHandle::t_fail(const Variant& exception) {
  auto const cell = exception.asCell();
  if (UNLIKELY(
    cell->m_type != KindOfObject ||
    !cell->m_data.pobj->instanceof(SystemLib::s_ExceptionClass)
  )) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Expected exception to be an instance of Exception");
  }

  if (isFinished()) {
    failAlreadyFinished();
  }

  assert(getState() == STATE_BLOCKED);
  auto parentChain = getParentChain();
  setState(STATE_FAILED);
  cellDup(make_tv<KindOfObject>(cell->m_data.pobj), m_resultOrException);
  parentChain.unblock();
}
예제 #22
0
 /* Unserialize happens in the request thread where we can allocate smart pointers
  * Use this opportunity to marshal the saved data from persistent data structures
  * into per-request data.
  */
 void unserialize(Cell& c) override {
   if (!m_exception.empty()) {
     mcr_throwException(m_exception, m_op, m_replyCode, m_key);
   }
   if ((m_result.m_type == KindOfString) && !m_result.m_data.pstr) {
     // Deferred string init, see below
     m_result.m_data.pstr = StringData::Make(
       m_stringResult.c_str(), m_stringResult.size(), CopyString);
     m_stringResult.clear();
   } else if ((m_result.m_type == KindOfArray) && !m_result.m_data.parr) {
     // Deferred string value and cas, see below
     Array ret = Array::Create();
     ret.set(s_value,
       String(m_stringResult.c_str(), m_stringResult.size(), CopyString));
     ret.set(s_cas, (int64_t)m_cas);
     ret.set(s_flags, (int64_t)m_flags);
     m_result.m_data.parr = ret.detach();
     m_stringResult.clear();
   }
   cellDup(m_result, c);
 }
예제 #23
0
Cell lookupCnsUHelperPersistent(rds::Handle tv_handle,
                                StringData* nm, StringData* fallback) {
  assertx(rds::isPersistentHandle(tv_handle));

  // Lookup qualified name in thread-local constants.
  auto cns = lookupCnsImpl(nm);

  // Try cache handle for unqualified name.
  auto const tv = &rds::handleToRef<TypedValue>(tv_handle);
  if (UNLIKELY(!cns && tv->m_type != KindOfUninit)) {
    cns = tv;
  }

  if (LIKELY(cns != nullptr)) {
    Cell c1;
    cellDup(*cns, c1);
    return c1;
  }

  return lookupCnsHelper(fallback, false);
}
예제 #24
0
Cell lookupCnsUHelperNormal(rds::Handle tv_handle,
                            StringData* nm, StringData* fallback) {
  assertx(rds::isNormalHandle(tv_handle));

  // Lookup qualified name in thread-local constants.
  auto cns = lookupCnsImpl(nm);

  // Try cache handle for unqualified name.
  if (UNLIKELY(!cns && rds::isHandleInit(tv_handle, rds::NormalTag{}))) {
    cns = &rds::handleToRef<TypedValue>(tv_handle);
    assertx(cns->m_type != KindOfUninit);
  }

  if (LIKELY(cns != nullptr)) {
    Cell c1;
    cellDup(*cns, c1);
    return c1;
  }

  // Lookup unqualified name in thread-local constants.
  return lookupCnsHelper(fallback, false);
}
예제 #25
0
typename std::enable_if<
  std::is_base_of<BaseVector, TVector>::value, Object>::type
BaseSet::php_concat(const Variant& iterable) {
  size_t itSize;
  ArrayIter iter = getArrayIterHelper(iterable, itSize);
  auto vec = req::make<TVector>();
  uint32_t sz = m_size;
  vec->reserve((size_t)sz + itSize);
  assert(vec->canMutateBuffer());
  vec->setSize(sz);

  uint32_t used = posLimit();
  for (uint32_t i = 0, j = 0; i < used; ++i) {
    if (isTombstone(i)) {
      continue;
    }
    cellDup(data()[i].data, vec->data()[j]);
    ++j;
  }
  for (; iter; ++iter) {
    vec->addRaw(iter.second());
  }
  return Object{std::move(vec)};
}
p_StaticResultWaitHandle c_StaticResultWaitHandle::Create(const Cell& result) {
  p_StaticResultWaitHandle wh = NEWOBJ(c_StaticResultWaitHandle)();
  cellDup(result, wh->m_resultOrException);
  return wh;
}
예제 #27
0
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->func();
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  // Intercept only original generator / async function calls, not resumption.
  if (ar->resumed()) return true;

  Variant* h = get_intercept_handler(func->fullNameStr(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  /*
   * In production mode, only functions that we have assumed can be
   * intercepted during static analysis should actually be
   * intercepted.
   */
  if (RuntimeOption::RepoAuthoritative &&
      !RuntimeOption::EvalJitEnableRenameFunction) {
    if (!(func->attrs() & AttrInterceptable)) {
      raise_error("fb_intercept was used on a non-interceptable function (%s) "
                  "in RepoAuthoritative mode", func->fullName()->data());
    }
  }

  VMRegAnchor _;

  PC savePc = vmpc();

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Variant intArgs =
    PackedArrayInit(5)
      .append(VarNR(ar->func()->fullName()))
      .append(called_on)
      .append(get_frame_args_with_ref(ar))
      .append(h->asCArrRef()[1])
      .appendRef(doneFlag)
      .toArray();

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_context->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->func()->numLocals());
    Stack& stack = vmStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    vmfp() = outer;
    vmpc() = outer ? outer->func()->unit()->at(pcOff) : nullptr;

    return false;
  }
  vmfp() = ar;
  vmpc() = savePc;

  return true;
}
예제 #28
0
Cell lookupClsCnsHelper(TypedValue* cache, const NamedEntity* ne,
                        const StringData* cls, const StringData* cns) {
  auto const clsCns = g_context->lookupClsCns(ne, cls, cns);
  cellDup(clsCns, *cache);
  return clsCns;
}