Compute ambient coeffects and write to coeffects local
[hiphop-php.git] / hphp / runtime / vm / record.cpp
blob3971d1f34b35583ce6040e91f1a235f224be5a21
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 +----------------------------------------------------------------------+
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"
24 namespace HPHP {
26 Mutex g_recordsMutex;
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)
32 : m_unit(unit)
33 , m_namedEntity(NamedEntity::get(name))
34 , m_line1(line1)
35 , m_line2(line2)
36 , m_id(id)
37 , m_attrs(attrs)
38 , m_name(name)
39 , m_parentName(parentName)
40 , m_docComment(docComment) {}
42 void PreRecordDesc::atomicRelease() {
43 delete this;
46 PreRecordDesc::Field::Field(PreRecordDesc* record,
47 const StringData* name,
48 Attr attrs,
49 const StringData* userType,
50 const TypeConstraint& typeConstraint,
51 const StringData* docComment,
52 const TypedValue& val,
53 RepoAuthType repoAuthType,
54 UserAttributeMap userAttributes)
55 : m_name(name)
56 , m_mangledName(mangleFieldName(record->name(), name, attrs))
57 , m_attrs(attrs)
58 , m_userType{userType}
59 , m_docComment(docComment)
60 , m_val(val)
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,
69 Attr attrs) {
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(
84 name()->hashStatic(),
85 unit()->sn()
89 void RecordDesc::atomicRelease() {
90 assertx(!m_cachedRecordDesc.bound());
91 assertx(!getCount());
92 this->~RecordDesc();
93 lower_free(this);
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()));
109 return true;
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);
119 m_parent.reset();
121 Treadmill::enqueue(
122 [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()) {
140 if (!parent) {
141 auto pprec = ourParent->m_preRec.get();
142 parent = Unit::getRecordDesc(pprec->namedEntity(),
143 parentName(), tryAutoload);
144 if (!parent) {
145 parent = ourParent;
146 return Avail::Fail;
149 if (parent != ourParent) {
150 if (UNLIKELY(ourParent->isZombie())) {
151 const_cast<RecordDesc*>(this)->destroy();
153 return Avail::False;
156 return Avail::True;
159 RecordDesc* RecordDesc::newRecordDesc(PreRecordDesc* preRec,
160 RecordDesc* parent) {
161 auto const mem = lower_malloc(sizeof(RecordDesc));
162 try {
163 return new (mem) RecordDesc(preRec, parent);
164 } catch (...) {
165 lower_free(mem);
166 throw;
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",
192 name()->data(),
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)
202 : m_parent(parent)
203 , m_preRec(PreRecordDescPtr(preRec))
204 , m_serialized(false) {
205 setParent();
206 setFields();
209 bool RecordDesc::recordDescOf(const RecordDesc* rec) const {
210 // TODO: Optimize this. See T45403957.
211 assertx(rec);
212 auto curr = this;
213 while(curr) {
214 if (curr == rec) return true;
215 curr = curr->m_parent.get();
217 return false;
220 const RecordDesc* RecordDesc::commonAncestor(const RecordDesc* rec) const {
221 // TODO: Optimize this. See T45403957.
222 assertx(rec);
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;
228 do {
229 if (thisVec[idx] == recVec[idx]) return thisVec[idx];
230 } while(idx--);
231 return nullptr;
234 bool RecordDesc::serialize() const {
235 if (m_serialized) return false;
236 m_serialized = true;
237 return true;
240 bool RecordDesc::wasSerialized() const {
241 return m_serialized;