Rm experimental/Instructions.,h
[hiphop-php.git] / hphp / hhbbc / class-util.cpp
blobdf432754eaec8e2fc5c098891d917d9746aafc6a
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/hhbbc/class-util.h"
18 #include "hphp/hhbbc/analyze.h"
19 #include "hphp/hhbbc/context.h"
20 #include "hphp/hhbbc/index.h"
21 #include "hphp/hhbbc/representation.h"
22 #include "hphp/hhbbc/type-system.h"
24 #include "hphp/runtime/base/array-init.h"
25 #include "hphp/runtime/base/collections.h"
27 #include "hphp/runtime/vm/preclass-emitter.h"
29 #include <boost/algorithm/string/predicate.hpp>
31 namespace HPHP::HHBBC {
33 //////////////////////////////////////////////////////////////////////
35 namespace {
37 const StaticString
38 s_SimpleXMLElement("SimpleXMLElement"),
39 s_Closure("Closure"),
40 s_MockClass("__MockClass"),
41 s_NoFlatten("__NoFlatten"),
42 s_invoke("__invoke"),
43 s_debugInfo("__debugInfo"),
44 s_construct("__construct");
48 //////////////////////////////////////////////////////////////////////
50 bool has_magic_bool_conversion(SString clsName) {
51 return
52 collections::isTypeName(clsName) ||
53 clsName->tsame(s_SimpleXMLElement.get());
56 bool is_collection(res::Class cls) {
57 auto const name = cls.name();
58 return collections::isTypeName(name);
61 php::Func* find_method(const php::Class* cls, SString name) {
62 for (auto& m : cls->methods) {
63 if (m->name == name) {
64 return m.get();
67 return nullptr;
70 bool is_special_method_name(SString name) {
71 auto const p = name->data();
72 return p && p[0] == '8' && p[1] == '6';
75 bool has_name_only_func_family(SString name) {
76 return
77 name != s_construct.get() &&
78 name != s_invoke.get() &&
79 name != s_debugInfo.get() &&
80 !is_special_method_name(name);
83 bool is_mock_class(const php::Class* cls) {
84 return cls->userAttributes.count(s_MockClass.get());
87 bool is_noflatten_trait(const php::Class* cls) {
88 assertx(cls->attrs & AttrTrait);
89 return cls->userAttributes.count(s_NoFlatten.get());
92 bool is_closure_base(SString name) {
93 return name->tsame(s_Closure.get());
96 bool is_closure_base(const php::Class& c) {
97 return c.name->tsame(s_Closure.get());
100 bool is_closure(const php::Class& c) {
101 return c.parentName && c.parentName->tsame(s_Closure.get());
104 bool is_closure_name(SString name) {
105 return boost::starts_with(name->slice(), "Closure$");
108 bool is_unused_trait(const php::Class& c) {
109 return
110 (c.attrs & (AttrTrait | AttrNoOverride)) == (AttrTrait | AttrNoOverride);
113 bool is_used_trait(const php::Class& c) {
114 return
115 (c.attrs & (AttrTrait | AttrNoOverride)) == AttrTrait;
118 //////////////////////////////////////////////////////////////////////
120 Type get_type_of_reified_list(const UserAttributeMap& ua) {
121 auto const it = ua.find(s___Reified.get());
122 assertx(it != ua.end());
123 auto const tv = it->second;
124 assertx(tvIsVec(&tv));
125 auto const info = extractSizeAndPosFromReifiedAttribute(tv.m_data.parr);
126 auto const numGenerics = info.m_typeParamInfo.size();
127 assertx(numGenerics > 0);
129 auto t = vec(std::vector<Type>(numGenerics, TDict));
131 // If the type params are all soft, the reified list is allowed to
132 // be empty.
133 auto const allSoft = [&] {
134 for (auto const& tp : info.m_typeParamInfo) {
135 if (!tp.m_isSoft) return false;
137 return true;
138 }();
139 if (allSoft) t |= TVecE;
140 return t;
143 // The value returned from this must satisfy the type returned from
144 // get_type_of_reified_list.
145 TypedValue get_default_value_of_reified_list(const UserAttributeMap& ua) {
146 auto const it = ua.find(s___Reified.get());
147 assertx(it != ua.end());
148 auto const tv = it->second;
149 assertx(tvIsVec(&tv));
150 auto const info = extractSizeAndPosFromReifiedAttribute(tv.m_data.parr);
151 auto const numGenerics = info.m_typeParamInfo.size();
152 assertx(numGenerics > 0);
154 // Empty vec is allowed for the "all soft" case, so use that if it
155 // applies.
156 auto const allSoft = [&] {
157 for (auto const& tp : info.m_typeParamInfo) {
158 if (!tp.m_isSoft) return false;
160 return true;
161 }();
162 if (allSoft) return make_tv<KindOfPersistentVec>(staticEmptyVec());
164 // Otherwise make a vec of the appropriate size filled with empty
165 // dicts, which satisfies get_type_of_reified_list.
166 VecInit init{numGenerics};
167 for (size_t i = 0; i < numGenerics; ++i) {
168 init.append(make_tv<KindOfPersistentDict>(staticEmptyDictArray()));
170 auto var = init.toVariant();
171 var.setEvalScalar();
172 return *var.asTypedValue();
175 Type loosen_this_prop_for_serialization(const php::Class& ctx,
176 SString name,
177 Type type) {
178 // The 86reified_prop has special enforcement for serialization, so
179 // we don't have to pessimize it as much.
180 if (name == s_86reified_prop.get()) {
181 return union_of(
182 std::move(type),
183 get_type_of_reified_list(ctx.userAttributes)
186 return loosen_vec_or_dict(loosen_all(std::move(type)));
189 //////////////////////////////////////////////////////////////////////
191 namespace php {
193 //////////////////////////////////////////////////////////////////////
195 ClassBase::ClassBase(const ClassBase& other) {
196 for (auto& m : other.methods) {
197 if (!m) {
198 methods.emplace_back();
199 } else {
200 methods.emplace_back(std::make_unique<php::Func>(*m));
203 for (auto& c : other.closures) {
204 closures.emplace_back(std::make_unique<php::Class>(*c));
208 //////////////////////////////////////////////////////////////////////
212 //////////////////////////////////////////////////////////////////////