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; }
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(); } }