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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/preclass.h"
19 #include "hphp/runtime/base/array-iterator.h"
20 #include "hphp/runtime/base/attr.h"
21 #include "hphp/runtime/base/datatype.h"
22 #include "hphp/runtime/base/repo-auth-type.h"
23 #include "hphp/runtime/base/string-data.h"
24 #include "hphp/runtime/base/typed-value.h"
25 #include "hphp/runtime/vm/func.h"
26 #include "hphp/runtime/vm/hhbc.h"
27 #include "hphp/runtime/vm/unit.h"
33 ///////////////////////////////////////////////////////////////////////////////
35 PreClass::PreClass(Unit
* unit
, int line1
, int line2
, const StringData
* n
,
36 Attr attrs
, const StringData
* parent
, const StringData
* docComment
,
39 , m_namedEntity(NamedEntity::get(n
))
46 , m_docComment(docComment
)
50 PreClass::~PreClass() {
51 std::for_each(methods(), methods() + numMethods(), Func::destroy
);
54 void PreClass::atomicRelease() {
58 const StringData
* PreClass::manglePropName(const StringData
* className
,
59 const StringData
* propName
,
61 switch (attrs
& VisibilityAttrs
) {
66 std::string mangledName
= "";
67 mangledName
.push_back('\0');
68 mangledName
.push_back('*');
69 mangledName
.push_back('\0');
70 mangledName
+= propName
->data();
71 return makeStaticString(mangledName
);
74 std::string mangledName
= "";
75 mangledName
.push_back('\0');
76 mangledName
+= className
->data();
77 mangledName
.push_back('\0');
78 mangledName
+= propName
->data();
79 return makeStaticString(mangledName
);
82 //Failing here will cause the VM to crash before the Verifier runs, so we
83 //defer the failure to runtime so the Verifier can report this problem to
85 return staticEmptyString();
89 void PreClass::prettyPrint(std::ostream
&out
) const {
90 if (m_attrs
& AttrSealed
) { out
<< "<<__Sealed()>> "; }
92 if (m_attrs
& AttrAbstract
) { out
<< "abstract "; }
93 if (m_attrs
& AttrFinal
) { out
<< "final "; }
94 if (m_attrs
& AttrInterface
) { out
<< "interface "; }
95 out
<< m_name
->data();
96 if (m_attrs
& AttrNoOverride
){ out
<< " (nooverride)"; }
97 if (m_attrs
& AttrUnique
) out
<< " (unique)";
98 if (m_attrs
& AttrPersistent
) out
<< " (persistent)";
99 if (m_attrs
& AttrIsConst
) {
100 // AttrIsConst classes will always also have AttrForbidDynamicProps set,
101 // so don't bother printing it
103 } else if (m_attrs
& AttrForbidDynamicProps
) {
104 out
<< " (no-dynamic-props)";
106 if (m_attrs
& AttrDynamicallyConstructible
) out
<< " (dyn_constructible)";
108 out
<< " (ID " << m_id
<< ")";
112 for (Func
* const* it
= methods(); it
!= methods() + numMethods(); ++it
) {
114 (*it
)->prettyPrint(out
);
116 for (const Prop
* it
= properties();
117 it
!= properties() + numProperties();
120 it
->prettyPrint(out
, this);
122 for (const Const
* it
= constants();
123 it
!= constants() + numConstants();
126 it
->prettyPrint(out
, this);
130 const StaticString
s___Sealed("__Sealed");
131 void PreClass::enforceInMaybeSealedParentWhitelist(
132 const PreClass
* parentPreClass
) const {
133 // if our parent isn't sealed, then we're fine. If we're a mock, YOLO
134 if (!(parentPreClass
->attrs() & AttrSealed
) ||
135 m_userAttributes
.find(s___MockClass
.get()) != m_userAttributes
.end()) {
138 const UserAttributeMap
& parent_attrs
= parentPreClass
->userAttributes();
139 assertx(parent_attrs
.find(s___Sealed
.get()) != parent_attrs
.end());
140 const auto& parent_sealed_attr
= parent_attrs
.find(s___Sealed
.get())->second
;
141 bool in_sealed_whitelist
= false;
142 IterateV(parent_sealed_attr
.m_data
.parr
,
143 [&in_sealed_whitelist
, this](TypedValue v
) -> bool {
144 if (v
.m_data
.pstr
->same(name())) {
145 in_sealed_whitelist
= true;
150 if (!in_sealed_whitelist
) {
151 raise_error("Class %s may not inherit from sealed %s (%s) without "
152 "being in the whitelist",
154 parentPreClass
->attrs() & AttrInterface
? "interface" : "class",
155 parentPreClass
->name()->data());
159 const StaticString
s___EnableMethodTraitDiamond("__EnableMethodTraitDiamond");
160 bool PreClass::enableMethodTraitDiamond() {
161 return m_userAttributes
.find(s___EnableMethodTraitDiamond
.get()) != m_userAttributes
.end();
164 ///////////////////////////////////////////////////////////////////////////////
167 PreClass::Prop::Prop(PreClass
* preClass
,
168 const StringData
* name
,
170 const StringData
* userType
,
171 const TypeConstraint
& typeConstraint
,
172 const CompactVector
<TypeConstraint
>& ubs
,
173 const StringData
* docComment
,
174 const TypedValue
& val
,
175 RepoAuthType repoAuthType
,
176 UserAttributeMap userAttributes
)
178 , m_mangledName(manglePropName(preClass
->name(), name
, attrs
))
180 , m_userType
{userType
}
181 , m_docComment(docComment
)
183 , m_repoAuthType
{repoAuthType
}
184 , m_typeConstraint
{typeConstraint
}
185 , m_userAttributes(userAttributes
) {
186 m_ubs
.resize(ubs
.size());
187 std::copy(ubs
.begin(), ubs
.end(), m_ubs
.begin());
190 void PreClass::Prop::prettyPrint(std::ostream
& out
,
191 const PreClass
* preClass
) const {
193 if (m_attrs
& AttrStatic
) { out
<< "static "; }
194 if (m_attrs
& AttrPublic
) { out
<< "public "; }
195 if (m_attrs
& AttrProtected
) { out
<< "protected "; }
196 if (m_attrs
& AttrPrivate
) { out
<< "private "; }
197 if (m_attrs
& AttrInternal
) { out
<< "internal "; }
198 if (m_attrs
& AttrPersistent
) { out
<< "(persistent) "; }
199 if (m_attrs
& AttrIsConst
) { out
<< "(const) "; }
200 if (m_attrs
& AttrTrait
) { out
<< "(trait) "; }
201 if (m_attrs
& AttrNoBadRedeclare
) { out
<< "(no-bad-redeclare) "; }
202 if (m_attrs
& AttrNoOverride
) { out
<< "(no-override) "; }
203 if (m_attrs
& AttrSystemInitialValue
) { out
<< "(system-initial-val) "; }
204 if (m_attrs
& AttrNoImplicitNullable
) { out
<< "(no-implicit-nullable) "; }
205 if (m_attrs
& AttrInitialSatisfiesTC
) { out
<< "(initial-satisfies-tc) "; }
206 if (m_attrs
& AttrLSB
) { out
<< "(lsb) "; }
207 if (m_attrs
& AttrLateInit
) { out
<< "(late-init) "; }
208 out
<< preClass
->name()->data() << "::" << m_name
->data() << " = ";
209 if (m_val
.m_type
== KindOfUninit
) {
210 out
<< "<non-scalar>";
213 staticStreamer(&m_val
, ss
);
216 out
<< " (RAT = " << show(m_repoAuthType
) << ")";
217 if (m_userType
&& !m_userType
->empty()) {
218 out
<< " (user-type = " << m_userType
->data() << ")";
220 if (m_typeConstraint
.hasConstraint()) {
221 out
<< " (tc = " << m_typeConstraint
.displayName(nullptr, true) << ")";
223 if (!m_ubs
.empty()) {
225 for (auto const& ub
: m_ubs
) {
226 if (ub
.hasConstraint()) {
227 out
<< ub
.displayName(nullptr, true);
236 ///////////////////////////////////////////////////////////////////////////////
239 PreClass::Const::Const(const StringData
* name
,
240 const StringData
* cls
,
241 const TypedValueAux
& val
,
242 Array resolvedTypeStructure
,
243 Invariance invariance
,
248 , m_resolvedTypeStructure(std::move(resolvedTypeStructure
))
249 , m_invariance(invariance
)
250 , m_fromTrait(fromTrait
)
253 void PreClass::Const::prettyPrint(std::ostream
& out
,
254 const PreClass
* preClass
) const {
256 case ConstModifiers::Kind::Value
:
258 case ConstModifiers::Kind::Type
:
261 case ConstModifiers::Kind::Context
:
265 auto const name
= [&] {
266 out
<< preClass
->name()->data() << "::" << m_name
->data();
267 if (cls()) out
<< " (" << cls()->data() << ")";
269 if (isAbstractAndUninit()) {
270 out
<< "Constant (abstract) ";
275 if (kind() == ConstModifiers::Kind::Context
) {
278 out
<< " " << coeffects().toString()
284 if (m_val
.m_type
== KindOfUninit
) {
285 out
<< " = <non-scalar>";
288 staticStreamer(&m_val
, ss
);
291 if (!m_resolvedTypeStructure
.isNull()) {
294 make_array_like_tv(m_resolvedTypeStructure
.get());
295 staticStreamer(&tv
, ss
);
296 out
<< " (resolved = " << ss
<< ")";
297 switch (invariance()) {
298 case Invariance::None
:
300 case Invariance::Present
:
303 case Invariance::ClassnamePresent
:
304 out
<< " <classname>";
306 case Invariance::Same
:
314 StaticCoeffects
PreClass::Const::coeffects() const {
315 assertx(kind() == ConstModifiers::Kind::Context
);
316 return m_val
.constModifiers().getCoeffects();
319 ///////////////////////////////////////////////////////////////////////////////
320 // PreClass::TraitAliasRule.
322 PreClass::TraitAliasRule::NamePair
323 PreClass::TraitAliasRule::asNamePair() const {
324 auto const tmp
= folly::sformat(
326 traitName()->empty() ? "(null)" : traitName()->data(),
329 auto origName
= makeStaticString(tmp
);
330 return std::make_pair(newMethodName(), origName
);
333 ///////////////////////////////////////////////////////////////////////////////