Serialize/Deserialize TargetProfiles
[hiphop-php.git] / hphp / runtime / vm / jit / prof-data-serialize.cpp
blob72cd06a5c0484e0dd85b1683b96954beb1758070
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/jit/prof-data-serialize.h"
19 #include "hphp/runtime/base/builtin-functions.h"
20 #include "hphp/runtime/base/program-functions.h"
21 #include "hphp/runtime/base/string-data.h"
22 #include "hphp/runtime/base/unit-cache.h"
23 #include "hphp/runtime/base/variable-serializer.h"
25 #include "hphp/runtime/ext/std/ext_std_closure.h"
27 #include "hphp/runtime/vm/class.h"
28 #include "hphp/runtime/vm/func.h"
29 #include "hphp/runtime/vm/jit/array-kind-profile.h"
30 #include "hphp/runtime/vm/jit/array-offset-profile.h"
31 #include "hphp/runtime/vm/jit/cls-cns-profile.h"
32 #include "hphp/runtime/vm/jit/meth-profile.h"
33 #include "hphp/runtime/vm/jit/profile-refcount.h"
34 #include "hphp/runtime/vm/jit/release-vv-profile.h"
35 #include "hphp/runtime/vm/jit/switch-profile.h"
36 #include "hphp/runtime/vm/jit/type-profile.h"
37 #include "hphp/runtime/vm/jit/containers.h"
38 #include "hphp/runtime/vm/jit/prof-data.h"
39 #include "hphp/runtime/vm/jit/trans-cfg.h"
40 #include "hphp/runtime/vm/unit.h"
42 #include <fstream>
44 namespace HPHP { namespace jit {
45 //////////////////////////////////////////////////////////////////////
47 namespace {
48 //////////////////////////////////////////////////////////////////////
50 TRACE_SET_MOD(hhbc);
52 StaticString s_invoke("__invoke");
53 StaticString s_86ctor("86ctor");
54 StaticString s_86pinit("86pinit");
55 StaticString s_86sinit("86sinit");
57 constexpr uint32_t k86pinitSlot = 0x80000000u;
58 constexpr uint32_t k86sinitSlot = 0x80000001u;
60 template<typename F>
61 auto deserialize(ProfDataDeserializer&ser, F&& f) -> decltype(f()) {
62 using T = decltype(f());
63 auto const ptr = read_raw<uintptr_t>(ser);
64 if (!ptr) return T{};
65 if (ptr & 1) {
66 auto& ent = ser.getEnt(reinterpret_cast<T>(ptr - 1));
67 assertx(!ent);
68 ent = f();
69 assertx(ent);
70 return ent;
72 auto const ent = ser.getEnt(reinterpret_cast<T>(ptr));
73 assertx(ent);
74 return ent;
77 void write_serialized_ptr(ProfDataSerializer& ser, const void* p) {
78 auto const ptr_as_int = reinterpret_cast<uintptr_t>(p);
79 assertx(!(ptr_as_int & 1));
80 write_raw(ser, ptr_as_int | 1);
83 void write_raw_ptr(ProfDataSerializer& ser, const void* p) {
84 auto const ptr_as_int = reinterpret_cast<uintptr_t>(p);
85 assertx(!(ptr_as_int & 1));
86 write_raw(ser, ptr_as_int);
90 * Helper functions so that the function passed to write_container can
91 * take a serializer as a parameter, or skip it (eg if its a lambda
92 * which is already capturing the serializer).
94 template<typename S, typename T, typename F>
95 auto call(F& f, S& ser, const T& t) -> decltype(f(ser, t)) {
96 return f(ser, t);
99 template<typename S, typename T, typename F>
100 auto call(F& f, S&, const T& t) -> decltype(f(t)) {
101 return f(t);
104 template<typename C, typename F>
105 void write_container(ProfDataSerializer& ser, const C& cont, F f) {
106 write_raw(ser, safe_cast<uint32_t>(cont.size()));
107 for (auto const &elm : cont) {
108 call(f, ser, elm);
112 template<typename F>
113 void read_container(ProfDataDeserializer& ser, F f) {
114 auto sz = read_raw<uint32_t>(ser);
115 while (sz--) { f(); }
118 void write_srckey(ProfDataSerializer& ser, SrcKey sk) {
119 ITRACE(2, "SrcKey>\n");
120 if (ser.serialize(sk.func())) {
121 Trace::Indent _i;
122 write_raw(ser, uintptr_t(-1));
123 write_func(ser, sk.func());
125 write_raw(ser, sk.toAtomicInt());
126 ITRACE(2, "SrcKey: {}\n", show(sk));
129 SrcKey read_srckey(ProfDataDeserializer& ser) {
130 ITRACE(2, "SrcKey>\n");
131 auto orig = read_raw<SrcKey::AtomicInt>(ser);
132 if (orig == uintptr_t(-1)) {
133 Trace::Indent _i;
134 read_func(ser);
135 orig = read_raw<SrcKey::AtomicInt>(ser);
137 auto const id = SrcKey::fromAtomicInt(orig).funcID();
138 assertx(uint32_t(orig) == id);
139 auto const sk = SrcKey::fromAtomicInt(orig - id + ser.getFid(id));
140 ITRACE(2, "SrcKey: {}\n", show(sk));
141 return sk;
144 void write_reffiness_pred(ProfDataSerializer& ser,
145 const RegionDesc::ReffinessPred& pred) {
146 write_container(ser, pred.mask, write_raw<bool>);
147 write_container(ser, pred.vals, write_raw<bool>);
148 write_raw(ser, pred.arSpOffset);
151 RegionDesc::ReffinessPred read_reffiness_pred(ProfDataDeserializer& ser) {
152 RegionDesc::ReffinessPred ret;
153 read_container(ser,
154 [&] { ret.mask.push_back(read_raw<bool>(ser)); });
155 read_container(ser,
156 [&] { ret.vals.push_back(read_raw<bool>(ser)); });
157 ret.arSpOffset = read_raw<decltype(ret.arSpOffset)>(ser);
158 return ret;
161 void write_type(ProfDataSerializer& ser, Type t) {
162 t.serialize(ser);
165 Type read_type(ProfDataDeserializer& ser) {
166 return Type::deserialize(ser);
169 void write_typed_location(ProfDataSerializer& ser,
170 const RegionDesc::TypedLocation& loc) {
171 write_raw(ser, loc.location);
172 write_type(ser, loc.type);
175 void write_guarded_location(ProfDataSerializer& ser,
176 const RegionDesc::GuardedLocation& loc) {
177 write_raw(ser, loc.location);
178 write_type(ser, loc.type);
179 write_raw(ser, loc.category);
182 RegionDesc::TypedLocation read_typed_location(ProfDataDeserializer& ser) {
183 auto const location = read_raw<Location>(ser);
184 auto const type = read_type(ser);
185 return { location, type };
188 RegionDesc::GuardedLocation read_guarded_location(ProfDataDeserializer& ser) {
189 auto const location = read_raw<Location>(ser);
190 auto const type = read_type(ser);
191 auto const cat = read_raw<DataTypeCategory>(ser);
192 return { location, type, cat };
195 void write_global_array_map(ProfDataSerializer& ser) {
196 write_container(ser, globalArrayTypeTable(),
197 write_raw<const RepoAuthType::Array*>);
200 void read_global_array_map(ProfDataDeserializer& ser) {
201 auto sz DEBUG_ONLY = read_raw<uint32_t>(ser);
202 assertx(sz == globalArrayTypeTable().size());
203 for (auto arr : globalArrayTypeTable()) {
204 auto const orig = read_raw<const RepoAuthType::Array*>(ser);
205 ser.recordRat(orig, arr);
209 void write_region_block(ProfDataSerializer& ser,
210 const RegionDesc::BlockPtr& block) {
211 write_raw(ser, block->id());
212 write_srckey(ser, block->start());
213 write_raw(ser, block->length());
214 write_raw(ser, block->initialSpOffset());
215 write_raw(ser, block->profTransID());
216 write_container(ser, block->typePredictions(), write_typed_location);
217 write_container(ser, block->typePreConditions(), write_guarded_location);
218 write_container(ser, block->paramByRefs(),
219 [] (ProfDataSerializer& s, std::pair<SrcKey, bool> byRef) {
220 write_srckey(s, byRef.first);
221 write_raw(s, byRef.second);
223 write_container(ser, block->reffinessPreds(), write_reffiness_pred);
224 write_container(ser, block->knownFuncs(),
225 [] (ProfDataSerializer& s,
226 std::pair<SrcKey, const Func*> knownFunc) {
227 write_srckey(s, knownFunc.first);
228 write_func(s, knownFunc.second);
230 write_container(ser, block->postConds().changed, write_typed_location);
231 write_container(ser, block->postConds().refined, write_typed_location);
234 RegionDesc::BlockPtr read_region_block(ProfDataDeserializer& ser) {
235 auto const id = read_raw<RegionDesc::BlockId>(ser);
236 auto const start = read_srckey(ser);
237 auto const length = read_raw<int>(ser);
238 auto const initialSpOffset = read_raw<FPInvOffset>(ser);
240 auto const block = std::make_shared<RegionDesc::Block>(id,
241 start.func(),
242 start.resumeMode(),
243 start.hasThis(),
244 start.offset(),
245 length,
246 initialSpOffset);
248 block->setProfTransID(read_raw<TransID>(ser));
250 read_container(ser,
251 [&] {
252 block->addPredicted(read_typed_location(ser));
255 read_container(ser,
256 [&] {
257 block->addPreCondition(read_guarded_location(ser));
260 read_container(ser,
261 [&] {
262 auto const sk = read_srckey(ser);
263 auto const byRef = read_raw<bool>(ser);
264 block->setParamByRef(sk, byRef);
267 read_container(ser,
268 [&] {
269 block->addReffinessPred(read_reffiness_pred(ser));
272 read_container(ser,
273 [&] {
274 auto const sk = read_srckey(ser);
275 auto const func = read_func(ser);
276 block->setKnownFunc(sk, func);
279 PostConditions postConds;
280 read_container(ser,
281 [&] {
282 postConds.changed.push_back(read_typed_location(ser));
284 read_container(ser,
285 [&] {
286 postConds.refined.push_back(read_typed_location(ser));
288 block->setPostConds(postConds);
289 return block;
292 void write_region_desc(ProfDataSerializer& ser, const RegionDesc* rd) {
293 write_container(ser, rd->blocks(), write_region_block);
294 write_container(ser, findPredTrans(rd->entry()->id(), profData()),
295 [&] (RegionDesc::BlockId id) {
296 write_raw(ser, id);
298 write_container(ser, rd->blocks(),
299 [&] (const RegionDesc::BlockPtr& b) {
300 auto const bid = b->id();
301 write_raw(ser, bid);
302 assertx(rd->succs(bid).empty());
303 assertx(rd->preds(bid).empty());
304 assertx(rd->merged(bid).empty());
305 auto const pr = rd->prevRetrans(bid);
306 write_raw(ser, pr ? pr.value() : kInvalidTransID);
307 auto const nr = rd->nextRetrans(bid);
308 write_raw(ser, nr ? nr.value() : kInvalidTransID);
310 write_type(ser, rd->inlineCtxType());
311 write_container(ser, rd->inlineInputTypes(), write_type);
314 RegionDescPtr read_region_desc(ProfDataDeserializer& ser) {
315 auto ret = std::make_shared<RegionDesc>();
316 read_container(ser, [&] { ret->addBlock(read_region_block(ser)); });
317 RegionDesc::BlockIdSet incoming;
318 read_container(ser,
319 [&] { incoming.insert(read_raw<RegionDesc::BlockId>(ser)); });
320 ret->incoming(std::move(incoming));
322 read_container(ser,
323 [&] {
324 auto const id = read_raw<RegionDesc::BlockId>(ser);
325 auto const pr = read_raw<RegionDesc::BlockId>(ser);
326 auto const nr = read_raw<RegionDesc::BlockId>(ser);
327 if (pr != kInvalidTransID) {
328 ret->setNextRetrans(pr, id);
330 if (nr != kInvalidTransID) {
331 ret->setNextRetrans(id, nr);
334 auto const ty = read_type(ser);
335 std::vector<Type> args;
336 read_container(ser,
337 [&] {
338 args.push_back(read_type(ser));
340 ret->setInlineContext(ty, args);
341 return ret;
344 void write_prof_trans_rec(ProfDataSerializer& ser, const ProfTransRec* ptr) {
345 if (!ptr) return write_raw(ser, TransKind{});
346 write_raw(ser, ptr->kind());
347 write_srckey(ser, ptr->srcKey());
348 if (ptr->kind() == TransKind::Profile) {
349 write_raw(ser, ptr->lastBcOff());
350 write_region_desc(ser, ptr->region().get());
351 } else {
352 // No need to preserve callers; there won't be any when we use this data.
353 write_raw(ser, ptr->prologueArgs());
357 std::unique_ptr<ProfTransRec> read_prof_trans_rec(ProfDataDeserializer& ser) {
358 auto const kind = read_raw<TransKind>(ser);
359 static_assert(TransKind::Profile != TransKind{} &&
360 TransKind::ProfPrologue != TransKind{},
361 "Profile and ProfPrologue must not be zero");
362 if (kind == TransKind{}) return nullptr;
363 auto const sk = read_srckey(ser);
364 if (kind == TransKind::Profile) {
365 auto const lastBcOff = read_raw<Offset>(ser);
366 auto const region = read_region_desc(ser);
367 return std::make_unique<ProfTransRec>(lastBcOff, sk, region);
370 return std::make_unique<ProfTransRec>(sk, read_raw<int>(ser));
373 void write_profiled_funcs(ProfDataSerializer& ser, ProfData* pd) {
374 auto const maxFuncId = pd->maxProfilingFuncId();
376 for (FuncId fid = 0; fid <= maxFuncId; fid++) {
377 if (!Func::isFuncIdValid(fid) || !pd->profiling(fid)) continue;
378 write_func(ser, Func::fromFuncId(fid));
381 write_raw(ser, uintptr_t{});
384 void read_profiled_funcs(ProfDataDeserializer& ser, ProfData* pd) {
385 while (auto const func = read_func(ser)) {
386 pd->setProfiling(func->getFuncId());
390 void write_prof_data(ProfDataSerializer& ser, ProfData* pd) {
391 write_profiled_funcs(ser, pd);
393 write_raw(ser, pd->counterDefault());
394 pd->forEachTransRec(
395 [&] (const ProfTransRec* ptr) {
396 auto const transID = ptr->isProfile() ?
397 ptr->region()->entry()->profTransID() :
398 pd->proflogueTransId(ptr->func(), ptr->prologueArgs());
399 write_raw(ser, transID);
400 write_prof_trans_rec(ser, ptr);
401 // forEachTransRec already grabs a read lock, and we're not
402 // going to add a *new* counter here (so we don't need a write
403 // lock).
404 write_raw(ser, *pd->transCounterAddrNoLock(transID));
407 write_raw(ser, kInvalidTransID);
410 void read_prof_data(ProfDataDeserializer& ser, ProfData* pd) {
411 read_profiled_funcs(ser, pd);
413 pd->resetCounters(read_raw<int64_t>(ser));
414 while (true) {
415 auto const transID = read_raw<TransID>(ser);
416 if (transID == kInvalidTransID) break;
417 pd->addProfTrans(transID, read_prof_trans_rec(ser));
418 *pd->transCounterAddr(transID) = read_raw<int64_t>(ser);
422 template<typename T>
423 auto write_impl(ProfDataSerializer& ser, const T& out, bool) ->
424 decltype(std::declval<T&>().serialize(ser),void()) {
425 out.serialize(ser);
428 template<typename T>
429 void write_impl(ProfDataSerializer& ser, const T& out, int) {
430 write_raw(ser, out);
433 template<typename T>
434 void write_maybe_serializable(ProfDataSerializer& ser, const T& out) {
435 write_impl(ser, out, false);
438 struct TargetProfileVisitor : boost::static_visitor<void> {
439 TargetProfileVisitor(ProfDataSerializer& ser,
440 const rds::Symbol& sym,
441 rds::Handle handle,
442 uint32_t size) :
443 ser{ser},
444 sym{sym},
445 handle{handle},
446 size{size} {}
448 template<typename T>
449 void process(T& out, const StringData* name) {
450 write_raw(ser, size);
451 write_string(ser, name);
452 write_raw(ser, sym);
453 TargetProfile<T>::reduce(out, handle, size);
454 if (size == sizeof(T)) {
455 write_maybe_serializable(ser, out);
456 } else {
457 write_raw(ser, &out, size);
461 template<typename T> void operator()(const T&) {}
462 template<typename T>
463 void operator()(const rds::Profile<T>& pt) {
464 if (size == sizeof(T)) {
465 T out{};
466 process(out, pt.name.get());
467 } else {
468 auto const mem = calloc(1, size);
469 SCOPE_EXIT { free(mem); };
470 process(*reinterpret_cast<T*>(mem), pt.name.get());
474 ProfDataSerializer& ser;
475 const rds::Symbol& sym;
476 rds::Handle handle;
477 uint32_t size;
480 void write_target_profiles(ProfDataSerializer& ser) {
481 rds::visitSymbols(
482 [&] (const rds::Symbol& symbol, rds::Handle handle, uint32_t size) {
483 TargetProfileVisitor tv(ser, symbol, handle, size);
484 boost::apply_visitor(tv, symbol);
487 write_raw(ser, uint32_t{});
490 template<typename T>
491 auto read_impl(ProfDataDeserializer& ser, T& out, bool) ->
492 decltype(out.deserialize(ser),void()) {
493 out.deserialize(ser);
496 template<typename T>
497 void read_impl(ProfDataDeserializer& ser, T& out, int) {
498 read_raw(ser, out);
501 template<typename T>
502 void read_maybe_serializable(ProfDataDeserializer& ser, T& out) {
503 read_impl(ser, out, false);
506 struct SymbolFixup : boost::static_visitor<void> {
507 SymbolFixup(ProfDataDeserializer& ser, StringData* name, uint32_t size) :
508 ser{ser}, name{name}, size{size} {}
510 template<typename T> void operator()(T&) { always_assert(false); }
511 template<typename T>
512 void operator()(rds::Profile<T>& pt) {
513 TargetProfile<T> prof(pt.transId,
514 TransKind::Profile,
515 pt.bcOff,
516 name,
517 size - sizeof(T));
519 if (size == sizeof(T)) {
520 read_maybe_serializable(ser, prof.value());
521 } else {
522 read_raw(ser, &prof.value(), size);
526 ProfDataDeserializer& ser;
527 StringData* name;
528 // The size of the original rds allocation.
529 uint32_t size;
532 void read_target_profiles(ProfDataDeserializer& ser) {
533 while (true) {
534 auto const size = read_raw<uint32_t>(ser);
535 if (!size) break;
536 auto const name = read_string(ser);
537 auto sym = read_raw<rds::Symbol>(ser);
538 auto sf = SymbolFixup{ser, name, size};
539 boost::apply_visitor(sf, sym);
543 ////////////////////////////////////////////////////////////////////////////////
546 ProfDataSerializer::ProfDataSerializer(const std::string& name) : m_ofs(name) {
547 if (!m_ofs.good()) throw std::runtime_error("Failed to open: " + name);
550 ProfDataDeserializer::ProfDataDeserializer(const std::string& name)
551 : m_ifs(name) {
552 if (!m_ifs.good()) throw std::runtime_error("Failed to open: " + name);
555 void write_raw(ProfDataSerializer& ser, const void* data, size_t sz) {
556 if (!ser.m_ofs.write(static_cast<const char*>(data), sz).good()) {
557 throw std::runtime_error("Failed to write serialized data");
561 void read_raw(ProfDataDeserializer& ser, void* data, size_t sz) {
562 if (!ser.m_ifs.read(static_cast<char*>(data), sz).good()) {
563 throw std::runtime_error("Failed to read serialized data");
567 StringData*& ProfDataDeserializer::getEnt(const StringData* p) {
568 return stringMap[uintptr_t(p)];
571 ArrayData*& ProfDataDeserializer::getEnt(const ArrayData* p) {
572 return arrayMap[uintptr_t(p)];
575 Unit*& ProfDataDeserializer::getEnt(const Unit* p) {
576 return unitMap[uintptr_t(p)];
579 Func*& ProfDataDeserializer::getEnt(const Func* p) {
580 return funcMap[uintptr_t(p)];
583 Class*& ProfDataDeserializer::getEnt(const Class* p) {
584 return classMap[uintptr_t(p)];
587 const RepoAuthType::Array*&
588 ProfDataDeserializer::getEnt(const RepoAuthType::Array* p) {
589 return ratMap[uintptr_t(p)];
592 bool ProfDataSerializer::serialize(const Unit* unit) {
593 return unit->serialize();
596 bool ProfDataSerializer::serialize(const Func* func) {
597 return func->serialize();
600 bool ProfDataSerializer::serialize(const Class* cls) {
601 return cls->serialize();
604 void write_string(ProfDataSerializer& ser, const StringData* str) {
605 if (!ser.serialize(str)) return write_raw(ser, str);
606 write_serialized_ptr(ser, str);
607 uint32_t sz = str->size();
608 write_raw(ser, sz);
609 write_raw(ser, str->data(), sz);
612 StringData* read_string(ProfDataDeserializer& ser) {
613 return deserialize(
614 ser,
615 [&] () -> StringData* {
616 auto const sz = read_raw<uint32_t>(ser);
617 String s{sz, ReserveStringMode{}};
618 auto const range = s.bufferSlice();
619 read_raw(ser, range.begin(), sz);
620 s.setSize(sz);
621 return makeStaticString(s);
626 void write_array(ProfDataSerializer& ser, const ArrayData* arr) {
627 if (!ser.serialize(arr)) return write_raw(ser, arr);
628 write_serialized_ptr(ser, arr);
629 auto const str = internal_serialize(VarNR(const_cast<ArrayData*>(arr)));
630 uint32_t sz = str.size();
631 write_raw(ser, sz);
632 write_raw(ser, str.data(), sz);
635 ArrayData* read_array(ProfDataDeserializer& ser) {
636 return deserialize(
637 ser,
638 [&] () -> ArrayData* {
639 auto const sz = read_raw<uint32_t>(ser);
640 String s{sz, ReserveStringMode{}};
641 auto const range = s.bufferSlice();
642 read_raw(ser, range.begin(), sz);
643 s.setSize(sz);
644 auto v = unserialize_from_buffer(
645 s.data(),
646 s.size(),
647 VariableUnserializer::Type::Internal
649 return ArrayData::GetScalarArray(std::move(v));
654 void write_unit(ProfDataSerializer& ser, const Unit* unit) {
655 if (!ser.serialize(unit)) return write_raw(ser, unit);
656 ITRACE(2, "Unit: {}\n", unit->filepath());
657 write_serialized_ptr(ser, unit);
658 write_string(ser, unit->filepath());
661 Unit* read_unit(ProfDataDeserializer& ser) {
662 return deserialize(
663 ser,
664 [&] () -> Unit* {
665 auto const filepath = read_string(ser);
666 ITRACE(2, "Unit: {}\n", filepath);
667 return lookupUnit(filepath, "", nullptr);
672 template<typename C1, typename C2, typename F>
673 void visit_deps(const C1& c1, const C2& c2, F& f) {
674 auto it = c2.begin();
675 auto const DEBUG_ONLY end = c2.end();
676 for (auto const& dep : c1) {
677 assertx(it != end);
678 f(dep.get(), *it++);
682 void write_class(ProfDataSerializer& ser, const Class* cls) {
683 SCOPE_EXIT {
684 ITRACE(2, "Class: {}\n", cls ? cls->name() : staticEmptyString());
686 ITRACE(2, "Class>\n");
687 Trace::Indent _;
689 if (!cls || !ser.serialize(cls)) return write_raw(ser, cls);
691 write_serialized_ptr(ser, cls);
692 write_raw(ser, cls->preClass()->id());
693 write_unit(ser, cls->preClass()->unit());
695 jit::vector<std::pair<const Class*, const StringData*>> dependents;
696 auto record_dep = [&] (const Class* dep, const StringData* depName) {
697 if (!dep) return;
698 if (!dep->wasSerialized() ||
699 !classHasPersistentRDS(dep) ||
700 !dep->name()->isame(depName)) {
701 dependents.emplace_back(dep, depName);
704 record_dep(cls->parent(), cls->preClass()->parent());
706 visit_deps(cls->declInterfaces(), cls->preClass()->interfaces(), record_dep);
708 if (cls->preClass()->attrs() & AttrNoExpandTrait) {
709 for (auto const tName : cls->preClass()->usedTraits()) {
710 auto const trait = Unit::lookupUniqueClassInContext(tName, nullptr);
711 assertx(trait);
712 record_dep(trait, tName);
714 } else {
715 visit_deps(cls->usedTraitClasses(),
716 cls->preClass()->usedTraits(),
717 record_dep);
720 write_container(ser, dependents,
721 [&] (const std::pair<const Class*, const StringData*> &dep) {
722 write_class(ser, dep.first);
723 write_string(ser, dep.second);
726 if (cls->parent() == c_Closure::classof()) {
727 auto const func = cls->lookupMethod(s_invoke.get());
728 assertx(func);
729 write_class(ser, func->cls());
733 Class* read_class(ProfDataDeserializer& ser) {
734 ITRACE(2, "Class>\n");
735 auto const ret = deserialize(
736 ser,
737 [&] () -> Class* {
738 Trace::Indent _;
739 auto const id = read_raw<decltype(std::declval<PreClass*>()->id())>(ser);
740 auto const unit = read_unit(ser);
742 read_container(ser,
743 [&] {
744 auto const dep = read_class(ser);
745 auto const ne = dep->preClass()->namedEntity();
746 // if its not persistent, make sure that dep
747 // is the active class for this NamedEntity
748 assertx(ne->m_cachedClass.bound());
749 if (ne->m_cachedClass.isNormal()) {
750 ne->setCachedClass(dep);
752 auto const depName = read_string(ser);
753 if (!dep->name()->isame(depName)) {
754 // this dependent was referred to via a
755 // class_alias, so we need to make sure
756 // *that* points to the class too
757 auto const aliasNe = NamedEntity::get(depName);
758 aliasNe->m_cachedClass.bind();
759 if (aliasNe->m_cachedClass.isNormal()) {
760 aliasNe->m_cachedClass.markUninit();
762 aliasNe->setCachedClass(dep);
766 auto const preClass = unit->lookupPreClassId(id);
767 auto const ne = preClass->namedEntity();
768 // If its not persistent, make sure its NamedEntity is
769 // unbound, ready for DefClass
770 if (ne->m_cachedClass.bound() &&
771 ne->m_cachedClass.isNormal()) {
772 ne->m_cachedClass.markUninit();
775 auto const cls = Unit::defClass(preClass, true);
776 if (cls->pinitVec().size()) cls->initPropHandle();
777 if (cls->numStaticProperties()) cls->initSPropHandles();
779 if (cls->parent() == c_Closure::classof()) {
780 auto const ctx = read_class(ser);
781 if (ctx != cls) return cls->rescope(ctx);
783 return cls;
787 ITRACE(2, "Class: {}\n", ret ? ret->name() : staticEmptyString());
788 return ret;
791 void write_func(ProfDataSerializer& ser, const Func* func) {
792 SCOPE_EXIT {
793 ITRACE(2, "Func: {}\n", func ? func->fullName() : staticEmptyString());
795 ITRACE(2, "Func>\n");
796 Trace::Indent _;
798 if (!func || !ser.serialize(func)) return write_raw(ser, func);
800 write_serialized_ptr(ser, func);
801 uint32_t fid = func->getFuncId();
802 assertx(!(fid & 0x80000000));
803 if (func == SystemLib::s_nullCtor ||
804 (!func->isMethod() && !func->isPseudoMain() && func->isBuiltin())) {
805 if (func == SystemLib::s_nullCtor) {
806 assertx(func->name()->isame(s_86ctor.get()));
808 fid = ~fid;
809 write_raw(ser, fid);
810 return write_string(ser, func->name());
812 write_raw(ser, fid);
813 if (func->isPseudoMain()) {
814 const uint32_t zero = 0;
815 write_raw(ser, zero);
816 write_unit(ser, func->unit());
817 return write_class(ser, func->cls());
820 if (func->isMethod()) {
821 auto const* cls = func->implCls();
822 auto const nslot = [&] () -> uint32_t {
823 const uint32_t slot = func->methodSlot();
824 if (cls->getMethod(slot) != func) {
825 if (func->name() == s_86pinit.get()) return k86pinitSlot;
826 if (func->name() == s_86sinit.get()) return k86sinitSlot;
827 cls = getOwningClassForFunc(func);
828 assertx(cls->getMethod(slot) == func);
830 return ~slot;
831 }();
832 assertx(nslot & 0x80000000);
833 write_raw(ser, nslot);
834 return write_class(ser, cls);
837 // Ideally we'd write the func's index in its Unit; but we may not
838 // have that after Unit::initial_merge
839 const uint32_t off = func->base();
840 assertx(off && !(off & 0x80000000));
841 write_raw(ser, off);
842 write_unit(ser, func->unit());
845 Func* read_func(ProfDataDeserializer& ser) {
846 ITRACE(2, "Func>\n");
847 auto const ret = deserialize(
848 ser,
849 [&] () -> Func* {
850 Trace::Indent _;
851 auto fid = read_raw<uint32_t>(ser);
852 auto const func = [&] () -> const Func* {
853 if (fid & 0x80000000) {
854 fid = ~fid;
855 auto const name = read_string(ser);
856 if (name->isame(s_86ctor.get())) return SystemLib::s_nullCtor;
857 return Unit::lookupFunc(name);
859 auto const id = read_raw<uint32_t>(ser);
860 if (!id) {
861 auto const unit = read_unit(ser);
862 return unit->getMain(read_class(ser));
864 if (id & 0x80000000) {
865 auto const cls = read_class(ser);
866 if (id == k86pinitSlot) return cls->get86pinit();
867 if (id == k86sinitSlot) return cls->get86sinit();
868 const Slot slot = ~id;
869 return cls->getMethod(slot);
871 auto const unit = read_unit(ser);
872 for (auto const f : unit->funcs()) {
873 if (f->base() == id) {
874 Unit::bindFunc(f);
875 if (!rds::isPersistentHandle(f->funcHandle()) &&
876 (!rds::isHandleInit(f->funcHandle(), rds::NormalTag{}) ||
877 rds::handleToRef<LowPtr<Func>>(f->funcHandle()).get() != f)) {
878 rds::uninitHandle(f->funcHandle());
879 Unit::defFunc(f, false);
881 return f;
884 not_reached();
885 }();
886 ser.recordFid(fid, func->getFuncId());
887 return const_cast<Func*>(func);
890 ITRACE(2, "Func: {}\n", ret ? ret->fullName() : staticEmptyString());
891 return ret;
894 bool serializeProfData(const std::string& filename) {
895 try {
896 ProfDataSerializer ser{filename};
898 Func::s_treadmill = true;
899 hphp_thread_init();
900 hphp_session_init();
901 requestInitProfData();
903 SCOPE_EXIT {
904 requestExitProfData();
905 hphp_context_exit();
906 hphp_session_exit();
907 hphp_thread_exit();
908 Func::s_treadmill = false;
911 write_global_array_map(ser);
913 auto const pd = profData();
914 write_prof_data(ser, pd);
916 write_target_profiles(ser);
918 return true;
919 } catch (std::runtime_error& err) {
920 FTRACE(1, "serializeProfData - Failed: {}\n", err.what());
921 return false;
925 bool deserializeProfData(const std::string& filename) {
926 try {
927 ProfDataDeserializer ser{filename};
929 read_global_array_map(ser);
931 ProfData::Session pds;
932 auto const pd = profData();
933 read_prof_data(ser, pd);
934 pd->setDeserialized();
936 read_target_profiles(ser);
938 return true;
939 } catch (std::runtime_error& err) {
940 FTRACE(1, "deserializeProfData - Failed: {}\n", err.what());
941 return false;
945 //////////////////////////////////////////////////////////////////////