Пример #1
0
const uchar* InstPointInfo::lookupPC() {
  TRACE(2, "InstPointInfo::lookupPC\n");
  VMExecutionContext* context = g_vmContext;
  if (m_locType == LocHere) {
    // Instrument to current location
    ActRec *fp = context->getFP();
    if (!fp) {
      return nullptr;
    }
    PC pc = context->getPC();
    HPHP::Unit *unit = fp->m_func->unit();
    if (!unit) {
      return nullptr;
    }
    m_file = unit->filepath()->data();
    m_line = unit->getLineNumber(unit->offsetOf(pc));
    return pc;
  }
  // TODO for file and line
  return nullptr;
}
Пример #2
0
Class* Unit::defClass(PreClass* preClass,
                      bool failIsFatal /* = true */) {
  Class* const* clsList = preClass->namedEntity()->clsList();
  Class* top = *clsList;
  if (top) {
    Class *cls = top->getCached();
    if (cls) {
      // Raise a fatal unless the existing class definition is identical to the
      // one this invocation would create.
      if (cls->preClass() != preClass) {
        if (failIsFatal) {
          raise_error("Class already declared: %s", preClass->name()->data());
        }
        return NULL;
      }
      return cls;
    }
  }
  // Get a compatible Class, and add it to the list of defined classes.

  Class* parent = NULL;
  for (;;) {
    // Search for a compatible extant class.  Searching from most to least
    // recently created may have better locality than alternative search orders.
    // In addition, its the only simple way to make this work lock free...
    for (Class* class_ = top; class_ != NULL; class_ = class_->m_nextClass) {
      if (class_->preClass() != preClass) continue;

      Class::Avail avail = class_->avail(parent, failIsFatal /*tryAutoload*/);
      if (LIKELY(avail == Class::AvailTrue)) {
        class_->setCached();
        DEBUGGER_ATTACHED_ONLY(phpDefClassHook(class_));
        return class_;
      }
      if (avail == Class::AvailFail) {
        if (failIsFatal) {
          raise_error("unknown class %s", parent->name()->data());
        }
        return NULL;
      }
      ASSERT(avail == Class::AvailFalse);
    }

    // Create a new class.
    if (!parent && preClass->parent()->size() != 0) {
      parent = Unit::getClass(preClass->parent(), failIsFatal);
      if (parent == NULL) {
        if (failIsFatal) {
          raise_error("unknown class %s", preClass->parent()->data());
        }
        return NULL;
      }
    }

    VMExecutionContext* ec = g_vmContext;
    ActRec* fp = ec->getFP();
    PC pc = ec->getPC();

    bool needsFrame = ec->m_stack.top() &&
      (!fp || fp->m_func->unit() != preClass->unit());

    if (needsFrame) {
      /*
        we can be called from Unit::merge, which hasnt yet setup
        the frame (because often it doesnt need to).
        Set up a fake frame here, in case of errors.
        But note that mergeUnit is called for systemlib etc before the
        stack has been setup. So dont do anything if m_stack.top()
        is NULL
      */
      ActRec &tmp = *ec->m_stack.allocA();
      tmp.m_savedRbp = (uint64_t)fp;
      tmp.m_savedRip = 0;
      tmp.m_func = preClass->unit()->getMain();
      tmp.m_soff = preClass->getOffset() - tmp.m_func->base();
      tmp.setThis(NULL);
      tmp.m_varEnv = 0;
      tmp.initNumArgs(0);
      ec->m_fp = &tmp;
      ec->m_pc = preClass->unit()->at(preClass->getOffset());
      ec->pushLocalsAndIterators(tmp.m_func);
    }
    ClassPtr newClass(Class::newClass(preClass, parent));
    if (needsFrame) {
      ec->m_stack.top() = (Cell*)(ec->m_fp+1);
      ec->m_fp = fp;
      ec->m_pc = pc;
    }
    Lock l(Unit::s_classesMutex);
    /*
      We could re-enter via Unit::getClass() or class_->avail(), so
      no need for *clsList to be volatile
    */
    if (UNLIKELY(top != *clsList)) {
      top = *clsList;
      continue;
    }
    if (top) {
      newClass->m_cachedOffset = top->m_cachedOffset;
    } else {
      newClass->m_cachedOffset =
        Transl::TargetCache::allocKnownClass(preClass->name());
    }
    newClass->m_nextClass = top;
    Util::compiler_membar();
    *const_cast<Class**>(clsList) = newClass.get();
    newClass.get()->incAtomicCount();
    newClass.get()->setCached();
    DEBUGGER_ATTACHED_ONLY(phpDefClassHook(newClass.get()));
    return newClass.get();
  }
}