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/runtime/base/array-iterator.h"
23 #include "hphp/runtime/base/coeffects-config.h"
24 #include "hphp/runtime/base/runtime-option.h"
25 #include "hphp/runtime/vm/repo-autoload-map-builder.h"
26 #include "hphp/runtime/vm/native.h"
27 #include "hphp/runtime/vm/native-data.h"
29 #include "hphp/util/blob-encoder.h"
33 //=============================================================================
34 // PreClassEmitter::Prop.
36 PreClassEmitter::Prop::Prop(const PreClassEmitter
* pce
,
39 const StringData
* userType
,
40 const TypeConstraint
& typeConstraint
,
41 const UpperBoundVec
& ubs
,
42 const StringData
* docComment
,
43 const TypedValue
* val
,
44 RepoAuthType repoAuthType
,
45 UserAttributeMap userAttributes
)
48 , m_userType(userType
)
49 , m_docComment(docComment
)
50 , m_repoAuthType(repoAuthType
)
51 , m_typeConstraint(typeConstraint
)
53 , m_userAttributes(userAttributes
)
55 memcpy(&m_val
, val
, sizeof(TypedValue
));
58 PreClassEmitter::Prop::~Prop() {
61 //=============================================================================
64 PreClassEmitter::PreClassEmitter(UnitEmitter
& ue
,
68 , m_name(makeStaticString(n
))
71 void PreClassEmitter::init(int line1
, int line2
, Attr attrs
,
72 const StringData
* parent
,
73 const StringData
* docComment
) {
78 m_docComment
= docComment
;
79 if (!SystemLib::s_inited
) {
80 m_attrs
= m_attrs
| AttrBuiltin
;
84 PreClassEmitter::~PreClassEmitter() {
85 for (MethodVec::const_iterator it
= m_methods
.begin();
86 it
!= m_methods
.end(); ++it
) {
91 void PreClassEmitter::addInterface(const StringData
* n
) {
92 m_interfaces
.push_back(n
);
95 void PreClassEmitter::addEnumInclude(const StringData
* n
) {
96 m_enumIncludes
.push_back(n
);
99 bool PreClassEmitter::addMethod(FuncEmitter
* method
) {
100 MethodMap::const_iterator it
= m_methodMap
.find(method
->name
);
101 if (it
!= m_methodMap
.end()) {
104 m_methods
.push_back(method
);
105 m_methodMap
[method
->name
] = method
;
109 void PreClassEmitter::renameMethod(const StringData
* oldName
,
110 const StringData
* newName
) {
111 assertx(m_methodMap
.count(oldName
));
112 auto it
= m_methodMap
.find(oldName
);
113 auto fe
= it
->second
;
114 m_methodMap
.erase(it
);
116 m_methodMap
[newName
] = fe
;
119 bool PreClassEmitter::addProperty(const StringData
* n
, Attr attrs
,
120 const StringData
* userType
,
121 const TypeConstraint
& typeConstraint
,
122 const UpperBoundVec
& ubs
,
123 const StringData
* docComment
,
124 const TypedValue
* val
,
125 RepoAuthType repoAuthType
,
126 UserAttributeMap userAttributes
) {
127 assertx(typeConstraint
.validForProp());
128 PropMap::Builder::const_iterator it
= m_propMap
.find(n
);
129 if (it
!= m_propMap
.end()) {
132 PreClassEmitter::Prop prop
{
144 m_propMap
.add(prop
.name(), prop
);
148 bool PreClassEmitter::addAbstractConstant(const StringData
* n
,
149 ConstModifiers::Kind kind
,
151 assertx(kind
== ConstModifiers::Kind::Value
||
152 kind
== ConstModifiers::Kind::Type
);
154 auto it
= m_constMap
.find(n
);
155 if (it
!= m_constMap
.end()) {
158 PreClassEmitter::Const
cns(n
, nullptr, nullptr,
160 Const::Invariance::None
,
162 m_constMap
.add(cns
.name(), cns
);
166 bool PreClassEmitter::addContextConstant(
168 PreClassEmitter::Const::CoeffectsVec coeffects
,
171 auto it
= m_constMap
.find(n
);
172 if (it
!= m_constMap
.end()) {
175 PreClassEmitter::Const
cns(n
, nullptr, nullptr,
176 std::move(coeffects
),
178 ConstModifiers::Kind::Context
,
179 Const::Invariance::None
,
180 isAbstract
, fromTrait
);
181 m_constMap
.add(cns
.name(), cns
);
185 bool PreClassEmitter::addConstant(const StringData
* n
,
186 const StringData
* cls
,
187 const TypedValue
* val
,
188 Array resolvedTypeStructure
,
189 ConstModifiers::Kind kind
,
190 Const::Invariance invariance
,
193 assertx(kind
== ConstModifiers::Kind::Value
||
194 kind
== ConstModifiers::Kind::Type
);
195 assertx(IMPLIES(kind
== ConstModifiers::Kind::Value
, !cls
));
196 assertx(IMPLIES(kind
== ConstModifiers::Kind::Value
,
197 resolvedTypeStructure
.isNull()));
198 assertx(IMPLIES(!resolvedTypeStructure
.isNull(),
199 resolvedTypeStructure
.isDict() &&
200 !resolvedTypeStructure
.empty() &&
201 resolvedTypeStructure
->isStatic()));
202 assertx(IMPLIES(invariance
!= Const::Invariance::None
,
203 !resolvedTypeStructure
.isNull()));
206 ConstMap::Builder::const_iterator it
= m_constMap
.find(n
);
207 if (it
!= m_constMap
.end()) {
210 PreClassEmitter::Const
cns(n
, cls
, val
, {}, std::move(resolvedTypeStructure
),
211 kind
, invariance
, isAbstract
, fromTrait
);
212 m_constMap
.add(cns
.name(), cns
);
216 void PreClassEmitter::addUsedTrait(const StringData
* traitName
) {
217 m_usedTraits
.push_back(traitName
);
220 void PreClassEmitter::addTraitPrecRule(
221 const PreClass::TraitPrecRule
&rule
) {
222 m_traitPrecRules
.push_back(rule
);
225 void PreClassEmitter::addTraitAliasRule(
226 const PreClass::TraitAliasRule
&rule
) {
227 m_traitAliasRules
.push_back(rule
);
231 s_nativedata("__nativedata"),
232 s_DynamicallyConstructible("__DynamicallyConstructible"),
233 s_invoke("__invoke"),
234 s_coeffectsProp("86coeffects");
236 PreClass
* PreClassEmitter::create(Unit
& unit
) const {
237 Attr attrs
= m_attrs
;
238 if (attrs
& AttrPersistent
&&
239 !RuntimeOption::RepoAuthoritative
&& SystemLib::s_inited
) {
240 attrs
= Attr(attrs
& ~AttrPersistent
);
243 auto const dynConstructSampleRate
= [&] () -> int64_t {
244 if (!(attrs
& AttrDynamicallyConstructible
)) return -1;
246 auto const it
= m_userAttributes
.find(s_DynamicallyConstructible
.get());
247 if (it
== m_userAttributes
.end()) return -1;
249 assertx(isArrayLikeType(type(it
->second
)));
250 auto const rate
= val(it
->second
).parr
->get(int64_t(0));
251 if (!isIntType(type(rate
)) || val(rate
).num
< 0) return -1;
253 attrs
= Attr(attrs
& ~AttrDynamicallyConstructible
);
254 return val(rate
).num
;
257 auto const invoke
= lookupMethod(s_invoke
.get());
258 if (invoke
&& invoke
->isClosureBody
) {
259 attrs
|= AttrIsClosureClass
;
260 if (!invoke
->coeffectRules
.empty()) {
261 assertx(invoke
->coeffectRules
.size() == 1);
262 if (invoke
->coeffectRules
[0].isClosureParentScope()) {
263 attrs
|= AttrHasClosureCoeffectsProp
;
265 assertx(invoke
->coeffectRules
[0].isCaller());
270 assertx(attrs
& AttrPersistent
|| SystemLib::s_inited
);
272 auto pc
= std::make_unique
<PreClass
>(
273 &unit
, m_line1
, m_line2
, m_name
,
274 attrs
, m_parent
, m_docComment
, m_id
);
275 pc
->m_interfaces
= m_interfaces
;
276 pc
->m_includedEnums
= m_enumIncludes
;
277 pc
->m_usedTraits
= m_usedTraits
;
278 pc
->m_requirements
= m_requirements
;
279 pc
->m_traitPrecRules
= m_traitPrecRules
;
280 pc
->m_traitAliasRules
= m_traitAliasRules
;
281 pc
->m_enumBaseTy
= m_enumBaseTy
;
282 pc
->m_numDeclMethods
= -1;
283 pc
->m_ifaceVtableSlot
= m_ifaceVtableSlot
;
284 pc
->m_dynConstructSampleRate
= dynConstructSampleRate
;
286 // Set user attributes.
288 pc
->m_userAttributes
= m_userAttributes
;
289 pc
->m_nativeDataInfo
= nullptr;
290 if (!m_userAttributes
.size()) return;
292 // Check for <<__NativeData("Type")>>.
293 auto it
= m_userAttributes
.find(s_nativedata
.get());
294 if (it
== m_userAttributes
.end()) return;
296 TypedValue ndiInfo
= it
->second
;
297 if (!isArrayLikeType(ndiInfo
.m_type
)) return;
299 // Use the first string label which references a registered type. In
300 // practice, there should generally only be one item and it should be a
301 // string, but maybe that'll be extended...
302 for (ArrayIter
it(ndiInfo
.m_data
.parr
); it
; ++it
) {
303 Variant val
= it
.second();
304 if (!val
.isString()) continue;
306 pc
->m_nativeDataInfo
= Native::getNativeDataInfo(val
.toString().get());
307 if (pc
->m_nativeDataInfo
) break;
311 PreClass::MethodMap::Builder methodBuild
;
312 for (MethodVec::const_iterator it
= m_methods
.begin();
313 it
!= m_methods
.end(); ++it
) {
314 Func
* f
= (*it
)->create(unit
, pc
.get());
315 if (f
->attrs() & AttrTrait
) {
316 if (pc
->m_numDeclMethods
== -1) {
317 pc
->m_numDeclMethods
= it
- m_methods
.begin();
319 } else if (!f
->isGenerated()) {
320 assertx(pc
->m_numDeclMethods
== -1);
322 methodBuild
.add(f
->name(), f
);
324 pc
->m_methods
.create(methodBuild
);
326 PreClass::PropMap::Builder propBuild
;
327 if (pc
->attrs() & AttrHasClosureCoeffectsProp
) {
329 tvWriteUninit(tvInit
);
331 propBuild
.add(s_coeffectsProp
.get(), PreClass::Prop(pc
.get(),
332 s_coeffectsProp
.get(),
333 AttrPrivate
|AttrSystemInitialValue
,
336 CompactVector
<TypeConstraint
>{},
343 for (unsigned i
= 0; i
< m_propMap
.size(); ++i
) {
344 const Prop
& prop
= m_propMap
[i
];
345 propBuild
.add(prop
.name(), PreClass::Prop(pc
.get(),
349 prop
.typeConstraint(),
354 prop
.userAttributes()));
356 pc
->m_properties
.create(propBuild
);
358 PreClass::ConstMap::Builder constBuild
;
359 for (unsigned i
= 0; i
< m_constMap
.size(); ++i
) {
360 const Const
& const_
= m_constMap
[i
];
362 tvaux
.constModifiers() = {};
363 tvaux
.constModifiers().setIsAbstract(const_
.isAbstract());
364 if (const_
.kind() == ConstModifiers::Kind::Context
) {
365 auto const coeffects
=
366 getCoeffectsInfoFromList(const_
.coeffects(), false).first
;
367 tvaux
.constModifiers().setCoeffects(coeffects
);
368 if (!const_
.coeffects().empty()) {
369 tvCopy(make_tv
<KindOfInt64
>(0), tvaux
); // dummy value for m_data
371 tvWriteConstValMissing(tvaux
);
374 if (const_
.valOption()) {
375 tvCopy(const_
.val(), tvaux
);
377 tvWriteConstValMissing(tvaux
);
381 tvaux
.constModifiers().setKind(const_
.kind());
384 IMPLIES(const_
.kind() != ConstModifiers::Kind::Type
, !const_
.cls())
387 IMPLIES(const_
.kind() != ConstModifiers::Kind::Type
,
388 const_
.resolvedTypeStructure().isNull())
391 IMPLIES(!const_
.resolvedTypeStructure().isNull(),
392 const_
.resolvedTypeStructure().isDict() &&
393 !const_
.resolvedTypeStructure().empty())
396 IMPLIES(const_
.invariance() != Const::Invariance::None
,
397 !const_
.resolvedTypeStructure().isNull())
406 const_
.resolvedTypeStructure(),
412 if (auto nativeConsts
= Native::getClassConstants(m_name
)) {
413 for (auto cnsMap
: *nativeConsts
) {
415 tvCopy(cnsMap
.second
, tvaux
);
416 tvaux
.constModifiers() = {};
417 constBuild
.add(cnsMap
.first
, PreClass::Const(cnsMap
.first
,
421 Const::Invariance::None
,
426 pc
->m_constants
.create(constBuild
);
430 template<class SerDe
> void PreClassEmitter::serdeMetaData(SerDe
& sd
) {
431 // NOTE: name and a few other fields currently
432 // serialized outside of this.
447 (m_propMap
, [](Prop p
) { return p
.name(); })
448 (m_constMap
, [](Const c
) { return c
.name(); })
453 template void PreClassEmitter::serdeMetaData
<>(BlobDecoder
&);
454 template void PreClassEmitter::serdeMetaData
<>(BlobEncoder
&);