2 +----------------------------------------------------------------------+
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"
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"
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
,
53 const StringData
* typeConstraint
,
54 const StringData
* docComment
,
55 const TypedValue
* val
,
56 RepoAuthType repoAuthType
)
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 //=============================================================================
73 extern const StaticString s_Closure
;
75 PreClassEmitter::PreClassEmitter(UnitEmitter
& ue
,
78 PreClass::Hoistable hoistable
)
80 , m_name(preClassName(n
))
82 , m_hoistable(hoistable
) {
83 if (m_name
->isame(s_Closure
.get())) {
88 void PreClassEmitter::init(int line1
, int line2
, Offset offset
, Attr attrs
,
89 const StringData
* parent
,
90 const StringData
* docComment
) {
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
) {
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()) {
118 m_methods
.push_back(method
);
119 m_methodMap
[method
->name
] = method
;
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()) {
141 PreClassEmitter::Prop
prop(this, n
, attrs
, typeConstraint
, docComment
, val
,
143 m_propMap
.add(prop
.name(), prop
);
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()) {
162 PreClassEmitter::Const
cns(n
, typeConstraint
, nullptr, nullptr, typeconst
);
163 m_constMap
.add(cns
.name(), cns
);
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()) {
178 if (typeconst
&& !typeStructure
.empty()) {
179 tvVal
= make_tv
<KindOfPersistentArray
>(typeStructure
.get());
180 assert(tvIsPlausible(tvVal
));
184 PreClassEmitter::Const
cns(n
, typeConstraint
, &tvVal
, phpCode
, typeconst
);
185 m_constMap
.add(cns
.name(), cns
);
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
) {
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
,
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.
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;
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(),
284 prop
.typeConstraint(),
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
];
295 if (const_
.isAbstract()) {
296 tvWriteUninit(&tvaux
);
297 tvaux
.constModifiers().m_isAbstract
= true;
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(),
309 if (auto nativeConsts
= Native::getClassConstants(m_name
)) {
310 for (auto cnsMap
: *nativeConsts
) {
312 tvCopy(cnsMap
.second
, tvaux
);
313 tvaux
.constModifiers() = { false, false };
314 constBuild
.add(cnsMap
.first
, PreClass::Const(cnsMap
.first
,
316 staticEmptyString()));
320 pc
->m_constants
.create(constBuild
);
324 template<class SerDe
> void PreClassEmitter::serdeMetaData(SerDe
& sd
) {
325 // NOTE: name, hoistable, and a few other fields currently
326 // serialized outside of this.
348 //=============================================================================
349 // PreClassRepoProxy.
351 PreClassRepoProxy::PreClassRepoProxy(Repo
& 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
) {
377 std::stringstream ssInsert
;
378 ssInsert
<< "INSERT INTO " << m_repo
.table(m_repoId
, "PreClass")
379 << " VALUES(@unitSn, @preClassId, @name, @hoistable, "
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);
400 void PreClassRepoProxy::GetPreClassesStmt
401 ::get(UnitEmitter
& ue
) {
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
);
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());