Updating submodules
[hiphop-php.git] / hphp / runtime / vm / preclass-emitter.cpp
blobf7b4e022f3880eb14af28da8042a7e25a436275a
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/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"
31 namespace HPHP {
33 const StaticString s_SoftInternal("__SoftInternal");
35 //=============================================================================
36 // PreClassEmitter::Prop.
38 PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
39 const StringData* n,
40 Attr attrs,
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)
48 : m_name(n)
49 , m_attrs(attrs)
50 , m_userType(userType)
51 , m_docComment(docComment)
52 , m_repoAuthType(repoAuthType)
53 , m_typeConstraint(typeConstraint)
54 , m_ubs(ubs)
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 //=============================================================================
68 // PreClassEmitter.
70 PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
71 const std::string& n)
72 : m_ue(ue)
73 , m_name(makeStaticString(n)) {}
75 void PreClassEmitter::init(int line1, int line2, Attr attrs,
76 const StringData* parent,
77 const StringData* docComment) {
78 m_line1 = line1;
79 m_line2 = line2;
80 m_attrs = attrs;
81 m_parent = parent;
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) {
91 delete *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()) {
106 return false;
108 m_methods.push_back(method);
109 m_methodMap[method->name] = method;
110 return true;
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()) {
124 return false;
126 PreClassEmitter::Prop prop{
127 this,
129 attrs,
130 userType,
131 typeConstraint,
132 ubs,
133 docComment,
134 val,
135 repoAuthType,
136 userAttributes
138 m_propMap.add(prop.name(), prop);
139 return true;
142 bool PreClassEmitter::addAbstractConstant(const StringData* n,
143 ConstModifiers::Kind kind,
144 bool fromTrait) {
145 assertx(kind == ConstModifiers::Kind::Value ||
146 kind == ConstModifiers::Kind::Type);
148 auto it = m_constMap.find(n);
149 if (it != m_constMap.end()) {
150 return false;
152 PreClassEmitter::Const cns(n, nullptr, nullptr,
153 {}, Array{}, kind,
154 Const::Invariance::None,
155 true, fromTrait);
156 m_constMap.add(cns.name(), cns);
157 return true;
160 bool PreClassEmitter::addContextConstant(
161 const StringData* n,
162 PreClassEmitter::Const::CoeffectsVec coeffects,
163 bool isAbstract,
164 bool fromTrait) {
165 auto it = m_constMap.find(n);
166 if (it != m_constMap.end()) {
167 return false;
169 PreClassEmitter::Const cns(n, nullptr, nullptr,
170 std::move(coeffects),
171 Array{},
172 ConstModifiers::Kind::Context,
173 Const::Invariance::None,
174 isAbstract, fromTrait);
175 m_constMap.add(cns.name(), cns);
176 return true;
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,
185 bool fromTrait,
186 bool isAbstract) {
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()));
198 assertx(val);
200 ConstMap::Builder::const_iterator it = m_constMap.find(n);
201 if (it != m_constMap.end()) {
202 return false;
204 PreClassEmitter::Const cns(n, cls, val, {}, std::move(resolvedTypeStructure),
205 kind, invariance, isAbstract, fromTrait);
206 m_constMap.add(cns.name(), cns);
207 return true;
210 void PreClassEmitter::addUsedTrait(const StringData* traitName) {
211 m_usedTraits.push_back(traitName);
214 const StaticString
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;
240 }();
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;
249 } else {
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.
275 [&] {
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());
285 }();
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) {
304 TypedValue tvInit;
305 tvWriteUninit(tvInit);
307 propBuild.add(s_coeffectsProp.get(), PreClass::Prop(pc.get(),
308 s_coeffectsProp.get(),
309 AttrPrivate|AttrSystemInitialValue,
310 staticEmptyString(),
311 TypeConstraint(),
312 TypeIntersectionConstraint{},
313 staticEmptyString(),
314 tvInit,
315 RepoAuthType{},
316 UserAttributeMap{}
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(),
322 prop.name(),
323 prop.attrs(),
324 prop.userType(),
325 prop.typeConstraint(),
326 prop.upperBounds(),
327 prop.docComment(),
328 prop.val(),
329 prop.repoAuthType(),
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];
337 TypedValueAux tvaux;
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
346 } else {
347 tvWriteConstValMissing(tvaux);
349 } else {
350 if (const_.valOption()) {
351 tvCopy(const_.val(), tvaux);
352 } else {
353 tvWriteConstValMissing(tvaux);
357 tvaux.constModifiers().setKind(const_.kind());
359 assertx(
360 IMPLIES(const_.kind() != ConstModifiers::Kind::Type, !const_.cls())
362 assertx(
363 IMPLIES(const_.kind() != ConstModifiers::Kind::Type,
364 const_.resolvedTypeStructure().isNull())
366 assertx(
367 IMPLIES(!const_.resolvedTypeStructure().isNull(),
368 const_.resolvedTypeStructure().isDict() &&
369 !const_.resolvedTypeStructure().empty())
371 assertx(
372 IMPLIES(const_.invariance() != Const::Invariance::None,
373 !const_.resolvedTypeStructure().isNull())
376 constBuild.add(
377 const_.name(),
378 PreClass::Const(
379 const_.name(),
380 const_.cls(),
381 tvaux,
382 const_.resolvedTypeStructure(),
383 const_.invariance(),
384 const_.isFromTrait()
388 if (auto nativeConsts = Native::getClassConstants(m_name)) {
389 for (auto cnsMap : *nativeConsts) {
390 TypedValueAux tvaux;
391 tvCopy(cnsMap.second, tvaux);
392 tvaux.constModifiers() = {};
393 constBuild.add(cnsMap.first, PreClass::Const(cnsMap.first,
394 nullptr,
395 tvaux,
396 Array{},
397 Const::Invariance::None,
398 false));
402 pc->m_constants.create(constBuild);
403 return pc.release();
406 template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
407 // NOTE: name and a few other fields currently
408 // serialized outside of this.
409 sd(m_line1)
410 (m_line2)
411 (m_attrs)
412 (m_parent)
413 (m_docComment)
414 (m_ifaceVtableSlot)
416 (m_interfaces)
417 (m_enumIncludes)
418 (m_usedTraits)
419 (m_requirements)
420 (m_userAttributes)
421 (m_propMap, [](Prop p) { return p.name(); })
422 (m_constMap, [](Const c) { return c.name(); })
423 (m_enumBaseTy)
427 template void PreClassEmitter::serdeMetaData<>(BlobDecoder&);
428 template void PreClassEmitter::serdeMetaData<>(BlobEncoder&);
430 } // HPHP