Add varray support to the serializer
[hiphop-php.git] / hphp / runtime / base / variable-serializer.h
blobd3f8338cb08a860597f200f4a898540b693f3b34
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 #ifndef incl_HPHP_VARIABLE_SERIALIZER_H_
18 #define incl_HPHP_VARIABLE_SERIALIZER_H_
20 #include "hphp/runtime/base/string-buffer.h"
21 #include "hphp/runtime/base/string-data.h"
22 #include "hphp/runtime/base/runtime-option.h"
23 #include "hphp/runtime/base/req-containers.h"
24 #include "hphp/runtime/base/tv-mutate.h"
25 #include "hphp/runtime/base/tv-variant.h"
26 #include "hphp/runtime/vm/class.h"
28 #include <boost/noncopyable.hpp>
30 namespace HPHP {
31 ///////////////////////////////////////////////////////////////////////////////
33 /**
34 * Maintaining states during serialization of a variable. We use this single
35 * class to uniformly serialize variables according to different formats.
37 struct VariableSerializer {
38 /**
39 * Supported formats.
41 enum class Type {
42 PrintR, //print_r()
43 VarExport, //var_export()
44 VarDump, //var_dump()
45 DebugDump, //debug_zval_dump()
46 DebuggerDump, //used by hphp debugger to obtain user visible output
47 Serialize, // serialize()
48 JSON, //json_encode()
49 APCSerialize, //used in APC serialization (controlled by switch)
50 DebuggerSerialize, //used by hphp debugger for client<->proxy communication
51 PHPOutput, //used by compiler to output scalar values into byte code
54 /**
55 * Constructor and destructor.
57 explicit VariableSerializer(Type type, int option = 0, int maxRecur = 3);
58 ~VariableSerializer();
59 VariableSerializer(const VariableSerializer&) = delete;
60 VariableSerializer& operator=(const VariableSerializer&) = delete;
62 // Use UnlimitSerializationScope to suspend this temporarily.
63 static __thread int64_t serializationSizeLimit;
65 /**
66 * Top level entry function called by f_ functions.
68 String serialize(const Variant& v, bool ret, bool keepCount = false);
69 String serializeValue(const Variant& v, bool limit);
71 // Serialize with limit size of output, always return the serialized string.
72 // It does not work with Serialize, JSON, APCSerialize, DebuggerSerialize.
73 String serializeWithLimit(const Variant& v, int limit);
75 // for ext_json
76 void setDepthLimit(size_t depthLimit) { m_maxDepth = depthLimit; }
77 // for ext_std_variable
78 void incMaxCount() { m_maxCount++; }
80 Type getType() const { return m_type; }
82 enum class ArrayKind { PHP, Dict, Vec, Keyset, VArray };
84 private:
85 /**
86 * Type specialized output functions.
88 void write(bool v);
89 void write(char v) { write((int64_t)v);}
90 void write(short v) { write((int64_t)v);}
91 void write(int v) { write((int64_t)v);}
92 void write(int64_t v);
93 void write(double v);
95 void write(const char *v, int len = -1, bool isArrayKey = false,
96 bool noQuotes = false);
98 void write(const String& v);
99 void write(const Object& v);
100 void write(const Variant& v, bool isArrayKey = false);
102 void writeNull();
103 // what to write if recursive level is over limit?
104 void writeOverflow(const TypedValue& tv);
105 void writeRefCount(); // for DebugDump only
107 void writeArrayHeader(int size, bool isVectorData, ArrayKind kind);
108 void writeArrayKey(const Variant& key, ArrayKind kind);
109 void writeArrayValue(
110 const Variant& value,
111 ArrayKind kind
113 void writeCollectionKey(
114 const Variant& key,
115 ArrayKind kind
117 void writeArrayFooter(ArrayKind kind);
118 void writeSerializableObject(const String& clsname, const String& serialized);
121 * Helpers.
123 void indent();
124 void setReferenced(bool referenced) { m_referenced = referenced;}
125 void setRefCount(int count) { m_refCount = count;}
126 bool incNestedLevel(const TypedValue& tv);
127 void decNestedLevel(const TypedValue& tv);
128 void pushObjectInfo(const String& objClass, int objId, char objCode);
129 void popObjectInfo();
130 void pushResourceInfo(const String& rsrcName, int rsrcId);
131 void popResourceInfo();
133 // Sentinel used to indicate that a member of SavedRefMap has a count but no ID.
134 static constexpr int NO_ID = -1;
136 struct SavedRefMap {
137 ~SavedRefMap();
139 struct MapData : boost::noncopyable {
140 MapData() : m_count(0), m_id(-1) { }
141 int m_count;
142 int m_id;
145 MapData& operator[](const TypedValue& tv) {
146 auto& elm = m_mapping[tv];
147 if (!elm.m_count) tvIncRefGen(tv);
148 return elm;
151 const MapData& operator[](const TypedValue& tv) const {
152 return m_mapping.at(tv);
155 private:
156 struct TvHash {
157 std::size_t operator()(const TypedValue& tv) const {
158 return pointer_hash<void>()(tv.m_data.parr);
162 struct TvEq {
163 bool operator()(const TypedValue& a, const TypedValue& b) const {
164 return a.m_data.parr == b.m_data.parr;
168 req::hash_map<TypedValue, MapData, TvHash, TvEq> m_mapping;
171 Type m_type;
172 int m_option; // type specific extra options
173 StringBuffer *m_buf;
174 int m_indent;
175 SavedRefMap m_refs; // reference ids and counts for objs/arrays
176 int m_valueCount; // Current ref index
177 bool m_referenced; // mark current array element as reference
178 int m_refCount; // current variable's reference count
179 String m_objClass; // for object serialization
180 int m_objId; // for object serialization
181 char m_objCode; // for object serialization
182 String m_rsrcName; // for resource serialization
183 int m_rsrcId; // for resource serialization
184 int m_maxCount; // for max recursive levels
185 int m_levelDebugger; // keep track of levels for DebuggerSerialize
186 int m_maxLevelDebugger; // for max level of DebuggerSerialize
187 size_t m_currentDepth; // current depth (nasted objects/arrays)
188 size_t m_maxDepth; // max depth limit before an error (0 -> none)
190 struct ArrayInfo {
191 bool is_object; // nested arrays or objects
192 bool is_vector; // whether current array is a vector
193 bool first_element; // whether this is first array element
194 int indent_delta; // the extra indent to serialize this object
195 int size; // the number of elements in the array
197 req::vector<ArrayInfo> m_arrayInfos;
199 struct ObjectInfo {
200 String objClass;
201 int objId;
202 char objCode;
203 String rsrcName;
204 int rsrcId;
206 req::vector<ObjectInfo> m_objectInfos;
208 // The func parameter will be invoked only if there is no overflow.
209 // Otherwise, writeOverflow will be invoked instead.
210 void preventOverflow(const Object& v, const std::function<void()>& func);
211 void writePropertyKey(const String& prop);
213 void serializeRef(const TypedValue* tv, bool isArrayKey);
214 // Serialize a Variant recursively.
215 // The last param noQuotes indicates to serializer to not put the output in
216 // double quotes (used when printing the output of a __toDebugDisplay() of
217 // an object when it is a string.
218 void serializeVariant(const Variant&,
219 bool isArrayKey = false,
220 bool skipNestCheck = false,
221 bool noQuotes = false);
222 void serializeObject(const Object&);
223 void serializeObject(const ObjectData*);
224 void serializeObjectImpl(const ObjectData* obj);
225 void serializeCollection(ObjectData* obj);
226 void serializeArray(const Array&, bool isObject = false);
227 void serializeArray(const ArrayData*, bool skipNestCheck = false);
228 void serializeArrayImpl(const ArrayData* arr);
229 void serializeResource(const ResourceData*);
230 void serializeResourceImpl(const ResourceData* res);
231 void serializeString(const String&);
233 Array getSerializeProps(const ObjectData* obj) const;
236 // TODO: Move to util/folly?
237 template<typename T> struct TmpAssign {
238 TmpAssign(T& v, const T tmp) : cur(v), save(cur) { cur = tmp; }
239 ~TmpAssign() { cur = save; }
240 T& cur;
241 const T save;
244 struct UnlimitSerializationScope {
245 static constexpr int32_t kTmpLimit = StringData::MaxSize;
246 TmpAssign<int64_t> v{VariableSerializer::serializationSizeLimit, kTmpLimit};
247 TmpAssign<int64_t> rs{RuntimeOption::SerializationSizeLimit, kTmpLimit};
248 TmpAssign<int32_t> rm{RuntimeOption::MaxSerializedStringSize, kTmpLimit};
251 extern const StaticString s_serializedNativeDataKey;
253 ///////////////////////////////////////////////////////////////////////////////
256 #endif // incl_HPHP_VARIABLE_SERIALIZER_H_