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 const StaticString
s_SoftInternal("__SoftInternal");
35 //=============================================================================
36 // PreClassEmitter::Prop.
38 PreClassEmitter::Prop::Prop(const PreClassEmitter
* pce
,
41 const StringData
* userType
,
42 const TypeConstraint
& typeConstraint
,
43 const UpperBoundVec
& ubs
,
44 const StringData
* docComment
,
45 const TypedValue
* val
,
46 RepoAuthType repoAuthType
,
47 UserAttributeMap userAttributes
)
50 , m_userType(userType
)
51 , m_docComment(docComment
)
52 , m_repoAuthType(repoAuthType
)
53 , m_typeConstraint(typeConstraint
)
55 , m_userAttributes(userAttributes
)
57 memcpy(&m_val
, val
, sizeof(TypedValue
));
58 if (m_attrs
& AttrInternal
&&
59 m_userAttributes
.find(s_SoftInternal
.get()) != m_userAttributes
.end()) {
60 m_attrs
|= AttrInternalSoft
;
64 PreClassEmitter::Prop::~Prop() {
67 //=============================================================================
70 PreClassEmitter::PreClassEmitter(UnitEmitter
& ue
,
73 , m_name(makeStaticString(n
)) {}
75 void PreClassEmitter::init(int line1
, int line2
, Attr attrs
,
76 const StringData
* parent
,
77 const StringData
* docComment
) {
82 m_docComment
= docComment
;
83 if (ue().isASystemLib()) {
84 m_attrs
= m_attrs
| AttrBuiltin
;
88 PreClassEmitter::~PreClassEmitter() {
89 for (MethodVec::const_iterator it
= m_methods
.begin();
90 it
!= m_methods
.end(); ++it
) {
95 void PreClassEmitter::addInterface(const StringData
* n
) {
96 m_interfaces
.push_back(n
);
99 void PreClassEmitter::addEnumInclude(const StringData
* n
) {
100 m_enumIncludes
.push_back(n
);
103 bool PreClassEmitter::addMethod(FuncEmitter
* method
) {
104 MethodMap::const_iterator it
= m_methodMap
.find(method
->name
);
105 if (it
!= m_methodMap
.end()) {
108 m_methods
.push_back(method
);
109 m_methodMap
[method
->name
] = method
;
113 bool PreClassEmitter::addProperty(const StringData
* n
, Attr attrs
,
114 const StringData
* userType
,
115 const TypeConstraint
& typeConstraint
,
116 const UpperBoundVec
& ubs
,
117 const StringData
* docComment
,
118 const TypedValue
* val
,
119 RepoAuthType repoAuthType
,
120 UserAttributeMap userAttributes
) {
121 assertx(typeConstraint
.validForProp());
122 PropMap::Builder::const_iterator it
= m_propMap
.find(n
);
123 if (it
!= m_propMap
.end()) {
126 PreClassEmitter::Prop prop
{
138 m_propMap
.add(prop
.name(), prop
);
142 bool PreClassEmitter::addAbstractConstant(const StringData
* n
,
143 ConstModifiers::Kind kind
,
145 assertx(kind
== ConstModifiers::Kind::Value
||
146 kind
== ConstModifiers::Kind::Type
);
148 auto it
= m_constMap
.find(n
);
149 if (it
!= m_constMap
.end()) {
152 PreClassEmitter::Const
cns(n
, nullptr, nullptr,
154 Const::Invariance::None
,
156 m_constMap
.add(cns
.name(), cns
);
160 bool PreClassEmitter::addContextConstant(
162 PreClassEmitter::Const::CoeffectsVec coeffects
,
165 auto it
= m_constMap
.find(n
);
166 if (it
!= m_constMap
.end()) {
169 PreClassEmitter::Const
cns(n
, nullptr, nullptr,
170 std::move(coeffects
),
172 ConstModifiers::Kind::Context
,
173 Const::Invariance::None
,
174 isAbstract
, fromTrait
);
175 m_constMap
.add(cns
.name(), cns
);
179 bool PreClassEmitter::addConstant(const StringData
* n
,
180 const StringData
* cls
,
181 const TypedValue
* val
,
182 Array resolvedTypeStructure
,
183 ConstModifiers::Kind kind
,
184 Const::Invariance invariance
,
187 assertx(kind
== ConstModifiers::Kind::Value
||
188 kind
== ConstModifiers::Kind::Type
);
189 assertx(IMPLIES(kind
== ConstModifiers::Kind::Value
, !cls
));
190 assertx(IMPLIES(kind
== ConstModifiers::Kind::Value
,
191 resolvedTypeStructure
.isNull()));
192 assertx(IMPLIES(!resolvedTypeStructure
.isNull(),
193 resolvedTypeStructure
.isDict() &&
194 !resolvedTypeStructure
.empty() &&
195 resolvedTypeStructure
->isStatic()));
196 assertx(IMPLIES(invariance
!= Const::Invariance::None
,
197 !resolvedTypeStructure
.isNull()));
200 ConstMap::Builder::const_iterator it
= m_constMap
.find(n
);
201 if (it
!= m_constMap
.end()) {
204 PreClassEmitter::Const
cns(n
, cls
, val
, {}, std::move(resolvedTypeStructure
),
205 kind
, invariance
, isAbstract
, fromTrait
);
206 m_constMap
.add(cns
.name(), cns
);
210 void PreClassEmitter::addUsedTrait(const StringData
* traitName
) {
211 m_usedTraits
.push_back(traitName
);
215 s_NativeData("__NativeData"),
216 s_DynamicallyConstructible("__DynamicallyConstructible"),
217 s_DynamicallyReferenced("__DynamicallyReferenced"),
218 s_invoke("__invoke"),
219 s_coeffectsProp("86coeffects");
221 PreClass
* PreClassEmitter::create(Unit
& unit
) const {
222 Attr attrs
= m_attrs
;
223 if (attrs
& AttrPersistent
&&
224 !RuntimeOption::RepoAuthoritative
&& !ue().isASystemLib()) {
225 attrs
= Attr(attrs
& ~AttrPersistent
);
228 auto const dynConstructSampleRate
= [&] () -> int64_t {
229 if (!(attrs
& AttrDynamicallyConstructible
)) return -1;
231 auto const it
= m_userAttributes
.find(s_DynamicallyConstructible
.get());
232 if (it
== m_userAttributes
.end()) return -1;
234 assertx(isArrayLikeType(type(it
->second
)));
235 auto const rate
= val(it
->second
).parr
->get(int64_t(0));
236 if (!isIntType(type(rate
)) || val(rate
).num
< 0) return -1;
238 attrs
= Attr(attrs
& ~AttrDynamicallyConstructible
);
239 return val(rate
).num
;
242 auto const invoke
= lookupMethod(s_invoke
.get());
243 if (invoke
&& invoke
->isClosureBody
) {
244 attrs
|= AttrIsClosureClass
;
245 if (!invoke
->coeffectRules
.empty()) {
246 assertx(invoke
->coeffectRules
.size() == 1);
247 if (invoke
->coeffectRules
[0].isClosureParentScope()) {
248 attrs
|= AttrHasClosureCoeffectsProp
;
250 assertx(invoke
->coeffectRules
[0].isCaller());
255 if (attrs
& AttrInternal
&&
256 m_userAttributes
.find(s_SoftInternal
.get()) != m_userAttributes
.end()) {
257 attrs
|= AttrInternalSoft
;
260 assertx(attrs
& AttrPersistent
|| !ue().isASystemLib());
262 auto pc
= std::make_unique
<PreClass
>(
263 &unit
, m_line1
, m_line2
, m_name
,
264 attrs
, m_parent
, m_docComment
);
265 pc
->m_interfaces
= m_interfaces
;
266 pc
->m_includedEnums
= m_enumIncludes
;
267 pc
->m_usedTraits
= m_usedTraits
;
268 pc
->m_requirements
= m_requirements
;
269 pc
->m_enumBaseTy
= m_enumBaseTy
;
270 pc
->m_numDeclMethods
= -1;
271 pc
->m_ifaceVtableSlot
= m_ifaceVtableSlot
;
272 pc
->m_dynConstructSampleRate
= dynConstructSampleRate
;
274 // Set user attributes.
276 pc
->m_userAttributes
= m_userAttributes
;
277 pc
->m_nativeDataInfo
= nullptr;
278 if (!m_userAttributes
.size()) return;
280 // Check for <<__NativeData>>.
281 auto it
= m_userAttributes
.find(s_NativeData
.get());
282 if (it
== m_userAttributes
.end()) return;
284 pc
->m_nativeDataInfo
= Native::getNativeDataInfo(m_name
.get());
287 PreClass::MethodMap::Builder methodBuild
;
288 for (MethodVec::const_iterator it
= m_methods
.begin();
289 it
!= m_methods
.end(); ++it
) {
290 Func
* f
= (*it
)->create(unit
, pc
.get());
291 if (f
->attrs() & AttrTrait
) {
292 if (pc
->m_numDeclMethods
== -1) {
293 pc
->m_numDeclMethods
= it
- m_methods
.begin();
295 } else if (!f
->isGenerated()) {
296 assertx(pc
->m_numDeclMethods
== -1);
298 methodBuild
.add(f
->name(), f
);
300 pc
->m_methods
.create(methodBuild
);
302 PreClass::PropMap::Builder propBuild
;
303 if (pc
->attrs() & AttrHasClosureCoeffectsProp
) {
305 tvWriteUninit(tvInit
);
307 propBuild
.add(s_coeffectsProp
.get(), PreClass::Prop(pc
.get(),
308 s_coeffectsProp
.get(),
309 AttrPrivate
|AttrSystemInitialValue
,
312 TypeIntersectionConstraint
{},
319 for (unsigned i
= 0; i
< m_propMap
.size(); ++i
) {
320 const Prop
& prop
= m_propMap
[i
];
321 propBuild
.add(prop
.name(), PreClass::Prop(pc
.get(),
325 prop
.typeConstraint(),
330 prop
.userAttributes()));
332 pc
->m_properties
.create(propBuild
);
334 PreClass::ConstMap::Builder constBuild
;
335 for (unsigned i
= 0; i
< m_constMap
.size(); ++i
) {
336 const Const
& const_
= m_constMap
[i
];
338 tvaux
.constModifiers() = {};
339 tvaux
.constModifiers().setIsAbstract(const_
.isAbstract());
340 if (const_
.kind() == ConstModifiers::Kind::Context
) {
341 auto const coeffects
=
342 getCoeffectsInfoFromList(const_
.coeffects(), false).first
;
343 tvaux
.constModifiers().setCoeffects(coeffects
);
344 if (!const_
.coeffects().empty()) {
345 tvCopy(make_tv
<KindOfInt64
>(0), tvaux
); // dummy value for m_data
347 tvWriteConstValMissing(tvaux
);
350 if (const_
.valOption()) {
351 tvCopy(const_
.val(), tvaux
);
353 tvWriteConstValMissing(tvaux
);
357 tvaux
.constModifiers().setKind(const_
.kind());
360 IMPLIES(const_
.kind() != ConstModifiers::Kind::Type
, !const_
.cls())
363 IMPLIES(const_
.kind() != ConstModifiers::Kind::Type
,
364 const_
.resolvedTypeStructure().isNull())
367 IMPLIES(!const_
.resolvedTypeStructure().isNull(),
368 const_
.resolvedTypeStructure().isDict() &&
369 !const_
.resolvedTypeStructure().empty())
372 IMPLIES(const_
.invariance() != Const::Invariance::None
,
373 !const_
.resolvedTypeStructure().isNull())
382 const_
.resolvedTypeStructure(),
388 if (auto nativeConsts
= Native::getClassConstants(m_name
)) {
389 for (auto cnsMap
: *nativeConsts
) {
391 tvCopy(cnsMap
.second
, tvaux
);
392 tvaux
.constModifiers() = {};
393 constBuild
.add(cnsMap
.first
, PreClass::Const(cnsMap
.first
,
397 Const::Invariance::None
,
402 pc
->m_constants
.create(constBuild
);
406 template<class SerDe
> void PreClassEmitter::serdeMetaData(SerDe
& sd
) {
407 // NOTE: name and a few other fields currently
408 // serialized outside of this.
421 (m_propMap
, [](Prop p
) { return p
.name(); })
422 (m_constMap
, [](Const c
) { return c
.name(); })
427 template void PreClassEmitter::serdeMetaData
<>(BlobDecoder
&);
428 template void PreClassEmitter::serdeMetaData
<>(BlobEncoder
&);