コード例 #1
0
ファイル: tv-arith.cpp プロジェクト: AmineCherrai/hhvm
Cell cellArith(Op o, Cell c1, Cell c2) {
again:
  if (c1.m_type == KindOfInt64) {
    for (;;) {
      if (c2.m_type == KindOfInt64)  return o(c1.m_data.num, c2.m_data.num);
      if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
      cellCopy(numericConvHelper(c2), c2);
      assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
    }
  }

  if (c1.m_type == KindOfDouble) {
    for (;;) {
      if (c2.m_type == KindOfDouble) return o(c1.m_data.dbl, c2.m_data.dbl);
      if (c2.m_type == KindOfInt64)  return o(c1.m_data.dbl, c2.m_data.num);
      cellCopy(numericConvHelper(c2), c2);
      assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
    }
  }

  if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
    return make_tv<KindOfArray>(o(c1.m_data.parr, c2.m_data.parr));
  }

  cellCopy(numericConvHelper(c1), c1);
  assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
  goto again;
}
コード例 #2
0
void c_AsyncFunctionWaitHandle::ret(Cell& result) {
  assert(isRunning());
  auto parentChain = getParentChain();
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
  parentChain.unblock();
}
コード例 #3
0
void c_AsyncFunctionWaitHandle::ret(Cell& result) {
  auto const parentChain = getFirstParent();
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
  UnblockChain(parentChain);
  decRefObj(this);
}
コード例 #4
0
ファイル: static_wait_handle.cpp プロジェクト: BillHu/hhvm
/**
 * Create succeeded StaticWaitHandle object.
 *
 * - consumes reference of the given cell
 * - produces reference for the returned StaticWaitHandle object
 *
 * Both the JIT and bytecode.cpp assume this function gives the nothrow
 * guarantee.
 */
c_StaticWaitHandle* c_StaticWaitHandle::CreateSucceeded(const Cell result) {
  auto waitHandle = newobj<c_StaticWaitHandle>();
  waitHandle->setState(STATE_SUCCEEDED);
  waitHandle->incRefCount();
  cellCopy(result, waitHandle->m_resultOrException);
  return waitHandle;
}
コード例 #5
0
ファイル: testCell.cpp プロジェクト: richardgboyd/exact_cover
TEST(Cell, copyConstructor)
{
   Cell cell(1,2);
   Cell cellCopy(cell);

   ASSERT_EQ(cell.getCol(), 1);
   ASSERT_EQ(cell.getRow(), 2);
}
コード例 #6
0
void c_AsyncGeneratorWaitHandle::ret(Cell& result) {
  auto parentChain = getParentChain();
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
  parentChain.unblock();
  decRefObj(m_generator);
  decRefObj(this);
}
コード例 #7
0
ファイル: static-wait-handle.cpp プロジェクト: 191919/hhvm
/**
 * Create failed StaticWaitHandle object.
 *
 * - consumes reference of the given Exception object
 * - produces reference for the returned StaticWaitHandle object
 */
c_StaticWaitHandle* c_StaticWaitHandle::CreateFailed(ObjectData* exception) {
  assert(exception);
  assert(exception->instanceof(SystemLib::s_ExceptionClass));

  auto waitHandle = makeSmartPtr<c_StaticWaitHandle>();
  waitHandle->setState(STATE_FAILED);
  cellCopy(make_tv<KindOfObject>(exception), waitHandle->m_resultOrException);
  return waitHandle.detach();
}
コード例 #8
0
void c_AsyncGeneratorWaitHandle::fail(ObjectData* exception) {
  AsioSession* session = AsioSession::Get();
  if (UNLIKELY(session->hasOnResumableFailCallback())) {
    session->onResumableFail(this, exception);
  }

  auto parentChain = getParentChain();
  setState(STATE_FAILED);
  cellCopy(make_tv<KindOfObject>(exception), m_resultOrException);
  parentChain.unblock();
  decRefObj(m_generator);
  decRefObj(this);
}
コード例 #9
0
/**
 * Mark the wait handle as failed due to PHP exception.
 *
 * - consumes reference of the given Exception object
 */
