PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/vm/preclass-emitter.cpp

https://gitlab.com/0072016/0072016-PHP.LLC
C++ | 429 lines | 351 code | 50 blank | 28 comment | 45 complexity | b5fae05fcc57d81d1b070f3be7d077f4 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/vm/preclass-emitter.h"
  17. #include <limits>
  18. #include <folly/Memory.h>
  19. #include "hphp/runtime/base/array-iterator.h"
  20. #include "hphp/runtime/vm/repo.h"
  21. #include "hphp/runtime/vm/blob-helper.h"
  22. #include "hphp/runtime/vm/native.h"
  23. #include "hphp/runtime/vm/native-data.h"
  24. namespace HPHP {
  25. //=============================================================================
  26. // PreClassEmitter::Prop.
  27. PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
  28. const StringData* n,
  29. Attr attrs,
  30. const StringData* typeConstraint,
  31. const StringData* docComment,
  32. const TypedValue* val,
  33. RepoAuthType repoAuthType)
  34. : m_name(n)
  35. , m_attrs(attrs)
  36. , m_typeConstraint(typeConstraint)
  37. , m_docComment(docComment)
  38. , m_repoAuthType(repoAuthType)
  39. {
  40. m_mangledName = PreClass::manglePropName(pce->name(), n, attrs);
  41. memcpy(&m_val, val, sizeof(TypedValue));
  42. }
  43. PreClassEmitter::Prop::~Prop() {
  44. }
  45. //=============================================================================
  46. // PreClassEmitter.
  47. PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
  48. Id id,
  49. const StringData* n,
  50. PreClass::Hoistable hoistable)
  51. : m_ue(ue)
  52. , m_name(n)
  53. , m_id(id)
  54. , m_hoistable(hoistable)
  55. {}
  56. void PreClassEmitter::init(int line1, int line2, Offset offset, Attr attrs,
  57. const StringData* parent,
  58. const StringData* docComment) {
  59. m_line1 = line1;
  60. m_line2 = line2;
  61. m_offset = offset;
  62. m_attrs = attrs;
  63. m_parent = parent;
  64. m_docComment = docComment;
  65. if (!SystemLib::s_inited) {
  66. m_attrs = m_attrs | AttrBuiltin;
  67. }
  68. }
  69. PreClassEmitter::~PreClassEmitter() {
  70. for (MethodVec::const_iterator it = m_methods.begin();
  71. it != m_methods.end(); ++it) {
  72. delete *it;
  73. }
  74. }
  75. void PreClassEmitter::addInterface(const StringData* n) {
  76. m_interfaces.push_back(n);
  77. }
  78. bool PreClassEmitter::addMethod(FuncEmitter* method) {
  79. MethodMap::const_iterator it = m_methodMap.find(method->name);
  80. if (it != m_methodMap.end()) {
  81. return false;
  82. }
  83. m_methods.push_back(method);
  84. m_methodMap[method->name] = method;
  85. return true;
  86. }
  87. void PreClassEmitter::renameMethod(const StringData* oldName,
  88. const StringData* newName) {
  89. MethodMap::const_iterator it = m_methodMap.find(oldName);
  90. assert(it != m_methodMap.end());
  91. it->second->name = newName;
  92. m_methodMap[newName] = it->second;
  93. m_methodMap.erase(oldName);
  94. }
  95. bool PreClassEmitter::addProperty(const StringData* n, Attr attrs,
  96. const StringData* typeConstraint,
  97. const StringData* docComment,
  98. const TypedValue* val,
  99. RepoAuthType repoAuthType) {
  100. PropMap::Builder::const_iterator it = m_propMap.find(n);
  101. if (it != m_propMap.end()) {
  102. return false;
  103. }
  104. PreClassEmitter::Prop prop(this, n, attrs, typeConstraint, docComment, val,
  105. repoAuthType);
  106. m_propMap.add(prop.name(), prop);
  107. return true;
  108. }
  109. const PreClassEmitter::Prop&
  110. PreClassEmitter::lookupProp(const StringData* propName) const {
  111. PropMap::Builder::const_iterator it = m_propMap.find(propName);
  112. assert(it != m_propMap.end());
  113. Slot idx = it->second;
  114. return m_propMap[idx];
  115. }
  116. bool PreClassEmitter::addAbstractConstant(const StringData* n,
  117. const StringData* typeConstraint,
  118. const bool typeconst) {
  119. auto it = m_constMap.find(n);
  120. if (it != m_constMap.end()) {
  121. return false;
  122. }
  123. PreClassEmitter::Const cns(n, typeConstraint, nullptr, nullptr, typeconst);
  124. m_constMap.add(cns.name(), cns);
  125. return true;
  126. }
  127. bool PreClassEmitter::addConstant(const StringData* n,
  128. const StringData* typeConstraint,
  129. const TypedValue* val,
  130. const StringData* phpCode,
  131. const bool typeconst,
  132. const ArrayData* typeStructure) {
  133. ConstMap::Builder::const_iterator it = m_constMap.find(n);
  134. if (it != m_constMap.end()) {
  135. return false;
  136. }
  137. TypedValue tvVal;
  138. if (typeconst && typeStructure) {
  139. tvVal = make_tv<KindOfArray>(const_cast<ArrayData*>(typeStructure));
  140. } else {
  141. tvVal = *val;
  142. }
  143. PreClassEmitter::Const cns(n, typeConstraint, &tvVal, phpCode, typeconst);
  144. m_constMap.add(cns.name(), cns);
  145. return true;
  146. }
  147. void PreClassEmitter::addUsedTrait(const StringData* traitName) {
  148. m_usedTraits.push_back(traitName);
  149. }
  150. void PreClassEmitter::addTraitPrecRule(
  151. const PreClass::TraitPrecRule &rule) {
  152. m_traitPrecRules.push_back(rule);
  153. }
  154. void PreClassEmitter::addTraitAliasRule(
  155. const PreClass::TraitAliasRule &rule) {
  156. m_traitAliasRules.push_back(rule);
  157. }
  158. void PreClassEmitter::addUserAttribute(const StringData* name, TypedValue tv) {
  159. m_userAttributes[name] = tv;
  160. }
  161. void PreClassEmitter::commit(RepoTxn& txn) const {
  162. Repo& repo = Repo::get();
  163. PreClassRepoProxy& pcrp = repo.pcrp();
  164. int repoId = m_ue.m_repoId;
  165. int64_t usn = m_ue.m_sn;
  166. pcrp.insertPreClass[repoId]
  167. .insert(*this, txn, usn, m_id, m_name, m_hoistable);
  168. for (MethodVec::const_iterator it = m_methods.begin();
  169. it != m_methods.end(); ++it) {
  170. (*it)->commit(txn);
  171. }
  172. }
  173. void PreClassEmitter::setBuiltinClassInfo(const ClassInfo* info,
  174. BuiltinCtorFunction ctorFunc,
  175. BuiltinDtorFunction dtorFunc,
  176. BuiltinObjExtents extents) {
  177. if (info->getAttribute() & ClassInfo::IsFinal) {
  178. m_attrs = m_attrs | AttrFinal;
  179. }
  180. if (info->getAttribute() & ClassInfo::IsAbstract) {
  181. m_attrs = m_attrs | AttrAbstract;
  182. }
  183. if (info->getAttribute() & ClassInfo::IsTrait) {
  184. m_attrs = m_attrs | AttrTrait;
  185. }
  186. m_attrs = m_attrs | AttrUnique;
  187. m_instanceCtor = ctorFunc;
  188. m_instanceDtor = dtorFunc;
  189. assert(extents.totalSizeBytes <= std::numeric_limits<uint32_t>::max());
  190. assert(extents.odOffsetBytes <= std::numeric_limits<int32_t>::max());
  191. m_builtinObjSize = extents.totalSizeBytes - sizeof(ObjectData);
  192. m_builtinODOffset = extents.odOffsetBytes;
  193. }
  194. const StaticString s_nativedata("__nativedata");
  195. PreClass* PreClassEmitter::create(Unit& unit) const {
  196. Attr attrs = m_attrs;
  197. if (attrs & AttrPersistent &&
  198. !RuntimeOption::RepoAuthoritative && SystemLib::s_inited) {
  199. attrs = Attr(attrs & ~AttrPersistent);
  200. }
  201. auto pc = folly::make_unique<PreClass>(
  202. &unit, m_line1, m_line2, m_offset, m_name,
  203. attrs, m_parent, m_docComment, m_id,
  204. m_hoistable);
  205. pc->m_instanceCtor = m_instanceCtor;
  206. pc->m_instanceDtor = m_instanceDtor;
  207. pc->m_builtinObjSize = m_builtinObjSize;
  208. pc->m_builtinODOffset = m_builtinODOffset;
  209. pc->m_interfaces = m_interfaces;
  210. pc->m_usedTraits = m_usedTraits;
  211. pc->m_requirements = m_requirements;
  212. pc->m_traitPrecRules = m_traitPrecRules;
  213. pc->m_traitAliasRules = m_traitAliasRules;
  214. pc->m_enumBaseTy = m_enumBaseTy;
  215. pc->m_numDeclMethods = m_numDeclMethods;
  216. pc->m_ifaceVtableSlot = m_ifaceVtableSlot;
  217. // Set user attributes.
  218. [&] {
  219. pc->m_userAttributes = m_userAttributes;
  220. pc->m_nativeDataInfo = nullptr;
  221. if (!m_userAttributes.size()) return;
  222. // Check for <<__NativeData("Type")>>.
  223. auto it = m_userAttributes.find(s_nativedata.get());
  224. if (it == m_userAttributes.end()) return;
  225. TypedValue ndiInfo = it->second;
  226. if (ndiInfo.m_type != KindOfArray) return;
  227. // Use the first string label which references a registered type. In
  228. // practice, there should generally only be one item and it should be a
  229. // string, but maybe that'll be extended...
  230. for (ArrayIter it(ndiInfo.m_data.parr); it; ++it) {
  231. Variant val = it.second();
  232. if (!val.isString()) continue;
  233. pc->m_nativeDataInfo = Native::getNativeDataInfo(val.toString().get());
  234. if (pc->m_nativeDataInfo) break;
  235. }
  236. }();
  237. PreClass::MethodMap::Builder methodBuild;
  238. for (MethodVec::const_iterator it = m_methods.begin();
  239. it != m_methods.end(); ++it) {
  240. Func* f = (*it)->create(unit, pc.get());
  241. methodBuild.add(f->name(), f);
  242. }
  243. pc->m_methods.create(methodBuild);
  244. PreClass::PropMap::Builder propBuild;
  245. for (unsigned i = 0; i < m_propMap.size(); ++i) {
  246. const Prop& prop = m_propMap[i];
  247. propBuild.add(prop.name(), PreClass::Prop(pc.get(),
  248. prop.name(),
  249. prop.attrs(),
  250. prop.typeConstraint(),
  251. prop.docComment(),
  252. prop.val(),
  253. prop.repoAuthType()));
  254. }
  255. pc->m_properties.create(propBuild);
  256. PreClass::ConstMap::Builder constBuild;
  257. for (unsigned i = 0; i < m_constMap.size(); ++i) {
  258. const Const& const_ = m_constMap[i];
  259. TypedValueAux tvaux;
  260. if (const_.isAbstract()) {
  261. tvWriteUninit(&tvaux);
  262. tvaux.constModifiers().m_isAbstract = true;
  263. } else {
  264. tvCopy(const_.val(), tvaux);
  265. tvaux.constModifiers().m_isAbstract = false;
  266. }
  267. tvaux.constModifiers().m_isType = const_.isTypeconst();
  268. constBuild.add(const_.name(), PreClass::Const(const_.name(),
  269. tvaux,
  270. const_.phpCode()));
  271. }
  272. if (auto nativeConsts = Native::getClassConstants(m_name)) {
  273. for (auto cnsMap : *nativeConsts) {
  274. TypedValueAux tvaux;
  275. tvCopy(cnsMap.second, tvaux);
  276. tvaux.constModifiers() = { false, false };
  277. constBuild.add(cnsMap.first, PreClass::Const(cnsMap.first,
  278. tvaux,
  279. staticEmptyString()));
  280. }
  281. }
  282. pc->m_constants.create(constBuild);
  283. return pc.release();
  284. }
  285. template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
  286. // NOTE: name, hoistable, and a few other fields currently
  287. // serialized outside of this.
  288. sd(m_line1)
  289. (m_line2)
  290. (m_offset)
  291. (m_attrs)
  292. (m_parent)
  293. (m_docComment)
  294. (m_numDeclMethods)
  295. (m_ifaceVtableSlot)
  296. (m_interfaces)
  297. (m_usedTraits)
  298. (m_requirements)
  299. (m_traitPrecRules)
  300. (m_traitAliasRules)
  301. (m_userAttributes)
  302. (m_propMap)
  303. (m_constMap)
  304. (m_enumBaseTy)
  305. ;
  306. }
  307. //=============================================================================
  308. // PreClassRepoProxy.
  309. PreClassRepoProxy::PreClassRepoProxy(Repo& repo)
  310. : RepoProxy(repo),
  311. insertPreClass{InsertPreClassStmt(repo, 0), InsertPreClassStmt(repo, 1)},
  312. getPreClasses{GetPreClassesStmt(repo, 0), GetPreClassesStmt(repo, 1)}
  313. {}
  314. PreClassRepoProxy::~PreClassRepoProxy() {
  315. }
  316. void PreClassRepoProxy::createSchema(int repoId, RepoTxn& txn) {
  317. {
  318. std::stringstream ssCreate;
  319. ssCreate << "CREATE TABLE " << m_repo.table(repoId, "PreClass")
  320. << "(unitSn INTEGER, preClassId INTEGER, name TEXT,"
  321. " hoistable INTEGER, extraData BLOB,"
  322. " PRIMARY KEY (unitSn, preClassId));";
  323. txn.exec(ssCreate.str());
  324. }
  325. }
  326. void PreClassRepoProxy::InsertPreClassStmt
  327. ::insert(const PreClassEmitter& pce, RepoTxn& txn,
  328. int64_t unitSn, Id preClassId,
  329. const StringData* name,
  330. PreClass::Hoistable hoistable) {
  331. if (!prepared()) {
  332. std::stringstream ssInsert;
  333. ssInsert << "INSERT INTO " << m_repo.table(m_repoId, "PreClass")
  334. << " VALUES(@unitSn, @preClassId, @name, @hoistable, "
  335. "@extraData);";
  336. txn.prepare(*this, ssInsert.str());
  337. }
  338. BlobEncoder extraBlob;
  339. RepoTxnQuery query(txn, *this);
  340. query.bindInt64("@unitSn", unitSn);
  341. query.bindId("@preClassId", preClassId);
  342. query.bindStaticString("@name", name);
  343. query.bindInt("@hoistable", hoistable);
  344. const_cast<PreClassEmitter&>(pce).serdeMetaData(extraBlob);
  345. query.bindBlob("@extraData", extraBlob, /* static */ true);
  346. query.exec();
  347. }
  348. void PreClassRepoProxy::GetPreClassesStmt
  349. ::get(UnitEmitter& ue) {
  350. RepoTxn txn(m_repo);
  351. if (!prepared()) {
  352. std::stringstream ssSelect;
  353. ssSelect << "SELECT preClassId,name,hoistable,extraData FROM "
  354. << m_repo.table(m_repoId, "PreClass")
  355. << " WHERE unitSn == @unitSn ORDER BY preClassId ASC;";
  356. txn.prepare(*this, ssSelect.str());
  357. }
  358. RepoTxnQuery query(txn, *this);
  359. query.bindInt64("@unitSn", ue.m_sn);
  360. do {
  361. query.step();
  362. if (query.row()) {
  363. Id preClassId; /**/ query.getId(0, preClassId);
  364. StringData* name; /**/ query.getStaticString(1, name);
  365. int hoistable; /**/ query.getInt(2, hoistable);
  366. BlobDecoder extraBlob = /**/ query.getBlob(3);
  367. PreClassEmitter* pce = ue.newPreClassEmitter(
  368. name, (PreClass::Hoistable)hoistable);
  369. pce->serdeMetaData(extraBlob);
  370. if (!SystemLib::s_inited) {
  371. assert(pce->attrs() & AttrPersistent);
  372. assert(pce->attrs() & AttrUnique);
  373. }
  374. assert(pce->id() == preClassId);
  375. }
  376. } while (!query.done());
  377. txn.commit();
  378. }
  379. } // HPHP