codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / vm / preclass-emitter.cpp
bloba2110f470891d02a7eff4e25994a59d1cc8980bd
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/vm/preclass-emitter.h"
18 #include <limits>
20 #include <folly/Memory.h>
22 #include "hphp/parser/parser.h"
24 #include "hphp/runtime/base/array-iterator.h"
25 #include "hphp/runtime/vm/repo.h"
26 #include "hphp/runtime/vm/blob-helper.h"
27 #include "hphp/runtime/vm/native.h"
28 #include "hphp/runtime/vm/native-data.h"
30 namespace HPHP {
32 namespace {
34 const StringData* preClassName(const std::string& name) {
35 static std::atomic<uint32_t> next_anon_class;
36 if (ParserBase::IsAnonymousClassName(name)) {
37 if (name.find(';') == std::string::npos) {
38 return makeStaticString(
39 folly::sformat("{};{}", name, next_anon_class.fetch_add(1)));
42 return makeStaticString(name);
47 //=============================================================================
48 // PreClassEmitter::Prop.
50 PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
51 const StringData* n,
52 Attr attrs,
53 const StringData* typeConstraint,
54 const StringData* docComment,
55 const TypedValue* val,
56 RepoAuthType repoAuthType)
57 : m_name(n)
58 , m_attrs(attrs)
59 , m_typeConstraint(typeConstraint)
60 , m_docComment(docComment)
61 , m_repoAuthType(repoAuthType)
63 m_mangledName = PreClass::manglePropName(pce->name(), n, attrs);
64 memcpy(&m_val, val, sizeof(TypedValue));
67 PreClassEmitter::Prop::~Prop() {
70 //=============================================================================
71 // PreClassEmitter.
73 extern const StaticString s_Closure;
75 PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
76 Id id,
77 const std::string& n,
78 PreClass::Hoistable hoistable)
79 : m_ue(ue)
80 , m_name(preClassName(n))
81 , m_id(id)
82 , m_hoistable(hoistable) {
83 if (m_name->isame(s_Closure.get())) {
84 setClosurePreClass();
88 void PreClassEmitter::init(int line1, int line2, Offset offset, Attr attrs,
89 const StringData* parent,
90 const StringData* docComment) {
91 m_line1 = line1;
92 m_line2 = line2;
93 m_offset = offset;
94 m_attrs = attrs;
95 m_parent = parent;
96 m_docComment = docComment;
97 if (!SystemLib::s_inited) {
98 m_attrs = m_attrs | AttrBuiltin;
102 PreClassEmitter::~PreClassEmitter() {
103 for (MethodVec::const_iterator it = m_methods.begin();
104 it != m_methods.end(); ++it) {
105 delete *it;
109 void PreClassEmitter::addInterface(const StringData* n) {
110 m_interfaces.push_back(n);
113 bool PreClassEmitter::addMethod(FuncEmitter* method) {
114 MethodMap::const_iterator it = m_methodMap.find(method->name);
115 if (it != m_methodMap.end()) {
116 return false;
118 m_methods.push_back(method);
119 m_methodMap[method->name] = method;
120 return true;
123 void PreClassEmitter::renameMethod(const StringData* oldName,
124 const StringData* newName) {
125 MethodMap::const_iterator it = m_methodMap.find(oldName);
126 assert(it != m_methodMap.end());
127 it->second->name = newName;
128 m_methodMap[newName] = it->second;
129 m_methodMap.erase(oldName);
132 bool PreClassEmitter::addProperty(const StringData* n, Attr attrs,
133 const StringData* typeConstraint,
134 const StringData* docComment,
135 const TypedValue* val,
136 RepoAuthType repoAuthType) {
137 PropMap::Builder::const_iterator it = m_propMap.find(n);
138 if (it != m_propMap.end()) {
139 return false;
141 PreClassEmitter::Prop prop(this, n, attrs, typeConstraint, docComment, val,
142 repoAuthType);
143 m_propMap.add(prop.name(), prop);
144 return true;
147 const PreClassEmitter::Prop&
148 PreClassEmitter::lookupProp(const StringData* propName) const {
149 PropMap::Builder::const_iterator it = m_propMap.find(propName);
150 assert(it != m_propMap.end());
151 Slot idx = it->second;
152 return m_propMap[idx];
155 bool PreClassEmitter::addAbstractConstant(const StringData* n,
156 const StringData* typeConstraint,
157 const bool typeconst) {
158 auto it = m_constMap.find(n);
159 if (it != m_constMap.end()) {
160 return false;
162 PreClassEmitter::Const cns(n, typeConstraint, nullptr, nullptr, typeconst);
163 m_constMap.add(cns.name(), cns);
164 return true;
167 bool PreClassEmitter::addConstant(const StringData* n,
168 const StringData* typeConstraint,
169 const TypedValue* val,
170 const StringData* phpCode,
171 const bool typeconst,
172 const Array& typeStructure) {
173 ConstMap::Builder::const_iterator it = m_constMap.find(n);
174 if (it != m_constMap.end()) {
175 return false;
177 TypedValue tvVal;
178 if (typeconst && !typeStructure.empty()) {
179 tvVal = make_tv<KindOfPersistentArray>(typeStructure.get());
180 assert(tvIsPlausible(tvVal));
181 } else {
182 tvVal = *val;
184 PreClassEmitter::Const cns(n, typeConstraint, &tvVal, phpCode, typeconst);
185 m_constMap.add(cns.name(), cns);
186 return true;
189 void PreClassEmitter::addUsedTrait(const StringData* traitName) {
190 m_usedTraits.push_back(traitName);
193 void PreClassEmitter::addTraitPrecRule(
194 const PreClass::TraitPrecRule &rule) {
195 m_traitPrecRules.push_back(rule);
198 void PreClassEmitter::addTraitAliasRule(
199 const PreClass::TraitAliasRule &rule) {
200 m_traitAliasRules.push_back(rule);
203 void PreClassEmitter::addUserAttribute(const StringData* name, TypedValue tv) {
204 m_userAttributes[name] = tv;
207 void PreClassEmitter::commit(RepoTxn& txn) const {
208 Repo& repo = Repo::get();
209 PreClassRepoProxy& pcrp = repo.pcrp();
210 int repoId = m_ue.m_repoId;
211 int64_t usn = m_ue.m_sn;
212 pcrp.insertPreClass[repoId]
213 .insert(*this, txn, usn, m_id, m_name, m_hoistable);
215 for (MethodVec::const_iterator it = m_methods.begin();
216 it != m_methods.end(); ++it) {
217 (*it)->commit(txn);
221 const StaticString s_nativedata("__nativedata");
223 PreClass* PreClassEmitter::create(Unit& unit) const {
224 Attr attrs = m_attrs;
225 if (attrs & AttrPersistent &&
226 !RuntimeOption::RepoAuthoritative && SystemLib::s_inited) {
227 attrs = Attr(attrs & ~AttrPersistent);
230 auto pc = folly::make_unique<PreClass>(
231 &unit, m_line1, m_line2, m_offset, m_name,
232 attrs, m_parent, m_docComment, m_id,
233 m_hoistable);
234 pc->m_instanceCtor = m_instanceCtor;
235 pc->m_instanceDtor = m_instanceDtor;
236 pc->m_interfaces = m_interfaces;
237 pc->m_usedTraits = m_usedTraits;
238 pc->m_requirements = m_requirements;
239 pc->m_traitPrecRules = m_traitPrecRules;
240 pc->m_traitAliasRules = m_traitAliasRules;
241 pc->m_enumBaseTy = m_enumBaseTy;
242 pc->m_numDeclMethods = m_numDeclMethods;
243 pc->m_ifaceVtableSlot = m_ifaceVtableSlot;
245 // Set user attributes.
246 [&] {
247 pc->m_userAttributes = m_userAttributes;
248 pc->m_nativeDataInfo = nullptr;
249 if (!m_userAttributes.size()) return;
251 // Check for <<__NativeData("Type")>>.
252 auto it = m_userAttributes.find(s_nativedata.get());
253 if (it == m_userAttributes.end()) return;
255 TypedValue ndiInfo = it->second;
256 if (!isArrayType(ndiInfo.m_type)) return;
258 // Use the first string label which references a registered type. In
259 // practice, there should generally only be one item and it should be a
260 // string, but maybe that'll be extended...
261 for (ArrayIter it(ndiInfo.m_data.parr); it; ++it) {
262 Variant val = it.second();
263 if (!val.isString()) continue;
265 pc->m_nativeDataInfo = Native::getNativeDataInfo(val.toString().get());
266 if (pc->m_nativeDataInfo) break;
268 }();
270 PreClass::MethodMap::Builder methodBuild;
271 for (MethodVec::const_iterator it = m_methods.begin();
272 it != m_methods.end(); ++it) {
273 Func* f = (*it)->create(unit, pc.get());
274 methodBuild.add(f->name(), f);
276 pc->m_methods.create(methodBuild);
278 PreClass::PropMap::Builder propBuild;
279 for (unsigned i = 0; i < m_propMap.size(); ++i) {
280 const Prop& prop = m_propMap[i];
281 propBuild.add(prop.name(), PreClass::Prop(pc.get(),
282 prop.name(),
283 prop.attrs(),
284 prop.typeConstraint(),
285 prop.docComment(),
286 prop.val(),
287 prop.repoAuthType()));
289 pc->m_properties.create(propBuild);
291 PreClass::ConstMap::Builder constBuild;
292 for (unsigned i = 0; i < m_constMap.size(); ++i) {
293 const Const& const_ = m_constMap[i];
294 TypedValueAux tvaux;
295 if (const_.isAbstract()) {
296 tvWriteUninit(&tvaux);
297 tvaux.constModifiers().m_isAbstract = true;
298 } else {
299 tvCopy(const_.val(), tvaux);
300 tvaux.constModifiers().m_isAbstract = false;
303 tvaux.constModifiers().m_isType = const_.isTypeconst();
305 constBuild.add(const_.name(), PreClass::Const(const_.name(),
306 tvaux,
307 const_.phpCode()));
309 if (auto nativeConsts = Native::getClassConstants(m_name)) {
310 for (auto cnsMap : *nativeConsts) {
311 TypedValueAux tvaux;
312 tvCopy(cnsMap.second, tvaux);
313 tvaux.constModifiers() = { false, false };
314 constBuild.add(cnsMap.first, PreClass::Const(cnsMap.first,
315 tvaux,
316 staticEmptyString()));
320 pc->m_constants.create(constBuild);
321 return pc.release();
324 template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
325 // NOTE: name, hoistable, and a few other fields currently
326 // serialized outside of this.
327 sd(m_line1)
328 (m_line2)
329 (m_offset)
330 (m_attrs)
331 (m_parent)
332 (m_docComment)
333 (m_numDeclMethods)
334 (m_ifaceVtableSlot)
336 (m_interfaces)
337 (m_usedTraits)
338 (m_requirements)
339 (m_traitPrecRules)
340 (m_traitAliasRules)
341 (m_userAttributes)
342 (m_propMap)
343 (m_constMap)
344 (m_enumBaseTy)
348 //=============================================================================
349 // PreClassRepoProxy.
351 PreClassRepoProxy::PreClassRepoProxy(Repo& repo)
352 : RepoProxy(repo),
353 insertPreClass{InsertPreClassStmt(repo, 0), InsertPreClassStmt(repo, 1)},
354 getPreClasses{GetPreClassesStmt(repo, 0), GetPreClassesStmt(repo, 1)}
357 PreClassRepoProxy::~PreClassRepoProxy() {
360 void PreClassRepoProxy::createSchema(int repoId, RepoTxn& txn) {
362 std::stringstream ssCreate;
363 ssCreate << "CREATE TABLE " << m_repo.table(repoId, "PreClass")
364 << "(unitSn INTEGER, preClassId INTEGER, name TEXT,"
365 " hoistable INTEGER, extraData BLOB,"
366 " PRIMARY KEY (unitSn, preClassId));";
367 txn.exec(ssCreate.str());
371 void PreClassRepoProxy::InsertPreClassStmt
372 ::insert(const PreClassEmitter& pce, RepoTxn& txn,
373 int64_t unitSn, Id preClassId,
374 const StringData* name,
375 PreClass::Hoistable hoistable) {
376 if (!prepared()) {
377 std::stringstream ssInsert;
378 ssInsert << "INSERT INTO " << m_repo.table(m_repoId, "PreClass")
379 << " VALUES(@unitSn, @preClassId, @name, @hoistable, "
380 "@extraData);";
381 txn.prepare(*this, ssInsert.str());
384 auto n = name->slice();
385 auto const pos = RuntimeOption::RepoAuthoritative ?
386 std::string::npos : qfind(n, ';');
387 auto const nm = pos == std::string::npos ?
388 n : folly::StringPiece{n.data(), pos};
389 BlobEncoder extraBlob;
390 RepoTxnQuery query(txn, *this);
391 query.bindInt64("@unitSn", unitSn);
392 query.bindId("@preClassId", preClassId);
393 query.bindStringPiece("@name", nm);
394 query.bindInt("@hoistable", hoistable);
395 const_cast<PreClassEmitter&>(pce).serdeMetaData(extraBlob);
396 query.bindBlob("@extraData", extraBlob, /* static */ true);
397 query.exec();
400 void PreClassRepoProxy::GetPreClassesStmt
401 ::get(UnitEmitter& ue) {
402 RepoTxn txn(m_repo);
403 if (!prepared()) {
404 std::stringstream ssSelect;
405 ssSelect << "SELECT preClassId,name,hoistable,extraData FROM "
406 << m_repo.table(m_repoId, "PreClass")
407 << " WHERE unitSn == @unitSn ORDER BY preClassId ASC;";
408 txn.prepare(*this, ssSelect.str());
410 RepoTxnQuery query(txn, *this);
411 query.bindInt64("@unitSn", ue.m_sn);
412 do {
413 query.step();
414 if (query.row()) {
415 Id preClassId; /**/ query.getId(0, preClassId);
416 std::string name; /**/ query.getStdString(1, name);
417 int hoistable; /**/ query.getInt(2, hoistable);
418 BlobDecoder extraBlob = /**/ query.getBlob(3);
419 PreClassEmitter* pce = ue.newPreClassEmitter(
420 name, (PreClass::Hoistable)hoistable);
421 pce->serdeMetaData(extraBlob);
422 if (!SystemLib::s_inited) {
423 assert(pce->attrs() & AttrPersistent);
424 assert(pce->attrs() & AttrUnique);
426 assert(pce->id() == preClassId);
428 } while (!query.done());
429 txn.commit();
432 } // HPHP