void PreClassRepoProxy::GetPreClassesStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT preClassId,name,hoistable,extraData FROM " << m_repo.table(m_repoId, "PreClass") << " WHERE unitSn == @unitSn ORDER BY preClassId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.sn()); do { query.step(); if (query.row()) { Id preClassId; /**/ query.getId(0, preClassId); StringData* name; /**/ query.getStaticString(1, name); int hoistable; /**/ query.getInt(2, hoistable); BlobDecoder extraBlob = /**/ query.getBlob(3); PreClassEmitter* pce = ue.newPreClassEmitter( name, (PreClass::Hoistable)hoistable); pce->serdeMetaData(extraBlob); if (!SystemLib::s_inited) { assert(pce->attrs() & AttrPersistent); assert(pce->attrs() & AttrUnique); } assert(pce->id() == preClassId); } } while (!query.done()); txn.commit(); }
void FuncRepoProxy::GetFuncsStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT funcSn,preClassId,name,top,extraData " "FROM " << m_repo.table(m_repoId, "Func") << " WHERE unitSn == @unitSn ORDER BY funcSn ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.m_sn); do { query.step(); if (query.row()) { int funcSn; /**/ query.getInt(0, funcSn); Id preClassId; /**/ query.getId(1, preClassId); StringData* name; /**/ query.getStaticString(2, name); bool top; /**/ query.getBool(3, top); BlobDecoder extraBlob = /**/ query.getBlob(4); FuncEmitter* fe; if (preClassId < 0) { fe = ue.newFuncEmitter(name); } else { PreClassEmitter* pce = ue.pce(preClassId); fe = ue.newMethodEmitter(name, pce); bool added UNUSED = pce->addMethod(fe); assert(added); } assert(fe->sn() == funcSn); fe->top = top; fe->serdeMetaData(extraBlob); if (!SystemLib::s_inited && !fe->isPseudoMain()) { assert(fe->attrs & AttrBuiltin); if (preClassId < 0) { assert(fe->attrs & AttrPersistent); assert(fe->attrs & AttrUnique); assert(fe->attrs & AttrSkipFrame); } } fe->setEHTabIsSorted(); fe->finish(fe->past, true); ue.recordFunction(fe); } } while (!query.done()); txn.commit(); }
void parse_methods(ParseUnitState& puState, borrowed_ptr<php::Class> ret, borrowed_ptr<php::Unit> unit, const PreClassEmitter& pce) { for (auto& me : pce.methods()) { auto f = parse_func(puState, unit, ret, *me); ret->methods.push_back(std::move(f)); } }
PreClassEmitter* UnitEmitter::newPreClassEmitter( const StringData* name, PreClass::Hoistable hoistable ) { if (hoistable && m_hoistablePreClassSet.count(name)) { hoistable = PreClass::Mergeable; } PreClassEmitter* pce = new PreClassEmitter(*this, m_pceVec.size(), name, hoistable); if (hoistable >= PreClass::MaybeHoistable) { m_hoistablePreClassSet.insert(name); if (hoistable == PreClass::ClosureHoistable) { // Closures should appear at the VERY top of the file, so if any class in // the same file tries to use them, they are already defined. We had a // fun race where one thread was autoloading a file, finished parsing the // class, then another thread came along and saw the class was already // loaded and ran it before the first thread had time to parse the // closure class. m_hoistablePceIdList.push_front(pce->id()); } else { m_hoistablePceIdList.push_back(pce->id()); } } else { m_allClassesHoistable = false; } if (hoistable >= PreClass::Mergeable && hoistable < PreClass::AlwaysHoistable) { if (m_returnSeen) { m_allClassesHoistable = false; } else { pushMergeableClass(pce); } } m_pceVec.push_back(pce); return pce; }
void parse_methods(ParseUnitState& puState, borrowed_ptr<php::Class> ret, borrowed_ptr<php::Unit> unit, const PreClassEmitter& pce) { std::unique_ptr<php::Func> cinit; for (auto& me : pce.methods()) { auto f = parse_func(puState, unit, ret, *me); if (f->name == s_86cinit.get()) { cinit = std::move(f); } else { ret->methods.push_back(std::move(f)); } } if (cinit) ret->methods.push_back(std::move(cinit)); }
void parse_methods(ParseUnitState& puState, borrowed_ptr<php::Class> ret, borrowed_ptr<php::Unit> unit, const PreClassEmitter& pce) { std::unordered_map< SString, borrowed_ptr<php::Func>, string_data_hash, string_data_isame > innerGenerators; std::vector<std::pair<borrowed_ptr<php::Func>,SString>> generatorsToLink; for (auto& me : pce.methods()) { auto f = parse_func(puState, unit, ret, *me); if (f->isGeneratorBody) { always_assert(!innerGenerators.count(f->name)); innerGenerators[f->name] = borrow(f); } if (me->getGeneratorBodyName() && !f->isClosureBody) { generatorsToLink.emplace_back(borrow(f), me->getGeneratorBodyName()); } ret->methods.push_back(std::move(f)); } for (auto kv : generatorsToLink) { auto const it = innerGenerators.find(kv.second); assert(it != end(innerGenerators)); auto const outer = kv.first; auto const inner = it->second; assert(inner->isGeneratorBody); assert(!inner->innerGeneratorFunc && !inner->outerGeneratorFunc); assert(!outer->innerGeneratorFunc && !outer->outerGeneratorFunc); inner->outerGeneratorFunc = outer; outer->innerGeneratorFunc = inner; } }
std::unique_ptr<php::Class> parse_class(ParseUnitState& puState, borrowed_ptr<php::Unit> unit, const PreClassEmitter& pce) { FTRACE(2, " class: {}\n", pce.name()->data()); auto ret = folly::make_unique<php::Class>(); ret->name = pce.name(); ret->srcInfo = php::SrcInfo { pce.getLocation(), pce.docComment() }; ret->unit = unit; ret->closureContextCls = nullptr; ret->parentName = pce.parentName()->empty() ? nullptr : pce.parentName(); ret->attrs = pce.attrs(); ret->hoistability = pce.hoistability(); ret->userAttributes = pce.userAttributes(); for (auto& iface : pce.interfaces()) { ret->interfaceNames.push_back(iface); } ret->usedTraitNames = pce.usedTraits(); ret->traitPrecRules = pce.traitPrecRules(); ret->traitAliasRules = pce.traitAliasRules(); ret->traitRequirements = pce.traitRequirements(); parse_methods(puState, borrow(ret), unit, pce); auto& propMap = pce.propMap(); for (size_t idx = 0; idx < propMap.size(); ++idx) { auto& prop = propMap[idx]; ret->properties.push_back( php::Prop { prop.name(), prop.attrs(), prop.docComment(), prop.typeConstraint(), prop.val() } ); } auto& constMap = pce.constMap(); for (size_t idx = 0; idx < constMap.size(); ++idx) { auto& cconst = constMap[idx]; ret->constants.push_back( php::Const { cconst.name(), cconst.val(), cconst.phpCode(), cconst.typeConstraint() } ); } return ret; }