Use RATs from HHBBC in init_use_vars
[hiphop-php.git] / hphp / runtime / vm / blob-helper.h
blob6f1fcb599ae0fa5a589af19ada377813d2ac7ef3
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 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 #ifndef incl_HPHP_RUNTIME_VM_BLOB_HELPER_H_
18 #define incl_HPHP_RUNTIME_VM_BLOB_HELPER_H_
20 #include <algorithm>
21 #include <cstdlib>
22 #include <limits>
23 #include <type_traits>
24 #include <unordered_set>
25 #include <vector>
27 #include <folly/Optional.h>
28 #include <folly/Varint.h>
30 #include "hphp/runtime/base/builtin-functions.h"
31 #include "hphp/runtime/base/tv-helpers.h"
32 #include "hphp/runtime/base/type-string.h"
33 #include "hphp/runtime/vm/repo.h"
34 #include "hphp/runtime/vm/repo-global-data.h"
37 * This module contains helpers for serializing and deserializing
38 * metadata into blobs suitable for insertion into the hhbc repo.
40 * Types may provide their own serialization logic by implementing a
41 * single-argument member function template called `serde' (as in
42 * "serialization/deserialization"), and pushing data it wants to
43 * serialize into the parameter. Those members may in turn have
44 * customized serialization behavior, or they may "bottom out" to
45 * these helpers if they are basic-enough types.
47 * For example:
49 * struct MyBlobableStuff {
50 * int m_foo;
51 * std::vector<const StringData*> m_strList;
52 * OtherBlobbableData m_other;
54 * template<class SerDe> void serde(SerDe& sd) {
55 * sd(m_foo)(m_strList)(m_other);
56 * }
57 * };
59 * The argument to SerDe will have a static const member called
60 * `deserializing' which can be used to do custom behavior depending
61 * on whether you're deserializing. But generally the goal here
62 * should be to eliminate a class of bugs by having the same (textual)
63 * code implement both serialization and deserialization.
66 namespace HPHP {
68 //////////////////////////////////////////////////////////////////////
71 * Warning: some language abuse below.
73 * This defines a trait that determines whether or not a type T has a
74 * member function template called `serde' that specializes for the
75 * type `SerDe'. The point here is that calling one of the blob
76 * helpers on an object that knows how to do its own serialization
77 * will just reflect back to it.
79 * If you are unlucky enough to need to know how this works, look up
80 * "SFINAE".
83 template<class T, class SerDe>
84 class IsNontrivialSerializable {
85 template<class U, void (U::*)(SerDe&)> struct Checker;
86 template<class U> static char test(Checker<U,&U::template serde<SerDe> >*);
87 template<class> static long test(...);
88 public:
89 enum { value = sizeof(test<T>(0)) == 1 };
92 //////////////////////////////////////////////////////////////////////
94 struct BlobEncoder {
95 static const bool deserializing = false;
98 * Currently the most basic encoder/decode only works for integral
99 * types. (We don't want this to accidentally get used for things
100 * like pointers or aggregates.)
102 * Floating point support could be added later if we need it ...
104 template<class T>
105 typename std::enable_if<
106 std::is_integral<T>::value ||
107 std::is_enum<T>::value
108 >::type
109 encode(const T& t) {
110 const size_t start = m_blob.size();
111 unsigned char buf[folly::kMaxVarintLength64];
112 uint64_t value = uint64_t{
113 static_cast<typename std::make_unsigned<T>::type>(t)};
114 size_t buf_size = folly::encodeVarint(value, buf);
116 m_blob.resize(start + buf_size);
118 std::copy(buf, buf + buf_size, &m_blob[start]);
121 template<class T>
122 typename std::enable_if<
123 IsNontrivialSerializable<T,BlobEncoder>::value
124 >::type encode(const T& t) {
125 const_cast<T&>(t).serde(*this);
128 void encode(bool b) {
129 encode(b ? 1 : 0);
132 void encode(DataType t) {
133 // always encode DataType as int8 even if it's a bigger size.
134 assert(DataType(int8_t(t)) == t);
135 encode(int8_t(t));
138 void encode(const StringData* sd) {
139 if (!sd) { return encode(uint32_t(0)); }
140 uint32_t sz = sd->size();
141 encode(sz + 1);
142 if (!sz) { return; }
144 const size_t start = m_blob.size();
145 m_blob.resize(start + sz);
146 std::copy(sd->data(), sd->data() + sz, &m_blob[start]);
149 void encode(const RepoAuthType::Array* ar) {
150 if (!ar) return encode(std::numeric_limits<uint32_t>::max());
151 encode(ar->id());
154 void encode(const TypedValue& tv) {
155 if (tv.m_type == KindOfUninit) {
156 return encode(staticEmptyString());
158 String s = f_serialize(tvAsCVarRef(&tv));
159 encode(s.get());
162 void encode(const TypedValueAux& tv) = delete;
164 template<class T>
165 void encode(const folly::Optional<T>& opt) {
166 const bool some = opt.hasValue();
167 encode(some);
168 if (some) encode(*opt);
171 template<class K, class V>
172 void encode(const std::pair<K,V>& kv) {
173 encode(kv.first);
174 encode(kv.second);
177 template<class T>
178 void encode(const std::vector<T>& vec) {
179 encodeContainer(vec, "vector");
182 template<class K, class V, class H, class C>
183 void encode(const hphp_hash_map<K,V,H,C>& map) {
184 encodeContainer(map, "map");
187 template<class V, class H, class C>
188 void encode(const hphp_hash_set<V,H,C>& set) {
189 encodeContainer(set, "set");
192 template<class V, class H, class C>
193 void encode(const std::unordered_set<V,H,C>& set) {
194 encodeContainer(set, "set");
197 template<class T>
198 BlobEncoder& operator()(const T& t) {
199 encode(t);
200 return *this;
203 size_t size() const { return m_blob.size(); }
204 const void* data() const { return &m_blob[0]; }
206 private:
207 template<class Cont>
208 void encodeContainer(Cont& cont, const char* desc) {
209 if (cont.size() >= 0xffffffffu) {
210 throw std::runtime_error("maximum " + std::string(desc) +
211 " size exceeded in BlobEncoder");
213 encode(uint32_t(cont.size()));
214 typedef typename Cont::const_iterator iter;
215 for (iter it = cont.begin(); it != cont.end(); ++it) {
216 encode(*it);
220 private:
221 std::vector<char> m_blob;
224 //////////////////////////////////////////////////////////////////////
226 struct BlobDecoder {
227 static const bool deserializing = true;
229 explicit BlobDecoder(const void* vp, size_t sz)
230 : m_p(static_cast<const unsigned char*>(vp))
231 , m_last(m_p + sz)
234 void assertDone() {
235 assert(m_p >= m_last);
238 // See encode() in BlobEncoder for why this only allows integral
239 // types.
240 template<class T>
241 typename std::enable_if<
242 std::is_integral<T>::value ||
243 std::is_enum<T>::value
244 >::type
245 decode(T& t) {
246 folly::ByteRange range(m_p, m_last);
247 t = static_cast<T>(folly::decodeVarint(range));
248 m_p = range.begin();
251 template<class T>
252 typename std::enable_if<
253 IsNontrivialSerializable<T,BlobEncoder>::value
254 >::type decode(T& t) {
255 t.serde(*this);
258 void decode(DataType& t) {
259 // always decode DataType as int8 even if it's a bigger size.
260 int8_t t2;
261 decode(t2);
262 t = DataType(t2);
265 void decode(const StringData*& sd) {
266 String s(decodeString());
267 sd = s.get() ? makeStaticString(s) : 0;
270 void decode(LowStringPtr& s) {
271 const StringData* sd;
272 decode(sd);
273 s = sd;
276 void decode(const RepoAuthType::Array*& ar) {
277 uint32_t id;
278 decode(id);
279 ar = id == std::numeric_limits<uint32_t>::max()
280 ? nullptr
281 : Repo::get().global().arrayTypeTable.lookup(id);
284 void decode(TypedValue& tv) {
285 tvWriteUninit(&tv);
287 String s = decodeString();
288 assert(!!s);
289 if (s.empty()) return;
291 tvAsVariant(&tv) = unserialize_from_string(s);
292 tvAsVariant(&tv).setEvalScalar();
295 void decode(TypedValueAux& tv) = delete;
297 template<class T>
298 void decode(folly::Optional<T>& opt) {
299 bool some;
300 decode(some);
302 if (!some) {
303 opt = folly::none;
304 } else {
305 T value;
306 decode(value);
307 opt = value;
311 template<class K, class V>
312 void decode(std::pair<K,V>& val) {
313 decode(val.first);
314 decode(val.second);
317 template<class T>
318 void decode(std::vector<T>& vec) {
319 uint32_t size;
320 decode(size);
321 for (uint32_t i = 0; i < size; ++i) {
322 vec.push_back(T());
323 decode(vec.back());
327 template<class K, class V, class H, class C>
328 void decode(hphp_hash_map<K,V,H,C>& map) {
329 uint32_t size;
330 decode(size);
331 for (uint32_t i = 0; i < size; ++i) {
332 std::pair<K,V> val;
333 decode(val);
334 map.insert(val);
338 template<class V, class H, class C>
339 void decode(hphp_hash_set<V,H,C>& set) {
340 uint32_t size;
341 decode(size);
342 for (uint32_t i = 0; i < size; ++i) {
343 V val;
344 decode(val);
345 set.insert(val);
349 template<class V, class H, class C>
350 void decode(std::unordered_set<V,H,C>& set) {
351 uint32_t size;
352 decode(size);
353 for (uint32_t i = 0; i < size; ++i) {
354 V val;
355 decode(val);
356 set.insert(val);
360 template<class T>
361 BlobDecoder& operator()(T& t) {
362 decode(t);
363 return *this;
366 private:
367 String decodeString() {
368 uint32_t sz;
369 decode(sz);
370 if (sz == 0) return String();
371 sz--;
372 if (sz == 0) return empty_string();
374 String s = String(sz, ReserveString);
375 char* pch = s.mutableData();
376 assert(m_last - m_p >= sz);
377 std::copy(m_p, m_p + sz, pch);
378 m_p += sz;
379 s.setSize(sz);
380 return s;
383 private:
384 const unsigned char* m_p;
385 const unsigned char* const m_last;
388 //////////////////////////////////////////////////////////////////////
392 #endif