a8e3321fbd
We'd like to start using ##mixed## instead of ##var## for attribute types to be consistent with Hack. As a followup to this (once released), we would codemod all ##var## to ##mixed##.
245 linhas
7.3 KiB
C++
245 linhas
7.3 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.00 of the Zend license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_SHARED_VARIANT_H_
|
|
#define incl_HPHP_SHARED_VARIANT_H_
|
|
|
|
#include "hphp/runtime/base/types.h"
|
|
#include "hphp/util/lock.h"
|
|
#include "hphp/util/hash.h"
|
|
#include "hphp/util/atomic.h"
|
|
#include "hphp/runtime/base/complex_types.h"
|
|
#include "hphp/runtime/base/immutable_map.h"
|
|
#include "hphp/runtime/base/immutable_obj.h"
|
|
|
|
#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
|
|
# if defined(__LITTLE_ENDIAN__)
|
|
# undef WORDS_BIGENDIAN
|
|
# else
|
|
# if defined(__BIG_ENDIAN__)
|
|
# define WORDS_BIGENDIAN
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class SharedMap;
|
|
class SharedVariantStats;
|
|
class VectorData;
|
|
class ImmutableMap;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class SharedVariant {
|
|
public:
|
|
SharedVariant(CVarRef source, bool serialized, bool inner = false,
|
|
bool unserializeObj = false);
|
|
~SharedVariant();
|
|
|
|
bool is(DataType d) const { return m_type == d; }
|
|
DataType getType() const { return (DataType)m_type; }
|
|
CVarRef asCVarRef() const {
|
|
// Must be non-refcounted types
|
|
assert(m_flags == 0);
|
|
assert(!IS_REFCOUNTED_TYPE(m_tv.m_type));
|
|
return tvAsCVarRef(&m_tv);
|
|
}
|
|
|
|
Variant toLocal();
|
|
|
|
int64_t intData() const {
|
|
assert(is(KindOfInt64));
|
|
return m_data.num;
|
|
}
|
|
|
|
const char *stringData() const {
|
|
assert(is(KindOfString) || is(KindOfStaticString));
|
|
return m_data.str->data();
|
|
}
|
|
|
|
size_t stringLength() const {
|
|
assert(is(KindOfString) || is(KindOfStaticString));
|
|
return m_data.str->size();
|
|
}
|
|
|
|
strhash_t stringHash() const {
|
|
assert(is(KindOfString) || is(KindOfStaticString));
|
|
return m_data.str->hash();
|
|
}
|
|
|
|
// implementing LeakDetectable
|
|
void dump(std::string &out);
|
|
|
|
void getStats(SharedVariantStats *stats) const;
|
|
int32_t getSpaceUsage() const;
|
|
|
|
StringData *getStringData() const {
|
|
assert(is(KindOfString) || is(KindOfStaticString));
|
|
return m_data.str;
|
|
}
|
|
|
|
SharedVariant *convertObj(CVarRef var);
|
|
bool isUnserializedObj() { return getIsObj(); }
|
|
|
|
private:
|
|
/*
|
|
* Keep the object layout binary compatible with Variant for primitive types.
|
|
* We want to have compile time assertion to guard it but still want to have
|
|
* anonymous struct. For non-refcounted types, m_flags is
|
|
* guaranteed to be 0, and other parts of runtime will not touch the count.
|
|
*/
|
|
|
|
union SharedData {
|
|
int64_t num;
|
|
double dbl;
|
|
StringData *str;
|
|
ImmutableMap* map;
|
|
VectorData* vec;
|
|
ImmutableObj* obj;
|
|
};
|
|
|
|
union {
|
|
TypedValue m_tv;
|
|
struct {
|
|
#if PACKED_TV
|
|
uint8_t _typePad;
|
|
DataType m_type;
|
|
uint16_t m_flags;
|
|
uint32_t m_count;
|
|
SharedData m_data;
|
|
#else
|
|
#ifdef WORDS_BIGENDIAN
|
|
SharedData m_data;
|
|
uint32_t m_count;
|
|
uint16_t m_flags;
|
|
uint16_t m_type;
|
|
#else
|
|
SharedData m_data;
|
|
uint32_t m_count;
|
|
uint16_t m_type;
|
|
uint16_t m_flags;
|
|
#endif
|
|
#endif
|
|
};
|
|
};
|
|
|
|
const static uint8_t SerializedArray = (1<<0);
|
|
const static uint8_t IsVector = (1<<1);
|
|
const static uint8_t IsObj = (1<<2);
|
|
const static uint8_t ObjAttempted = (1<<3);
|
|
|
|
static void compileTimeAssertions() {
|
|
static_assert(offsetof(SharedVariant, m_data) == offsetof(TypedValue, m_data),
|
|
"Offset of m_data must be equal in SharedVar and TypedValue");
|
|
static_assert(offsetof(SharedVariant, m_count) == TypedValueAux::auxOffset,
|
|
"Offset of m_count must equal offset of TV.m_aux");
|
|
static_assert(offsetof(SharedVariant, m_type) == offsetof(TypedValue, m_type),
|
|
"Offset of m_type must be equal in SharedVar and TypedValue");
|
|
static_assert(sizeof(SharedVariant) == sizeof(TypedValue),
|
|
"Be careful with field layout");
|
|
}
|
|
|
|
bool getSerializedArray() const { return (bool)(m_flags & SerializedArray);}
|
|
void setSerializedArray() { m_flags |= SerializedArray;}
|
|
void clearSerializedArray() { m_flags &= ~SerializedArray;}
|
|
|
|
void setIsVector() { m_flags |= IsVector;}
|
|
void clearIsVector() { m_flags &= ~IsVector;}
|
|
|
|
bool getIsObj() const { return (bool)(m_flags & IsObj);}
|
|
void setIsObj() { m_flags |= IsObj;}
|
|
void clearIsObj() { m_flags &= ~IsObj;}
|
|
|
|
bool getObjAttempted() const { return (bool)(m_flags & ObjAttempted);}
|
|
void setObjAttempted() { m_flags |= ObjAttempted;}
|
|
void clearObjAttempted() { m_flags &= ~ObjAttempted;}
|
|
|
|
public:
|
|
bool getIsVector() const { return (bool)(m_flags & IsVector);}
|
|
ImmutableMap* getMap() const { return m_data.map; }
|
|
};
|
|
|
|
/* VectorData is used when when all the keys are integers
|
|
* in the sequential range 0 to n-1. */
|
|
class VectorData {
|
|
public:
|
|
union {
|
|
size_t m_size;
|
|
SharedVariant* m_align_dummy;
|
|
};
|
|
|
|
VectorData() : m_size(0) {}
|
|
|
|
~VectorData() {
|
|
SharedVariant* v = vals();
|
|
for (size_t i = 0; i < m_size; i++) {
|
|
v[i].~SharedVariant();
|
|
}
|
|
}
|
|
SharedVariant* getValue(ssize_t pos) {
|
|
return &((SharedVariant *)(this + 1))[pos];
|
|
}
|
|
SharedVariant* vals() { return (SharedVariant*)(this + 1); }
|
|
void *operator new(size_t sz, int num) {
|
|
assert(sz == sizeof(VectorData));
|
|
return malloc(sizeof(VectorData) + num * sizeof(SharedVariant));
|
|
}
|
|
void add(CVarRef val, bool unserializeObj) {
|
|
/* placement new */
|
|
new (&vals()[m_size++]) SharedVariant(val, false, true, unserializeObj);
|
|
}
|
|
void operator delete(void* ptr) { free(ptr); }
|
|
// just to keep the compiler happy; used if the constructor throws
|
|
void operator delete(void* ptr, int num) { free(ptr); }
|
|
};
|
|
|
|
class SharedVariantStats {
|
|
public:
|
|
int32_t dataSize;
|
|
int32_t dataTotalSize;
|
|
int32_t variantCount;
|
|
|
|
void initStats() {
|
|
variantCount = 0;
|
|
dataSize = 0;
|
|
dataTotalSize = 0;
|
|
}
|
|
|
|
SharedVariantStats() {
|
|
initStats();
|
|
}
|
|
|
|
void addChildStats(const SharedVariantStats *childStats) {
|
|
dataSize += childStats->dataSize;
|
|
dataTotalSize += childStats->dataTotalSize;
|
|
variantCount += childStats->variantCount;
|
|
}
|
|
|
|
void removeChildStats(const SharedVariantStats *childStats) {
|
|
dataSize -= childStats->dataSize;
|
|
dataTotalSize -= childStats->dataTotalSize;
|
|
variantCount -= childStats->variantCount;
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
#endif /* incl_HPHP_SHARED_VARIANT_H_ */
|