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/record.h"
19 #include "hphp/runtime/base/runtime-error.h"
20 #include "hphp/runtime/vm/preclass.h"
21 #include "hphp/runtime/vm/treadmill.h"
22 #include "hphp/runtime/vm/unit.h"
28 PreRecordDesc::PreRecordDesc(Unit
* unit
, int line1
, int line2
,
29 const StringData
* name
, Attr attrs
,
30 const StringData
* parentName
,
31 const StringData
* docComment
, Id id
)
33 , m_namedEntity(NamedEntity::get(name
))
39 , m_parentName(parentName
)
40 , m_docComment(docComment
) {}
42 void PreRecordDesc::atomicRelease() {
46 PreRecordDesc::Field::Field(PreRecordDesc
* record
,
47 const StringData
* name
,
49 const StringData
* userType
,
50 const TypeConstraint
& typeConstraint
,
51 const StringData
* docComment
,
52 const TypedValue
& val
,
53 RepoAuthType repoAuthType
,
54 UserAttributeMap userAttributes
)
56 , m_mangledName(mangleFieldName(record
->name(), name
, attrs
))
58 , m_userType
{userType
}
59 , m_docComment(docComment
)
61 , m_repoAuthType
{repoAuthType
}
62 , m_typeConstraint
{typeConstraint
}
63 , m_userAttributes(userAttributes
)
66 const StringData
* PreRecordDesc::mangleFieldName(
67 const StringData
* recordName
,
68 const StringData
* fieldName
,
70 return PreClass::manglePropName(recordName
, fieldName
, attrs
);
73 void PreRecordDesc::checkDefaultValueType(
74 const PreRecordDesc::Field
& field
) const {
75 auto const& val
= field
.val();
76 if (val
.m_type
== KindOfUninit
) return;
77 auto const& tc
= field
.typeConstraint();
78 if (tc
.isCheckable()) tc
.verifyRecField(&val
, m_name
, field
.name());
82 size_t RecordDesc::stableHash() const {
83 return folly::hash::hash_combine(
89 void RecordDesc::atomicRelease() {
90 assertx(!m_cachedRecordDesc
.bound());
96 void RecordDesc::setCached() {
97 m_cachedRecordDesc
.initWith(this);
100 void RecordDesc::setRecordDescHandle(
101 rds::Link
<LowPtr
<RecordDesc
>, rds::Mode::NonLocal
> link
) const {
102 assertx(!m_cachedRecordDesc
.bound());
103 m_cachedRecordDesc
= link
;
106 bool RecordDesc::verifyPersistent() const {
107 if (!isPersistent()) return false;
108 assertx(!m_parent
|| recordHasPersistentRDS(m_parent
.get()));
112 void RecordDesc::destroy() {
113 if (!m_cachedRecordDesc
.bound()) return;
115 Lock
l(g_recordsMutex
);
116 if (!m_cachedRecordDesc
.bound()) return;
117 m_cachedRecordDesc
= rds::Link
<LowPtr
<RecordDesc
>, rds::Mode::NonLocal
>{};
118 m_preRec
->namedEntity()->removeRecordDesc(this);
123 if (!this->decAtomicCount()) this->atomicRelease();
128 Slot
RecordDesc::lookupField(const StringData
* fieldName
) const {
129 return m_fields
.findIndex(fieldName
);
132 const RecordDesc::Field
& RecordDesc::field(Slot idx
) const {
133 assertx(idx
!= kInvalidSlot
&& idx
< numFields());
134 return m_fields
[idx
];
137 RecordDesc::Avail
RecordDesc::availWithParent(
138 RecordDesc
*& parent
, bool tryAutoload
/* = false */) const {
139 if (RecordDesc
* ourParent
= m_parent
.get()) {
141 auto pprec
= ourParent
->m_preRec
.get();
142 parent
= Unit::getRecordDesc(pprec
->namedEntity(),
143 parentName(), tryAutoload
);
149 if (parent
!= ourParent
) {
150 if (UNLIKELY(ourParent
->isZombie())) {
151 const_cast<RecordDesc
*>(this)->destroy();
159 RecordDesc
* RecordDesc::newRecordDesc(PreRecordDesc
* preRec
,
160 RecordDesc
* parent
) {
161 auto const mem
= lower_malloc(sizeof(RecordDesc
));
163 return new (mem
) RecordDesc(preRec
, parent
);
170 void RecordDesc::setParent() {
171 // validate the parent
172 if (m_parent
.get() != nullptr) {
173 auto parentAttrs
= m_parent
->attrs();
174 if (UNLIKELY(parentAttrs
& AttrFinal
)) {
175 raise_error("Record %s may not inherit from non-abstract record %s",
176 name()->data(), m_parent
->name()->data());
181 void RecordDesc::setFields() {
182 FieldMap::Builder curFieldMap
;
183 if (m_parent
.get() != nullptr) {
184 for (auto const& parentField
: m_parent
->allFields()) {
185 curFieldMap
.add(parentField
.name(), parentField
);
188 for (auto const& preField
: m_preRec
->allFields()) {
189 auto const it
= curFieldMap
.find(preField
.name());
190 if (it
!= curFieldMap
.end()) {
191 raise_error("Cannot redeclare record field %s::%s",
193 preField
.name()->data());
195 m_preRec
->checkDefaultValueType(preField
);
196 curFieldMap
.add(preField
.name(), preField
);
198 m_fields
.create(curFieldMap
);
201 RecordDesc::RecordDesc(PreRecordDesc
* preRec
, RecordDesc
* parent
)
203 , m_preRec(PreRecordDescPtr(preRec
))
204 , m_serialized(false) {
209 bool RecordDesc::recordDescOf(const RecordDesc
* rec
) const {
210 // TODO: Optimize this. See T45403957.
214 if (curr
== rec
) return true;
215 curr
= curr
->m_parent
.get();
220 const RecordDesc
* RecordDesc::commonAncestor(const RecordDesc
* rec
) const {
221 // TODO: Optimize this. See T45403957.
223 std::vector
<const RecordDesc
*> thisVec
;
224 std::vector
<const RecordDesc
*> recVec
;
225 for (auto r
= this; r
!= nullptr; r
= r
->m_parent
.get()) thisVec
.push_back(r
);
226 for (auto r
= rec
; r
!= nullptr; r
= r
->m_parent
.get()) recVec
.push_back(r
);
227 auto idx
= std::min(thisVec
.size(), recVec
.size()) - 1;
229 if (thisVec
[idx
] == recVec
[idx
]) return thisVec
[idx
];
234 bool RecordDesc::serialize() const {
235 if (m_serialized
) return false;
240 bool RecordDesc::wasSerialized() const {