コード例 #1
0
ファイル: ext_continuation.cpp プロジェクト: Alienfeel/hhvm
void c_Continuation::copyContinuationVars(ActRec* fp) {
  // For functions that contain only named locals, we can copy TVs
  // right to the local space.
  static const StringData* thisStr = s_this.get();
  bool skipThis;
  if (fp->hasVarEnv()) {
    Stats::inc(Stats::Cont_CreateVerySlow);
    Array definedVariables = fp->getVarEnv()->getDefinedVariables();
    skipThis = definedVariables.exists(s_this, true);

    for (ArrayIter iter(definedVariables); !iter.end(); iter.next()) {
      dupContVar(iter.first().getStringData(),
                 const_cast<TypedValue *>(iter.secondRef().asTypedValue()));
    }
  } else {
    const Func *genFunc = actRec()->m_func;
    skipThis = genFunc->lookupVarId(thisStr) != kInvalidId;
    for (Id i = 0; i < genFunc->numNamedLocals(); ++i) {
      dupContVar(genFunc->localVarName(i), frame_local(fp, i));
    }
  }

  // If $this is used as a local inside the body and is not provided
  // by our containing environment, just prefill it here instead of
  // using InitThisLoc inside the body
  if (!skipThis && fp->hasThis()) {
    Id id = actRec()->m_func->lookupVarId(thisStr);
    if (id != kInvalidId) {
      tvAsVariant(frame_local(actRec(), id)) = fp->getThis();
    }
  }
}
コード例 #2
0
String c_Continuation::t_getorigfuncname() {
  INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::getorigfuncname);
  String called_class;
  if (hhvm) {
    if (actRec()->hasThis()) {
      called_class = actRec()->getThis()->getVMClass()->name()->data();
    } else if (actRec()->hasClass()) {
      called_class = actRec()->getClass()->name()->data();
    }
  } else {
    called_class = getCalledClass();
  }
  if (called_class.size() == 0) {
    return m_origFuncName;
  }

  /*
    Replace the class name in m_origFuncName with the LSB class.  This
    produces more useful traces.
   */
  size_t method_pos = m_origFuncName.find("::");
  if (method_pos != std::string::npos) {
    return concat3(called_class, "::", m_origFuncName.substr(method_pos+2));
  } else {
    return m_origFuncName;
  }
}
コード例 #3
0
// Get the filename in which execution will proceed when execution resumes.
String c_AsyncFunctionWaitHandle::getFileName() {
  if (actRec()->func()->originalFilename()) {
    return actRec()->func()->originalFilename()->data();
  } else {
    return actRec()->func()->unit()->filepath()->data();
  }
}
コード例 #4
0
c_AsyncFunctionWaitHandle::~c_AsyncFunctionWaitHandle() {
  if (LIKELY(isFinished())) {
    return;
  }

  assert(!isRunning());
  frame_free_locals_inl_no_hook<false>(actRec(), actRec()->func()->numLocals());
  decRefObj(m_children[0].getChild());
}
コード例 #5
0
c_AsyncFunctionWaitHandle::~c_AsyncFunctionWaitHandle() {
  if (LIKELY(isFinished())) {
    assert(!m_child);
    return;
  }

  frame_free_locals_inl_no_hook<false>(actRec(), actRec()->func()->numLocals());
  if (m_child) {
    decRefObj(m_child);
  }
}
コード例 #6
0
String c_Continuation::t_getcalledclass() {
  String called_class;
  if (actRec()->hasThis()) {
    called_class = actRec()->getThis()->getVMClass()->name()->data();
  } else if (actRec()->hasClass()) {
    called_class = actRec()->getClass()->name()->data();
  } else {
    called_class = String("");
  }

  return called_class;
}
コード例 #7
0
ファイル: cmd_next.cpp プロジェクト: Einkoro/hhvm
// A AsyncSuspend is used in the codegen for an async function to setup
// a Continuation and return a wait handle so execution can continue
// later. We have just completed a AsyncSuspend, so the new
// Continuation is available, and it can predict where execution will
// resume.
void CmdNext::stepAfterAsyncSuspend() {
  auto topObj = g_context->getStack().topTV()->m_data.pobj;
  assert(topObj->instanceof(c_AsyncFunctionWaitHandle::classof()));
  auto wh = static_cast<c_AsyncFunctionWaitHandle*>(topObj);
  auto func = wh->actRec()->m_func;
  Offset nextInst = wh->getNextExecutionOffset();
  assert(nextInst != InvalidAbsoluteOffset);
  m_stepContTag = wh->actRec();
  TRACE(2,
        "CmdNext: patch for cont step after AsyncSuspend at '%s' offset %d\n",
        func->fullName()->data(), nextInst);
  m_stepCont = StepDestination(func->unit(), nextInst);
}
コード例 #8
0
ファイル: ext_generator.cpp プロジェクト: drrm/hhvm
String c_Generator::t_getcalledclass() {
  String called_class;

  if (actRec()->hasThis()) {
    called_class = actRec()->getThis()->getVMClass()->name()->data();
  } else if (actRec()->hasClass()) {
    called_class = actRec()->getClass()->name()->data();
  } else {
    called_class = empty_string();
  }

  return called_class;
}
コード例 #9
0
ファイル: cmd_next.cpp プロジェクト: facebook/hhvm
// An Await opcode is used in the codegen for an async function to suspend
// execution until the given wait handle is finished. In eager execution,
// the state is suspended into a new AsyncFunctionWaitHandle object so that
// the execution can continue later. We have just completed an Await, so
// the new AsyncFunctionWaitHandle is now available, and it can predict
// where execution will resume.
void CmdNext::stepAfterAwait() {
  auto topObj = vmsp()->m_data.pobj;
  assertx(topObj->instanceof(c_AsyncFunctionWaitHandle::classof()));
  auto wh = static_cast<c_AsyncFunctionWaitHandle*>(topObj);
  auto func = wh->actRec()->func();
  Offset nextInst = wh->getNextExecutionOffset();
  assertx(nextInst != InvalidAbsoluteOffset);
  m_stepResumableId = wh->actRec();
  TRACE(2,
        "CmdNext: patch for cont step after Await at '%s' offset %d\n",
        func->fullName()->data(), nextInst);
  m_stepResumable = StepDestination(func->unit(), nextInst);
}
コード例 #10
0
ファイル: backtrace.cpp プロジェクト: aruiz14/hhvm
static ActRec* getPrevActRec(const ActRec* fp, Offset* prevPc) {
  if (fp && fp->func() && fp->resumed() && fp->func()->isAsyncFunction()) {
    c_WaitableWaitHandle* currentWaitHandle = frame_afwh(fp);
    if (currentWaitHandle->isFinished()) {
      /*
       * It's possible in very rare cases (it will return a truncated stack):
       * 1) async function which WaitHandle is not referenced by anything
       *      else finishes
       * 2) its return value is an object with destructor
       * 3) this destructor gets called as part of destruction of the
       *      WaitHandleobject, which happens right before FP is adjusted
      */
      return nullptr;
    }

    auto const contextIdx = currentWaitHandle->getContextIdx();
    while (currentWaitHandle != nullptr) {
      auto p = currentWaitHandle->getParentChain().firstInContext(contextIdx);
      if (p == nullptr) break;

      if (p->getKind() == c_WaitHandle::Kind::AsyncFunction) {
        auto wh = p->asAsyncFunction();
        *prevPc = wh->resumable()->resumeOffset();
        return wh->actRec();
      }
      currentWaitHandle = p;
    }
    *prevPc = 0;
    return AsioSession::Get()->getContext(contextIdx)->getSavedFP();
  }
  return g_context->getPrevVMState(fp, prevPc);
}
コード例 #11
0
c_AsyncFunctionWaitHandle*
c_AsyncFunctionWaitHandle::Create(const ActRec* fp,
                                  size_t numSlots,
                                  jit::TCA resumeAddr,
                                  Offset resumeOffset,
                                  c_WaitableWaitHandle* child) {
  assert(fp);
  assert(!fp->resumed());
  assert(fp->func()->isAsyncFunction());
  assert(child);
  assert(child->instanceof(c_WaitableWaitHandle::classof()));
  assert(!child->isFinished());

  constexpr const size_t objSize = sizeof(c_AsyncFunctionWaitHandle);
  void* obj = Resumable::Create<false, objSize, mayUseVV>(fp,
                                                          numSlots,
                                                          resumeAddr,
                                                          resumeOffset);
  auto const waitHandle = new (obj) c_AsyncFunctionWaitHandle();
  assert(waitHandle->hasExactlyOneRef());
  waitHandle->actRec()->setReturnVMExit();
  assert(waitHandle->noDestruct());
  waitHandle->initialize(child);
  return waitHandle;
}
コード例 #12
0
c_AsyncFunctionWaitHandle*
c_AsyncFunctionWaitHandle::Create(const ActRec* fp,
                                  size_t numSlots,
                                  jit::TCA resumeAddr,
                                  Offset resumeOffset,
                                  c_WaitableWaitHandle* child) {
  assert(fp);
  assert(!fp->resumed());
  assert(fp->func()->isAsyncFunction());
  assert(child);
  assert(child->instanceof(c_WaitableWaitHandle::classof()));
  assert(!child->isFinished());

  const size_t frameSize = Resumable::getFrameSize(numSlots);
  const size_t totalSize = sizeof(ResumableNode) + frameSize +
                           sizeof(Resumable) +
                           sizeof(c_AsyncFunctionWaitHandle);
  auto const resumable = Resumable::Create(frameSize, totalSize);
  resumable->initialize<false, mayUseVV>(fp,
                                         resumeAddr,
                                         resumeOffset,
                                         frameSize,
                                         totalSize);
  auto const waitHandle = new (resumable + 1) c_AsyncFunctionWaitHandle();
  assert(waitHandle->hasExactlyOneRef());
  waitHandle->actRec()->setReturnVMExit();
  assert(waitHandle->noDestruct());
  waitHandle->initialize(child);
  return waitHandle;
}
コード例 #13
0
ファイル: ext_continuation.cpp プロジェクト: Alienfeel/hhvm
String c_Continuation::t_getorigfuncname() {
  const Func* origFunc = actRec()->func()->getGeneratorOrigFunc();
  auto const origName = origFunc->isClosureBody() ? s__closure_.get()
                                                  : origFunc->name();
  assert(origName->isStatic());
  return String(const_cast<StringData*>(origName));
}
コード例 #14
0
// Get the line number on which execution will proceed when execution resumes.
int c_AsyncFunctionWaitHandle::getLineNumber() {
  if (isFinished()) {
    return -1;
  }

  always_assert(!isRunning());
  return actRec()->func()->unit()->getLineNumber(resumable()->resumeOffset());
}
コード例 #15
0
ファイル: cmd_variable.cpp プロジェクト: Fininvest/hhvm
bool CmdVariable::onServer(DebuggerProxy &proxy) {
  if (m_type == KindOfVariableAsync) {
    //we only do variable inspection on continuation wait handles
    auto frame = getWaitHandleAtAsyncStackPosition(m_frame);

    if (frame != nullptr) {
      auto fp = frame->actRec();
      if (fp != nullptr) {
        m_variables = getVariables(fp);
      }
    }
  }
  else if (m_frame < 0) {
    m_variables = g_context->m_globalVarEnv->getDefinedVariables();
    m_global = true;
  } else {
    m_variables = g_context->getLocalDefinedVariables(m_frame);
    m_global = g_context->getVarEnv(m_frame) == g_context->m_globalVarEnv;
  }

  if (m_global) {
    m_variables.remove(s_GLOBALS);
  }
  if (m_version == 1) {
    // Remove the values before sending to client.
    ArrayInit ret(m_variables->size(), ArrayInit::Map{});
    Variant v;
    for (ArrayIter iter(m_variables); iter; ++iter) {
      ret.add(iter.first().toString(), v);
    }
    m_variables = ret.toArray();
    m_version = 2;
  } else if (m_version == 2) {
    // Remove entries that do not match a non empty m_varName.
    if (!m_varName.empty()) {
      ArrayInit ret(1, ArrayInit::Map{});
      ret.add(m_varName, m_variables[m_varName]);
      m_variables = ret.toArray();
    }
    // Remove entries whose name or contents do not match a non empty m_filter
    if (!m_filter.empty()) {
      ArrayInit ret(m_variables.size(), ArrayInit::Map{});
      for (ArrayIter iter(m_variables); iter; ++iter) {
        String name = iter.first().toString();
        if (name.find(m_filter, 0, false) < 0) {
          String fullvalue = DebuggerClient::FormatVariable(iter.second(), -1);
          if (fullvalue.find(m_filter, 0, false) < 0) {
            continue;
          }
        }
        ret.add(name, iter.second());
      }
      m_variables = ret.toArray();
    }
  }

  return proxy.sendToClient(this);
}
コード例 #16
0
c_Continuation::~c_Continuation() {
  ActRec* ar = actRec();

  if (ar->hasVarEnv()) {
    ar->getVarEnv()->detach(ar);
  } else {
    frame_free_locals_inl(ar, ar->m_func->numLocals());
  }
}
コード例 #17
0
c_Continuation::c_Continuation(const ObjectStaticCallbacks *cb) :
    ExtObjectData(cb),