void c_AsyncFunctionWaitHandle::fail(ObjectData* exception) {
  assert(isRunning());
  assert(exception);
  assert(exception->instanceof(SystemLib::s_ExceptionClass));

  AsioSession* session = AsioSession::Get();
  if (UNLIKELY(session->hasOnResumableFailCallback())) {
    session->onResumableFail(this, exception);
  }

  auto const parentChain = getFirstParent();
  setState(STATE_FAILED);
  cellCopy(make_tv<KindOfObject>(exception), m_resultOrException);
  UnblockChain(parentChain);
  decRefObj(this);
}
コード例 #10
0
RefData* closureStaticLocInit(StringData* name, ActRec* fp, TypedValue val) {
  auto const func = fp->m_func;
  assert(func->isClosureBody() || func->isGeneratorFromClosure());
  auto const closureLoc =
    LIKELY(func->isClosureBody())
      ? frame_local(fp, func->numParams())
      : frame_local(fp, frame_continuation(fp)->m_origFunc->numParams());

  bool inited;
  auto const refData = lookupStaticFromClosure(
    closureLoc->m_data.pobj, name, inited);
  if (!inited) {
    cellCopy(val, *refData->tv());
  }
  refData->incRefCount();
  return refData;
}
コード例 #11
0
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));
  }
}
コード例 #12
0
ファイル: tv-arith.cpp プロジェクト: RyanCccc/hhvm
Cell cellArithO(Op o, Check ck, Over ov, Cell c1, Cell c2) {
  if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
    return cellArith(o, c1, c2);
  }

  auto ensure_num = [](Cell& c) {
    if (c.m_type != KindOfInt64 && c.m_type != KindOfDouble) {
      cellCopy(numericConvHelper(c), c);
    }
  };

  ensure_num(c1);
  ensure_num(c2);
  auto both_ints = (c1.m_type == KindOfInt64 && c2.m_type == KindOfInt64);
  int64_t a = c1.m_data.num;
  int64_t b = c2.m_data.num;

  return (both_ints && ck(a,b)) ? ov(a,b) : cellArith(o, c1, c2);
}
コード例 #13
0
/**
 * Mark the wait handle as failed due to PHP exception.
 *
 * - consumes reference of the given Exception object
 */
void c_AsyncFunctionWaitHandle::fail(ObjectData* exception) {
  assert(isRunning());
  assert(exception);
  assert(exception->instanceof(SystemLib::s_ThrowableClass));

  AsioSession* session = AsioSession::Get();
  if (UNLIKELY(session->hasOnResumableFail())) {
    try {
      session->onResumableFail(this, Object{exception});
    } catch (...) {
      // TODO(#4557954) Make unwinder able to deal with new exceptions better.
      handle_destructor_exception("AsyncFunctionWaitHandle fail callback");
    }
  }

  auto parentChain = getParentChain();
  setState(STATE_FAILED);
  cellCopy(make_tv<KindOfObject>(exception), m_resultOrException);
  parentChain.unblock();
}
コード例 #14
0
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()
    );
  }
}
コード例 #15
0
ファイル: static-wait-handle.cpp プロジェクト: 191919/hhvm
/**
 * Create succeeded StaticWaitHandle object.
 *
 * - consumes reference of the given cell
 * - produces reference for the returned StaticWaitHandle object
 *
 * Both the JIT and bytecode.cpp assume this function gives the nothrow
 * guarantee.
 */
c_StaticWaitHandle* c_StaticWaitHandle::CreateSucceeded(const Cell result) {
  auto waitHandle = makeSmartPtr<c_StaticWaitHandle>();
  waitHandle->setState(STATE_SUCCEEDED);
  cellCopy(result, waitHandle->m_resultOrException);
  return waitHandle.detach();
}
コード例 #16
0
void c_AsyncFunctionWaitHandle::ret(Cell& result) {
  setState(STATE_SUCCEEDED);
  cellCopy(result, m_resultOrException);
}
コード例 #17
0
ファイル: unwind.cpp プロジェクト: jmarrama/hhvm
/**
 * Discard the current frame, assuming that a PHP exception given in
 * phpException argument, or C++ exception (phpException == nullptr)
 * is being thrown. Returns an exception to propagate, or nulltpr
 * if the VM execution should be resumed.
 */
