Arquivos
hhvm/hphp/runtime/base/shared_variant.h
T
Kyle Delong a8e3321fbd HPHP/XHP: 'mixed' type in attribute declarations
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##.
2013-07-18 17:28:37 -07:00

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_ */