#ifndef HHVM
    LABEL_INIT,
#endif
    m_index(-1LL),
    m_value(Variant::nullInit), m_received(Variant::nullInit),
    m_done(false), m_running(false), m_should_throw(false),
    m_isMethod(false), m_callInfo(NULL)
#ifdef HHVM
    , LABEL_INIT
#endif
{
}
#undef LABEL_INIT

c_Continuation::~c_Continuation() {
  if (hhvm) {
    VM::ActRec* ar = actRec();

    // The first local is the object itself, and it wasn't increffed at creation
    // time (see createContinuation()). Overwrite its type to exempt it from
    // refcounting here.
    TypedValue* contLocal = frame_local(ar, 0);
    ASSERT(contLocal->m_data.pobj == this);
    contLocal->m_type = KindOfNull;

    if (ar->hasVarEnv()) {
      VM::VarEnv::destroy(ar->getVarEnv());
    } else {
      frame_free_locals_inl(ar, m_vmFunc->numLocals());
    }
  }
}

void c_Continuation::t___construct(
    int64 func, int64 extra, bool isMethod,
    CStrRef origFuncName, CVarRef obj, CArrRef args) {
  INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::__construct);
  if (hhvm) {
    m_vmFunc       = (VM::Func*) extra;
    ASSERT(m_vmFunc);
  } else {
    m_callInfo     = (const CallInfo*) func;
    ASSERT(m_callInfo);
  }
  m_isMethod     = isMethod;
  m_origFuncName = origFuncName;

  if (!obj.isNull()) {
    m_obj = obj.toObject();
    ASSERT(!m_obj.isNull());
  } else {
    ASSERT(m_obj.isNull());
  }
  m_args = args;
}
コード例 #18
0
c_Continuation *c_Continuation::clone() {
  const Func *origFunc = m_origFunc;
  const Func *genFunc = actRec()->m_func;

  ActRec *fp = g_vmContext->getFP();
  c_Continuation* cont = origFunc->isMethod()
    ? g_vmContext->createContMeth(origFunc, genFunc, fp->getThisOrClass())
    : g_vmContext->createContFunc(origFunc, genFunc);

  cont->copyContinuationVars(actRec());

  cont->o_subclassData.u16 = o_subclassData.u16;
  cont->m_label = m_label;
  cont->m_index = m_index;
  cont->m_key   = m_key;
  cont->m_value = m_value;

  return cont;
}
コード例 #19
0
c_Continuation::~c_Continuation() {
  tvRefcountedDecRef(m_key);
  tvRefcountedDecRef(m_value);

  // Free locals, but don't trigger the EventHook for FunctionExit
  // since the continuation function has already been exited. We
  // don't want redundant calls.
  ActRec* ar = actRec();
  frame_free_locals_inl_no_hook<false>(ar, ar->m_func->numLocals());
}
コード例 #20
0
void c_Continuation::suspend(Offset offset, const Cell& key,
                             const Cell& value) {
  assert(actRec()->func()->contains(offset));
  m_offset = offset;
  cellSet(key, m_key);
  cellSet(value, m_value);
  if (m_key.m_type == KindOfInt64) {
    int64_t new_index = m_key.m_data.num;
    m_index = new_index > m_index ? new_index : m_index;
  }
}
コード例 #21
0
ファイル: ext_continuation.cpp プロジェクト: redknight/hhvm
c_Continuation *c_Continuation::Clone(ObjectData* obj) {
    auto thiz = static_cast<c_Continuation*>(obj);
    const Func *origFunc = thiz->m_origFunc;
    const Func *genFunc = thiz->actRec()->m_func;

    ActRec *fp = g_vmContext->getFP();
    c_Continuation* cont = origFunc->isMethod()
                           ? g_vmContext->createContMeth(origFunc, genFunc, fp->getThisOrClass())
                           : g_vmContext->createContFunc(origFunc, genFunc);

    cont->copyContinuationVars(thiz->actRec());

    cont->o_subclassData.u16 = thiz->o_subclassData.u16;
    cont->m_label = thiz->m_label;
    cont->m_index = thiz->m_index;
    cont->m_key   = thiz->m_key;
    cont->m_value = thiz->m_value;

    return cont;
}
コード例 #22
0
String c_AsyncFunctionWaitHandle::getName() {
  switch (getState()) {
    case STATE_BLOCKED:
    case STATE_READY:
    case STATE_RUNNING: {
      auto func = actRec()->func();
      if (!func->cls() ||
          func->cls()->attrs() & AttrNoOverride ||
          actRec()->localsDecRefd()) {
        auto name = func->fullName();
        if (func->isClosureBody()) {
          const char* p = strchr(name->data(), ':');
          if (p) {
            return
              concat(String(name->data(), p + 1 - name->data(), CopyString),
                     s__closure_);
          } else {
            return s__closure_;
          }
        }
        return String{const_cast<StringData*>(name)};
      }

      auto const cls = actRec()->hasThis() ?
        actRec()->getThis()->getVMClass() :
        actRec()->getClass();

      if (cls == func->cls() && !func->isClosureBody()) {
        return String{const_cast<StringData*>(func->fullName())};
      }

      StrNR funcName(func->isClosureBody() ? s__closure_.get() : func->name());

      return concat3(cls->nameStr(), "::", funcName);
    }

    default:
      raise_fatal_error(
          "Invariant violation: encountered unexpected state");
  }
}
コード例 #23
0
AsyncGenerator::~AsyncGenerator() {
  if (LIKELY(getState() == State::Done)) {
    return;
  }

  assert(!isRunning());

  // Free locals, but don't trigger the EventHook for FunctionReturn since
  // the generator has already been exited. We don't want redundant calls.
  ActRec* ar = actRec();
  frame_free_locals_inl_no_hook(ar, ar->m_func->numLocals());
}
コード例 #24
0
ファイル: ext_continuation.cpp プロジェクト: Alienfeel/hhvm
c_Continuation::~c_Continuation() {
  ActRec* ar = actRec();

  if (ar->hasVarEnv()) {
    ar->getVarEnv()->detach(ar);
  } else {
    // Free locals, but don't trigger the EventHook for FunctionExit
    // since the continuation function has already been exited. We
    // don't want redundant calls.
    frame_free_locals_inl_no_hook<false>(ar, ar->m_func->numLocals());
  }
}
コード例 #25
0
String c_AsyncFunctionWaitHandle::getName() {
    switch (getState()) {
    case STATE_BLOCKED:
    case STATE_SCHEDULED:
    case STATE_RUNNING: {
        String funcName;
        if (actRec()->func()->isClosureBody()) {
            // Can we do better than this?
            funcName = s__closure_;
        } else {
            funcName = actRec()->func()->name()->data();
        }

        String clsName;
        if (actRec()->hasThis()) {
            clsName = actRec()->getThis()->getVMClass()->name()->data();
        } else if (actRec()->hasClass()) {
            clsName = actRec()->getClass()->name()->data();
        } else {
            return funcName;
        }

        return concat3(clsName, "::", funcName);
    }

    default:
        throw FatalErrorException(
            "Invariant violation: encountered unexpected state");
    }
}
コード例 #26
0
void c_Continuation::dupContVar(const StringData* name, TypedValue* src) {
  ActRec *fp = actRec();
  Id destId = fp->m_func->lookupVarId(name);
  if (destId != kInvalidId) {
    // Copy the value of the local to the cont object.
    tvDupFlattenVars(src, frame_local(fp, destId));
  } else {
    if (!fp->hasVarEnv()) {
      fp->setVarEnv(VarEnv::createLocal(fp));
    }
    fp->getVarEnv()->setWithRef(name, src);
  }
}
コード例 #27
0
ファイル: ext_generator.cpp プロジェクト: KOgames/hhvm
Generator::~Generator() {
  if (LIKELY(getState() == State::Done)) {
    return;
  }

  assert(getState() != State::Running);
  tvRefcountedDecRef(m_key);
  tvRefcountedDecRef(m_value);

  // Free locals, but don't trigger the EventHook for FunctionReturn since
  // the generator has already been exited. We don't want redundant calls.
  ActRec* ar = actRec();
  frame_free_locals_inl_no_hook<false>(ar, ar->func()->numLocals());
}
コード例 #28
0
ファイル: ext_generator.cpp プロジェクト: NIT-Warangal/Judge
c_Generator *c_Generator::Clone(ObjectData* obj) {
  auto thiz = static_cast<c_Generator*>(obj);
  auto fp = thiz->actRec();

  c_Generator* cont = Create(fp, thiz->resumable()->resumeAddr(),
                                    thiz->resumable()->resumeOffset());
  cont->copyVars(fp);
  cont->setState(thiz->getState());
  cont->m_index  = thiz->m_index;
  cellSet(thiz->m_key, cont->m_key);
  cellSet(thiz->m_value, cont->m_value);

  return cont;
}
コード例 #29
0
ファイル: ext_generator.cpp プロジェクト: drrm/hhvm
c_Generator::~c_Generator() {
  if (LIKELY(getState() == Done)) {
    return;
  }

  tvRefcountedDecRef(m_key);
  tvRefcountedDecRef(m_value);

  // Free locals, but don't trigger the EventHook for FunctionReturn
  // since the generator has already been exited. We
  // don't want redundant calls.
  ActRec* ar = actRec();
  frame_free_locals_inl_no_hook<false>(ar, ar->m_func->numLocals());
}
コード例 #30
0
String c_AsyncFunctionWaitHandle::getName() {
  switch (getState()) {
    case STATE_BLOCKED:
    case STATE_READY:
    case STATE_RUNNING: {
      auto func = actRec()->func();
      if (!actRec()->getThisOrClass() ||
          func->cls()->attrs() & AttrNoOverride) {
        auto name = func->fullName();
        if (func->isClosureBody()) {
          const char* p = strchr(name->data(), ':');
          if (p) {
            return
              concat(String(name->data(), p + 1 - name->data(), CopyString),
                     s__closure_);
          } else {
            return s__closure_;
          }
        }
        return String{const_cast<StringData*>(name)};
      }
      String funcName;
      if (actRec()->func()->isClosureBody()) {
        // Can we do better than this?
        funcName = s__closure_;
      } else {
        funcName = const_cast<StringData*>(actRec()->func()->name());
      }

      String clsName;
      if (actRec()->hasThis()) {
        clsName = const_cast<StringData*>(actRec()->getThis()->
                                          getVMClass()->name());
      } else if (actRec()->hasClass()) {
        clsName = const_cast<StringData*>(actRec()->getClass()->name());
      } else {
        return funcName;
      }

      return concat3(clsName, "::", funcName);
    }

    default:
      raise_fatal_error(
          "Invariant violation: encountered unexpected state");
  }
}