ObjectData* tearDownFrame(ActRec*& fp, Stack& stack, PC& pc,
                          ObjectData* phpException) {
  auto const func = fp->func();
  auto const curOp = peek_op(pc);
  auto const prevFp = fp->sfp();
  auto const soff = fp->m_soff;

  ITRACE(1, "tearDownFrame: {} ({})\n",
         func->fullName()->data(),
         func->unit()->filepath()->data());
  ITRACE(1, "  fp {} prevFp {}\n",
         implicit_cast<void*>(fp),
         implicit_cast<void*>(prevFp));

  // When throwing from a constructor, we normally want to avoid running the
  // destructor on an object that hasn't been fully constructed yet. But if
  // we're unwinding through the constructor's RetC, the constructor has
  // logically finished and we're unwinding for some internal reason (timeout
  // or user profiler, most likely). More importantly, fp->m_this may have
  // already been destructed and/or overwritten due to sharing space with
  // fp->m_r.
  if (curOp != OpRetC &&
      fp->hasThis() &&
      fp->getThis()->getVMClass()->getCtor() == func &&
      fp->getThis()->getVMClass()->getDtor()) {
    /*
     * Looks like an FPushCtor call, but it could still have been called
     * directly. Check the fpi region to be sure.
     */
    Offset prevPc;
    auto outer = g_context->getPrevVMState(fp, &prevPc);
    if (outer) {
      auto fe = outer->func()->findPrecedingFPI(prevPc);
      if (fe && isFPushCtor(outer->func()->unit()->getOp(fe->m_fpushOff))) {
        fp->getThis()->setNoDestruct();
      }
    }
  }

  auto const decRefLocals = [&] {
    /*
     * It is possible that locals have already been decref'd.
     *
     * Here's why:
     *
     *   - If a destructor for any of these things throws a php
     *     exception, it's swallowed at the dtor boundary and we keep
     *     running php.
     *
     *   - If the destructor for any of these things throws a fatal,
     *     it's swallowed, and we set surprise flags to throw a fatal
     *     from now on.
     *
     *   - If the second case happened and we have to run another
     *     destructor, its enter hook will throw, but it will be
     *     swallowed again.
     *
     *   - Finally, the exit hook for the returning function can
     *     throw, but this happens last so everything is destructed.
     *
     *   - When that happens, exit hook sets localsDecRefd flag.
     */
    if (!fp->localsDecRefd()) {
      try {
        // Note that we must convert locals and the $this to
        // uninit/zero during unwind.  This is because a backtrace
        // from another destructing object during this unwind may try
        // to read them.
        frame_free_locals_unwind(fp, func->numLocals(), phpException);
      } catch (...) {}
    }
  };

  if (LIKELY(!fp->resumed())) {
    decRefLocals();
    if (UNLIKELY(func->isAsyncFunction()) &&
        phpException &&
        !fp->isFCallAwait()) {
      // If in an eagerly executed async function, wrap the user exception
      // into a failed StaticWaitHandle and return it to the caller.
      auto const waitHandle = c_StaticWaitHandle::CreateFailed(phpException);
      phpException = nullptr;
      stack.ndiscard(func->numSlotsInFrame());
      stack.ret();
      assert(stack.topTV() == &fp->m_r);
      cellCopy(make_tv<KindOfObject>(waitHandle), fp->m_r);
    } else {
      // Free ActRec.
      stack.ndiscard(func->numSlotsInFrame());
      stack.discardAR();
    }
  } else if (func->isAsyncFunction()) {
    auto const waitHandle = frame_afwh(fp);
    if (phpException) {
      // Handle exception thrown by async function.
      decRefLocals();
      waitHandle->fail(phpException);
      phpException = nullptr;
    } else if (waitHandle->isRunning()) {
      // Let the C++ exception propagate. If the current frame represents async
      // function that is running, mark it as abruptly interrupted. Some opcodes
      // like Await may change state of the async function just before exit hook
      // decides to throw C++ exception.
      decRefLocals();
      waitHandle->failCpp();
    }
  } else if (func->isAsyncGenerator()) {
    auto const gen = frame_async_generator(fp);
    if (phpException) {
      // Handle exception thrown by async generator.
      decRefLocals();
      auto eagerResult = gen->fail(phpException);
      phpException = nullptr;
      if (eagerResult) {
        stack.pushObjectNoRc(eagerResult);
      }
    } else if (gen->isEagerlyExecuted() || gen->getWaitHandle()->isRunning()) {
      // Fail the async generator and let the C++ exception propagate.
      decRefLocals();
      gen->failCpp();
    }
  } else if (func->isNonAsyncGenerator()) {
    // Mark the generator as finished.
    decRefLocals();
    frame_generator(fp)->fail();
  } else {
    not_reached();
  }

  /*
   * At the final ActRec in this nesting level.
   */
  if (UNLIKELY(!prevFp)) {
    pc = nullptr;
    fp = nullptr;
    return phpException;
  }

  assert(stack.isValidAddress(reinterpret_cast<uintptr_t>(prevFp)) ||
         prevFp->resumed());
  auto const prevOff = soff + prevFp->func()->base();
  pc = prevFp->func()->unit()->at(prevOff);
  fp = prevFp;
  return phpException;
}