Merge ObjectData and Instance together, part 1
When object support was first added to HHVM, a class named "Instance" was introduced (deriving from ObjectData) to represent instances of user defined classes. Since then, things have evolved and HPHPc and HPHPi have been retired, and now there really is no needed to have ObjectData and Instance be separate classes anymore. As a first step towards merging ObjectData and Instance together, this diff puts their definitions in the same .h file and puts their implementations in the same .cpp file. A few small changes were necessary to fix issues with cyclical includes: (1) Repo/emitter related parts of class.cpp and class.h were moved to class-emit.cpp and class-emit.h; (2) the contents of "vm/core_types.h" was moved to "base/types.h"; and (3) a few functions that didn't appear to be hot were moved from .h files and the corresponding .cpp files.
Esse commit está contido em:
@@ -90,6 +90,7 @@
|
||||
#include "hphp/runtime/base/program_functions.h"
|
||||
#include "hphp/runtime/base/file_repository.h"
|
||||
#include "hphp/runtime/ext_hhvm/ext_hhvm.h"
|
||||
#include "hphp/runtime/vm/preclass-emit.h"
|
||||
|
||||
#include "hphp/system/systemlib.h"
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "hphp/compiler/analysis/peephole.h"
|
||||
#include "hphp/compiler/analysis/emitter.h"
|
||||
#include "hphp/runtime/vm/preclass-emit.h"
|
||||
|
||||
namespace HPHP { namespace Compiler {
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "hphp/runtime/base/tv_helpers.h"
|
||||
#include "hphp/runtime/base/type_variant.h"
|
||||
#include "hphp/runtime/base/array/array_inline.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
|
||||
#undef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hphp/runtime/base/server/virtual_host.h"
|
||||
#include "hphp/runtime/base/runtime_option.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
#include "hphp/util/logger.h"
|
||||
#include "hphp/util/process.h"
|
||||
#include "hphp/util/util.h"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/base/file/file_stream_wrapper.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/file/plain_file.h"
|
||||
#include "hphp/runtime/base/server/static_content_cache.h"
|
||||
#include <memory>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/base/file/php_stream_wrapper.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/file/plain_file.h"
|
||||
#include "hphp/runtime/base/file/temp_file.h"
|
||||
#include "hphp/runtime/base/file/mem_file.h"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "hphp/runtime/base/file/ssl_socket.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/util/util.h"
|
||||
#include <poll.h>
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/base/file/user_file.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/ext/ext_function.h"
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
#include "hphp/runtime/vm/jit/translator-inline.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hphp/runtime/base/externals.h"
|
||||
#include "hphp/runtime/base/variable_serializer.h"
|
||||
#include "hphp/runtime/base/execution_context.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/util/lock.h"
|
||||
#include "hphp/runtime/base/class_info.h"
|
||||
#include "hphp/runtime/ext/ext_closure.h"
|
||||
@@ -27,6 +28,10 @@
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/ext/ext_simplexml.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/member_operations.h"
|
||||
#include "hphp/runtime/vm/object_allocator_sizes.h"
|
||||
#include "hphp/runtime/vm/jit/translator-inline.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -118,6 +123,10 @@ bool ObjectData::o_instanceof(CStrRef s) const {
|
||||
return m_cls->classof(cls);
|
||||
}
|
||||
|
||||
void ObjectData::raiseObjToIntNotice(const char* clsName) {
|
||||
raise_notice("Object of class %s could not be converted to int", clsName);
|
||||
}
|
||||
|
||||
bool ObjectData::o_toBooleanImpl() const noexcept {
|
||||
not_reached();
|
||||
}
|
||||
@@ -833,4 +842,810 @@ size_t object_alloc_index_to_size(int idx) {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static StaticString s___get(LITSTR_INIT("__get"));
|
||||
static StaticString s___set(LITSTR_INIT("__set"));
|
||||
static StaticString s___isset(LITSTR_INIT("__isset"));
|
||||
static StaticString s___unset(LITSTR_INIT("__unset"));
|
||||
|
||||
TRACE_SET_MOD(runtime);
|
||||
|
||||
int HPHP::Instance::ObjAllocatorSizeClassCount =
|
||||
HPHP::InitializeAllocators();
|
||||
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps) {
|
||||
auto* dst = propVec;
|
||||
auto* src = propData;
|
||||
for (; src != propData + nProps; ++src, ++dst) {
|
||||
*dst = *src;
|
||||
// m_aux.u_deepInit is true for properties that need "deep" initialization
|
||||
if (src->deepInit()) {
|
||||
tvIncRef(dst);
|
||||
collectionDeepCopyTV(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::raiseAbstractClassError(Class* cls) {
|
||||
Attr attrs = cls->attrs();
|
||||
raise_error("Cannot instantiate %s %s",
|
||||
(attrs & AttrInterface) ? "interface" :
|
||||
(attrs & AttrTrait) ? "trait" : "abstract class",
|
||||
cls->preClass()->name()->data());
|
||||
}
|
||||
|
||||
TypedValue* Instance::propVec() {
|
||||
uintptr_t ret = (uintptr_t)this + sizeof(ObjectData) + builtinPropSize();
|
||||
// TODO(#1432007): some builtins still do not have TypedValue-aligned sizes.
|
||||
assert(ret % sizeof(TypedValue) == builtinPropSize() % sizeof(TypedValue));
|
||||
return (TypedValue*) ret;
|
||||
}
|
||||
|
||||
const TypedValue* Instance::propVec() const {
|
||||
return const_cast<Instance*>(this)->propVec();
|
||||
}
|
||||
|
||||
Instance* Instance::callCustomInstanceInit() {
|
||||
static StringData* sd_init = StringData::GetStaticString("__init__");
|
||||
const Func* init = m_cls->lookupMethod(sd_init);
|
||||
if (init != nullptr) {
|
||||
TypedValue tv;
|
||||
// We need to incRef/decRef here because we're still a new (_count
|
||||
// == 0) object and invokeFunc is going to expect us to have a
|
||||
// reasonable refcount.
|
||||
try {
|
||||
incRefCount();
|
||||
g_vmContext->invokeFuncFew(&tv, init, this);
|
||||
decRefCount();
|
||||
assert(!IS_REFCOUNTED_TYPE(tv.m_type));
|
||||
} catch (...) {
|
||||
this->setNoDestruct();
|
||||
decRefObj(this);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void Instance::operator delete(void* p) {
|
||||
Instance* this_ = (Instance*)p;
|
||||
Class* cls = this_->getVMClass();
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
// cppext classes have their own implementation of delete
|
||||
assert(this_->builtinPropSize() == 0);
|
||||
TypedValue* propVec = (TypedValue *)((uintptr_t)this_ + sizeof(ObjectData));
|
||||
for (unsigned i = 0; i < nProps; ++i) {
|
||||
TypedValue* prop = &propVec[i];
|
||||
tvRefcountedDecRef(prop);
|
||||
}
|
||||
DELETEOBJSZ(sizeForNProps(nProps))(this_);
|
||||
}
|
||||
|
||||
HOT_FUNC_VM
|
||||
Instance* Instance::newInstanceRaw(Class* cls, int idx) {
|
||||
Instance* obj = (Instance*)ALLOCOBJIDX(idx);
|
||||
new (obj) Instance(cls, NoInit::noinit);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Instance::invokeUserMethod(TypedValue* retval, const Func* method,
|
||||
CArrRef params) {
|
||||
g_vmContext->invokeFunc(retval, method, params, this);
|
||||
}
|
||||
|
||||
Object Instance::FromArray(ArrayData *properties) {
|
||||
Instance* retval = Instance::newInstance(SystemLib::s_stdclassClass);
|
||||
retval->initDynProps();
|
||||
HphpArray* props = static_cast<HphpArray*>(retval->o_properties.get());
|
||||
for (ssize_t pos = properties->iter_begin(); pos != ArrayData::invalid_index;
|
||||
pos = properties->iter_advance(pos)) {
|
||||
TypedValue* value = properties->nvGetValueRef(pos);
|
||||
TypedValue key;
|
||||
properties->nvGetKey(&key, pos);
|
||||
if (key.m_type == KindOfInt64) {
|
||||
props->set(key.m_data.num, tvAsCVarRef(value), false);
|
||||
} else {
|
||||
assert(IS_STRING_TYPE(key.m_type));
|
||||
StringData* strKey = key.m_data.pstr;
|
||||
props->set(strKey, tvAsCVarRef(value), false);
|
||||
decRefStr(strKey);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Instance::initDynProps(int numDynamic /* = 0 */) {
|
||||
// Create o_properties with room for numDynamic
|
||||
o_properties.asArray() = ArrayData::Make(numDynamic);
|
||||
}
|
||||
|
||||
Slot Instance::declPropInd(TypedValue* prop) const {
|
||||
// Do an address range check to determine whether prop physically resides
|
||||
// in propVec.
|
||||
const TypedValue* pv = propVec();
|
||||
if (prop >= pv && prop < &pv[m_cls->numDeclProperties()]) {
|
||||
return prop - pv;
|
||||
} else {
|
||||
return kInvalidSlot;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool declOnly>
|
||||
TypedValue* Instance::getPropImpl(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible,
|
||||
bool& unset) {
|
||||
TypedValue* prop = nullptr;
|
||||
unset = false;
|
||||
Slot propInd = m_cls->getDeclPropIndex(ctx, key, accessible);
|
||||
visible = (propInd != kInvalidSlot);
|
||||
if (propInd != kInvalidSlot) {
|
||||
// We found a visible property, but it might not be accessible.
|
||||
// No need to check if there is a dynamic property with this name.
|
||||
prop = &propVec()[propInd];
|
||||
if (prop->m_type == KindOfUninit) {
|
||||
unset = true;
|
||||
}
|
||||
} else {
|
||||
assert(!visible && !accessible);
|
||||
// We could not find a visible property. We need to check for a
|
||||
// dynamic property with this name if declOnly = false.
|
||||
if (!declOnly && o_properties.get()) {
|
||||
prop = static_cast<HphpArray*>(o_properties.get())->nvGet(key);
|
||||
if (prop) {
|
||||
// o_properties.get()->nvGet() returned a non-declared property,
|
||||
// we know that it is visible and accessible (since all
|
||||
// dynamic properties are), and we know it is not unset
|
||||
// (since unset dynamic properties don't appear in o_properties.get()).
|
||||
visible = true;
|
||||
accessible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
TypedValue* Instance::getProp(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible, bool& unset) {
|
||||
return getPropImpl<false>(ctx, key, visible, accessible, unset);
|
||||
}
|
||||
|
||||
TypedValue* Instance::getDeclProp(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible,
|
||||
bool& unset) {
|
||||
return getPropImpl<true>(ctx, key, visible, accessible, unset);
|
||||
}
|
||||
|
||||
void Instance::invokeSet(TypedValue* retval, const StringData* key,
|
||||
TypedValue* val) {
|
||||
AttributeClearer a(UseSet, this);
|
||||
const Func* meth = m_cls->lookupMethod(s___set.get());
|
||||
assert(meth);
|
||||
invokeUserMethod(retval, meth,
|
||||
CREATE_VECTOR2(CStrRef(key), tvAsVariant(val)));
|
||||
}
|
||||
|
||||
#define MAGIC_PROP_BODY(name, attr) \
|
||||
AttributeClearer a((attr), this); \
|
||||
const Func* meth = m_cls->lookupMethod(name); \
|
||||
assert(meth); \
|
||||
invokeUserMethod(retval, meth, CREATE_VECTOR1(CStrRef(key))); \
|
||||
|
||||
void Instance::invokeGet(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___get.get(), UseGet);
|
||||
}
|
||||
|
||||
void Instance::invokeIsset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___isset.get(), UseIsset);
|
||||
}
|
||||
|
||||
void Instance::invokeUnset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___unset.get(), UseUnset);
|
||||
}
|
||||
|
||||
void Instance::invokeGetProp(TypedValue*& retval, TypedValue& tvRef,
|
||||
const StringData* key) {
|
||||
invokeGet(&tvRef, key);
|
||||
retval = &tvRef;
|
||||
}
|
||||
|
||||
template <bool warn, bool define>
|
||||
void Instance::propImpl(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx,
|
||||
const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
|
||||
if (visible) {
|
||||
if (accessible) {
|
||||
if (unset) {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
if (warn) {
|
||||
raiseUndefProp(key);
|
||||
}
|
||||
if (define) {
|
||||
retval = propVal;
|
||||
} else {
|
||||
retval = (TypedValue*)&init_null_variant;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
retval = propVal;
|
||||
}
|
||||
} else {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
// No need to check hasProp since visible is true
|
||||
// Visibility is either protected or private since accessible is false
|
||||
Slot propInd = m_cls->lookupDeclProp(key);
|
||||
bool priv = m_cls->declProperties()[propInd].m_attrs & AttrPrivate;
|
||||
|
||||
raise_error("Cannot access %s property %s::$%s",
|
||||
priv ? "private" : "protected",
|
||||
m_cls->m_preClass->name()->data(),
|
||||
key->data());
|
||||
}
|
||||
}
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
if (warn) {
|
||||
raiseUndefProp(key);
|
||||
}
|
||||
if (define) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&retval), false);
|
||||
} else {
|
||||
retval = (TypedValue*)&init_null_variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::prop(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<false, false>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propD(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<false, true>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propW(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<true, false>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propWD(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<true, true>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
bool Instance::propIsset(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
return isset(tvAsCVarRef(propVal));
|
||||
}
|
||||
if (!getAttribute(UseIsset)) {
|
||||
return false;
|
||||
}
|
||||
TypedValue tv;
|
||||
tvWriteUninit(&tv);
|
||||
invokeIsset(&tv, key);
|
||||
tvCastToBooleanInPlace(&tv);
|
||||
return tv.m_data.num;
|
||||
}
|
||||
|
||||
bool Instance::propEmpty(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
return empty(tvAsCVarRef(propVal));
|
||||
}
|
||||
if (!getAttribute(UseIsset)) {
|
||||
return true;
|
||||
}
|
||||
TypedValue tv;
|
||||
tvWriteUninit(&tv);
|
||||
invokeIsset(&tv, key);
|
||||
tvCastToBooleanInPlace(&tv);
|
||||
if (!tv.m_data.num) {
|
||||
return true;
|
||||
}
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGet(&tv, key);
|
||||
bool emptyResult = empty(tvAsCVarRef(&tv));
|
||||
tvRefcountedDecRef(&tv);
|
||||
return emptyResult;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setProp(Class* ctx, const StringData* key,
|
||||
TypedValue* val,
|
||||
bool bindingAssignment /* = false */) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseSet)) {
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, val);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
} else {
|
||||
if (UNLIKELY(bindingAssignment)) {
|
||||
tvBind(val, propVal);
|
||||
} else {
|
||||
tvSet(*val, *propVal);
|
||||
}
|
||||
}
|
||||
// Return a pointer to the property if it's a declared property
|
||||
return declPropInd(propVal) != kInvalidSlot ? propVal : nullptr;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
// when seting a dynamic property, do not write
|
||||
// directly to the TypedValue in the HphpArray, since
|
||||
// its _count field is used to store the string hash of
|
||||
// the property name. Instead, call the appropriate
|
||||
// setters (set() or setRef()).
|
||||
if (UNLIKELY(bindingAssignment)) {
|
||||
o_properties.get()->setRef(const_cast<StringData*>(key),
|
||||
tvAsCVarRef(val), false);
|
||||
} else {
|
||||
o_properties.get()->set(const_cast<StringData*>(key),
|
||||
tvAsCVarRef(val), false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseSet));
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, val);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
Cell* val) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseGet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
SETOP_BODY(&tvResult, op, val);
|
||||
if (getAttribute(UseSet)) {
|
||||
assert(tvRef.m_type == KindOfUninit);
|
||||
memcpy(&tvRef, &tvResult, sizeof(TypedValue));
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
} else {
|
||||
memcpy(propVal, &tvResult, sizeof(TypedValue));
|
||||
}
|
||||
} else {
|
||||
SETOP_BODY(propVal, op, val);
|
||||
}
|
||||
return propVal;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseGet) || !getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseGet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
SETOP_BODY(propVal, op, val);
|
||||
return propVal;
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
SETOP_BODY(&tvResult, op, val);
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
return propVal;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseGet) && getAttribute(UseSet));
|
||||
invokeGet(&tvRef, key);
|
||||
SETOP_BODY(&tvRef, op, val);
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
return propVal;
|
||||
}
|
||||
|
||||
template <bool setResult>
|
||||
void Instance::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseGet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
IncDecBody<setResult>(op, &tvResult, &dest);
|
||||
if (getAttribute(UseSet)) {
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvResult);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvResult;
|
||||
} else {
|
||||
memcpy((void *)propVal, (void *)&tvResult, sizeof(TypedValue));
|
||||
}
|
||||
} else {
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseGet) || !getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseGet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
return;
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
IncDecBody<setResult>(op, &tvResult, &dest);
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
return;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseGet) && getAttribute(UseSet));
|
||||
invokeGet(&tvRef, key);
|
||||
IncDecBody<setResult>(op, &tvRef, &dest);
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
}
|
||||
|
||||
template <>
|
||||
void Instance::incDecProp<false>(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
incDecPropImpl<false>(tvRef, ctx, op, key, dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Instance::incDecProp<true>(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
incDecPropImpl<true>(tvRef, ctx, op, key, dest);
|
||||
}
|
||||
|
||||
void Instance::unsetProp(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
Slot propInd = declPropInd(propVal);
|
||||
if (propInd != kInvalidSlot) {
|
||||
// Declared property.
|
||||
tvSetIgnoreRef(*null_variant.asTypedValue(), *propVal);
|
||||
} else {
|
||||
// Dynamic property.
|
||||
assert(o_properties.get() != nullptr);
|
||||
o_properties.get()->remove(CStrRef(key), false);
|
||||
}
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else {
|
||||
assert(!accessible);
|
||||
if (getAttribute(UseUnset)) {
|
||||
TypedValue ignored;
|
||||
invokeUnset(&ignored, key);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
} else if (visible) {
|
||||
raise_error("Cannot unset inaccessible property");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::raiseUndefProp(const StringData* key) {
|
||||
raise_notice("Undefined property: %s::$%s",
|
||||
m_cls->name()->data(), key->data());
|
||||
}
|
||||
|
||||
void Instance::getProp(const Class* klass, bool pubOnly,
|
||||
const PreClass::Prop* prop,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
if (prop->attrs() & AttrStatic) {
|
||||
return;
|
||||
}
|
||||
|
||||
Slot propInd = klass->lookupDeclProp(prop->name());
|
||||
assert(propInd != kInvalidSlot);
|
||||
const TypedValue* propVal = &propVec()[propInd];
|
||||
|
||||
if ((!pubOnly || (prop->attrs() & AttrPublic)) &&
|
||||
propVal->m_type != KindOfUninit &&
|
||||
!inserted[propInd]) {
|
||||
inserted[propInd] = true;
|
||||
props.lvalAt(CStrRef(klass->declProperties()[propInd].m_mangledName))
|
||||
.setWithRef(tvAsCVarRef(propVal));
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::getProps(const Class* klass, bool pubOnly,
|
||||
const PreClass* pc,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
PreClass::Prop const* propVec = pc->properties();
|
||||
size_t count = pc->numProperties();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
getProp(klass, pubOnly, &propVec[i], props, inserted);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___destruct() {
|
||||
static StringData* sd__destruct = StringData::GetStaticString("__destruct");
|
||||
const Func* method = m_cls->lookupMethod(sd__destruct);
|
||||
if (method) {
|
||||
Variant v;
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___call(Variant v_name, Variant v_arguments) {
|
||||
static StringData* sd__call = StringData::GetStaticString("__call");
|
||||
const Func* method = m_cls->lookupMethod(sd__call);
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[2];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
tvDup(*v_arguments.asTypedValue(), args[1]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 2,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___set(Variant v_name, Variant v_value) {
|
||||
const Func* method = m_cls->lookupMethod(s___set.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
g_vmContext->invokeFunc(v.asTypedValue(), method,
|
||||
Array(ArrayInit(2).set(v_name).set(withRefBind(v_value)).create()),
|
||||
this);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___get(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___get.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
bool Instance::t___isset(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___isset.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v.toBoolean();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___unset(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___unset.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___sleep() {
|
||||
static StringData* sd__sleep = StringData::GetStaticString("__sleep");
|
||||
const Func *method = m_cls->lookupMethod(sd__sleep);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return tvAsVariant(&tv);
|
||||
} else {
|
||||
clearAttribute(HasSleep);
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___wakeup() {
|
||||
static StringData* sd__wakeup = StringData::GetStaticString("__wakeup");
|
||||
const Func *method = m_cls->lookupMethod(sd__wakeup);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return tvAsVariant(&tv);
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___set_state(Variant v_properties) {
|
||||
static StringData* sd__set_state = StringData::GetStaticString("__set_state");
|
||||
const Func* method = m_cls->lookupMethod(sd__set_state);
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_properties.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String Instance::t___tostring() {
|
||||
const Func *method = m_cls->getToString();
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
if (!IS_STRING_TYPE(tv.m_type)) {
|
||||
void (*notify_user)(const char *, ...) = &raise_error;
|
||||
if (hphpiCompat) {
|
||||
tvCastToStringInPlace(&tv);
|
||||
notify_user = &raise_warning;
|
||||
}
|
||||
notify_user("Method %s::__toString() must return a string value",
|
||||
m_cls->m_preClass->name()->data());
|
||||
}
|
||||
return tv.m_data.pstr;
|
||||
} else {
|
||||
std::string msg = m_cls->m_preClass->name()->data();
|
||||
msg += "::__toString() was not defined";
|
||||
throw BadTypeConversionException(msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___clone() {
|
||||
static StringData* sd__clone = StringData::GetStaticString("__clone");
|
||||
const Func *method = m_cls->lookupMethod(sd__clone);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::cloneSet(ObjectData* clone) {
|
||||
Instance* iclone = static_cast<Instance*>(clone);
|
||||
Slot nProps = m_cls->numDeclProperties();
|
||||
TypedValue* iclonePropVec = (TypedValue *)((uintptr_t)iclone +
|
||||
sizeof(ObjectData) + builtinPropSize());
|
||||
for (Slot i = 0; i < nProps; i++) {
|
||||
tvRefcountedDecRef(&iclonePropVec[i]);
|
||||
tvDupFlattenVars(&propVec()[i], &iclonePropVec[i], nullptr);
|
||||
}
|
||||
if (o_properties.get()) {
|
||||
iclone->initDynProps();
|
||||
ssize_t iter = o_properties.get()->iter_begin();
|
||||
while (iter != HphpArray::ElmIndEmpty) {
|
||||
auto props = static_cast<HphpArray*>(o_properties.get());
|
||||
TypedValue key;
|
||||
props->nvGetKey(&key, iter);
|
||||
assert(tvIsString(&key));
|
||||
StringData* strKey = key.m_data.pstr;
|
||||
TypedValue *val = props->nvGet(strKey);
|
||||
TypedValue *retval;
|
||||
auto cloneProps = iclone->o_properties.get();
|
||||
cloneProps->createLvalPtr(strKey, *(Variant**)&retval, false);
|
||||
tvDupFlattenVars(val, retval, cloneProps);
|
||||
iter = o_properties.get()->iter_advance(iter);
|
||||
decRefStr(strKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjectData* Instance::cloneImpl() {
|
||||
Instance* obj = Instance::newInstance(m_cls);
|
||||
cloneSet(obj);
|
||||
obj->incRefCount();
|
||||
obj->t___clone();
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // HPHP::VM
|
||||
|
||||
|
||||
|
||||
@@ -21,9 +21,8 @@
|
||||
#include "hphp/runtime/base/util/smart_ptr.h"
|
||||
#include "hphp/runtime/base/types.h"
|
||||
#include "hphp/runtime/base/macros.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/int.hpp>
|
||||
|
||||
@@ -107,9 +106,6 @@ class ObjectData : public CountableNF {
|
||||
// Return the upper 3 bits of o_attribute
|
||||
return (Collection::Type)((uint16_t)(o_attribute >> 13) & 7);
|
||||
}
|
||||
bool supportsUnsetElem() const {
|
||||
return isCollection() || instanceof(SystemLib::s_ArrayAccessClass);
|
||||
}
|
||||
|
||||
bool implementsIterator() {
|
||||
return (instanceof(SystemLib::s_IteratorClass));
|
||||
@@ -150,14 +146,13 @@ class ObjectData : public CountableNF {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void raiseObjToIntNotice(const char*);
|
||||
|
||||
int64_t o_toInt64() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toInt64Impl();
|
||||
}
|
||||
raise_notice(
|
||||
"Object of class %s could not be converted to int",
|
||||
o_getClassName().data()
|
||||
);
|
||||
raiseObjToIntNotice(o_getClassName().data());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -416,6 +411,226 @@ ALWAYS_INLINE inline void decRefObj(ObjectData* obj) {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps);
|
||||
|
||||
class Instance : public ObjectData {
|
||||
// Do not declare any fields directly in Instance; instead embed them in
|
||||
// ObjectData, so that a property vector can always reside immediately past
|
||||
// the end of an object.
|
||||
|
||||
private:
|
||||
// This constructor is used for all pure classes that are not
|
||||
// descendents of cppext classes
|
||||
explicit Instance(Class* cls) : ObjectData(false, cls) {
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
enum class NoInit { noinit };
|
||||
explicit Instance(Class* cls, NoInit) : ObjectData(false, cls) {}
|
||||
|
||||
public:
|
||||
// This constructor is used for all cppext classes (including resources)
|
||||
// and their descendents.
|
||||
Instance(Class* cls, bool isResource)
|
||||
: ObjectData(isResource, cls) {
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
virtual ~Instance() {}
|
||||
|
||||
static int ObjAllocatorSizeClassCount;
|
||||
|
||||
static void raiseAbstractClassError(Class* cls);
|
||||
|
||||
// Call newInstance() to instantiate an Instance
|
||||
static Instance* newInstance(Class* cls) {
|
||||
if (cls->m_InstanceCtor) {
|
||||
return cls->m_InstanceCtor(cls);
|
||||
}
|
||||
Attr attrs = cls->attrs();
|
||||
if (UNLIKELY(attrs & (AttrAbstract | AttrInterface | AttrTrait))) {
|
||||
raiseAbstractClassError(cls);
|
||||
}
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t size = sizeForNProps(nProps);
|
||||
Instance* obj = (Instance*)ALLOCOBJSZ(size);
|
||||
new (obj) Instance(cls);
|
||||
if (UNLIKELY(cls->callsCustomInstanceInit())) {
|
||||
/*
|
||||
This must happen after the constructor finishes,
|
||||
because it can leak references to obj AND it can
|
||||
throw exceptions. If we have this in the Instance
|
||||
constructor, and it throws, obj will be partially
|
||||
destroyed (ie ~ObjectData will be called, resetting
|
||||
the vtable pointer) leaving dangling references
|
||||
to the object (eg in backtraces).
|
||||
*/
|
||||
obj->callCustomInstanceInit();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Given a Class that is assumed to be a concrete, regular (not a
|
||||
// trait or interface), pure PHP class, and an allocator index,
|
||||
// return a new, uninitialized object of that class.
|
||||
static Instance* newInstanceRaw(Class* cls, int idx);
|
||||
|
||||
private:
|
||||
void instanceInit(Class* cls) {
|
||||
setAttributes(cls->getODAttrs());
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
if (cls->needInitialization()) {
|
||||
cls->initialize();
|
||||
}
|
||||
if (nProps > 0) {
|
||||
if (cls->pinitVec().size() > 0) {
|
||||
const Class::PropInitVec* propInitVec = m_cls->getPropData();
|
||||
assert(propInitVec != nullptr);
|
||||
assert(nProps == propInitVec->size());
|
||||
if (!cls->hasDeepInitProps()) {
|
||||
memcpy(propVec(), &(*propInitVec)[0], nProps * sizeof(TypedValue));
|
||||
} else {
|
||||
deepInitHelper(propVec(), &(*propInitVec)[0], nProps);
|
||||
}
|
||||
} else {
|
||||
assert(nProps == cls->declPropInit().size());
|
||||
memcpy(propVec(), &cls->declPropInit()[0], nProps * sizeof(TypedValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
TypedValue* propVec();
|
||||
const TypedValue* propVec() const;
|
||||
|
||||
public:
|
||||
Instance* callCustomInstanceInit();
|
||||
|
||||
void operator delete(void* p);
|
||||
|
||||
//============================================================================
|
||||
// Virtual ObjectData methods that we need to override
|
||||
|
||||
public:
|
||||
virtual Variant t___destruct();
|
||||
virtual Variant t___call(Variant v_name, Variant v_arguments);
|
||||
virtual Variant t___set(Variant v_name, Variant v_value);
|
||||
virtual Variant t___get(Variant v_name);
|
||||
virtual bool t___isset(Variant v_name);
|
||||
virtual Variant t___unset(Variant v_name);
|
||||
virtual Variant t___sleep();
|
||||
virtual Variant t___wakeup();
|
||||
virtual Variant t___set_state(Variant v_properties);
|
||||
virtual String t___tostring();
|
||||
virtual Variant t___clone();
|
||||
|
||||
//============================================================================
|
||||
// Miscellaneous.
|
||||
|
||||
void cloneSet(ObjectData* clone);
|
||||
ObjectData* cloneImpl();
|
||||
|
||||
void invokeUserMethod(TypedValue* retval, const Func* method,
|
||||
CArrRef params);
|
||||
|
||||
const Func* methodNamed(const StringData* sd) const {
|
||||
return getVMClass()->lookupMethod(sd);
|
||||
}
|
||||
|
||||
static size_t sizeForNProps(Slot nProps) {
|
||||
size_t sz = sizeof(Instance) + (sizeof(TypedValue) * nProps);
|
||||
assert((sz & (sizeof(TypedValue) - 1)) == 0);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static Object FromArray(ArrayData *properties);
|
||||
|
||||
//============================================================================
|
||||
// Properties.
|
||||
public:
|
||||
int builtinPropSize() const {
|
||||
return m_cls->builtinPropSize();
|
||||
}
|
||||
|
||||
// public for ObjectData access
|
||||
void initDynProps(int numDynamic = 0);
|
||||
Slot declPropInd(TypedValue* prop) const;
|
||||
private:
|
||||
template <bool declOnly>
|
||||
TypedValue* getPropImpl(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
public:
|
||||
TypedValue* getProp(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
TypedValue* getDeclProp(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
private:
|
||||
template <bool warn, bool define>
|
||||
void propImpl(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void invokeSet(TypedValue* retval, const StringData* key, TypedValue* val);
|
||||
void invokeGet(TypedValue* retval, const StringData* key);
|
||||
void invokeGetProp(TypedValue*& retval, TypedValue& tvRef,
|
||||
const StringData* key);
|
||||
void invokeIsset(TypedValue* retval, const StringData* key);
|
||||
void invokeUnset(TypedValue* retval, const StringData* key);
|
||||
void getProp(const Class* klass, bool pubOnly, const PreClass::Prop* prop,
|
||||
Array& props, std::vector<bool>& inserted) const;
|
||||
void getProps(const Class* klass, bool pubOnly, const PreClass* pc,
|
||||
Array& props, std::vector<bool>& inserted) const;
|
||||
public:
|
||||
void prop(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propD(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propW(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propWD(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
bool propIsset(Class* ctx, const StringData* key);
|
||||
bool propEmpty(Class* ctx, const StringData* key);
|
||||
|
||||
TypedValue* setProp(Class* ctx, const StringData* key, TypedValue* val,
|
||||
bool bindingAssignment = false);
|
||||
TypedValue* setOpProp(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, Cell* val);
|
||||
private:
|
||||
template <bool setResult>
|
||||
void incDecPropImpl(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, TypedValue& dest);
|
||||
public:
|
||||
template <bool setResult>
|
||||
void incDecProp(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, TypedValue& dest);
|
||||
void unsetProp(Class* ctx, const StringData* key);
|
||||
|
||||
void raiseUndefProp(const StringData* name);
|
||||
|
||||
friend class ObjectData;
|
||||
};
|
||||
|
||||
inline Instance* instanceFromTv(TypedValue* tv) {
|
||||
assert(dynamic_cast<Instance*>(tv->m_data.pobj));
|
||||
return static_cast<Instance*>(tv->m_data.pobj);
|
||||
}
|
||||
|
||||
#endif // incl_HPHP_OBJECT_DATA_H_
|
||||
class ExtObjectData : public HPHP::Instance {
|
||||
public:
|
||||
explicit ExtObjectData(HPHP::Class* cls)
|
||||
: HPHP::Instance(cls, false) {
|
||||
assert(!m_cls->callsCustomInstanceInit());
|
||||
}
|
||||
};
|
||||
|
||||
template <int flags> class ExtObjectDataFlags : public ExtObjectData {
|
||||
public:
|
||||
explicit ExtObjectDataFlags(HPHP::Class* cb) : ExtObjectData(cb) {
|
||||
ObjectData::setAttributes(flags);
|
||||
}
|
||||
};
|
||||
|
||||
} // HPHP
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/memory/sweepable.h"
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -429,6 +429,26 @@ ALWAYS_INLINE inline void decRefStr(StringData* s) {
|
||||
if (s->decRefCount() == 0) s->release();
|
||||
}
|
||||
|
||||
struct string_data_hash {
|
||||
size_t operator()(const StringData *s) const {
|
||||
return s->hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct string_data_same {
|
||||
bool operator()(const StringData *s1, const StringData *s2) const {
|
||||
assert(s1 && s2);
|
||||
return s1->same(s2);
|
||||
}
|
||||
};
|
||||
|
||||
struct string_data_isame {
|
||||
bool operator()(const StringData *s1, const StringData *s2) const {
|
||||
assert(s1 && s2);
|
||||
return s1->isame(s2);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/type_conversions.h"
|
||||
#include "hphp/runtime/base/builtin_functions.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "hphp/runtime/base/time/timestamp.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/time/datetime.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
#include <timelib.h>
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "hphp/runtime/base/type_conversions.h"
|
||||
#include "hphp/runtime/base/builtin_functions.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
#include "hphp/util/logger.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/tv_conversions.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef incl_HPHP_TV_COMPARISONS_H_
|
||||
#define incl_HPHP_TV_COMPARISONS_H_
|
||||
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -442,26 +442,6 @@ extern const String null_string;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct string_data_hash {
|
||||
size_t operator()(const StringData *s) const {
|
||||
return s->hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct string_data_same {
|
||||
bool operator()(const StringData *s1, const StringData *s2) const {
|
||||
assert(s1 && s2);
|
||||
return s1->same(s2);
|
||||
}
|
||||
};
|
||||
|
||||
struct string_data_isame {
|
||||
bool operator()(const StringData *s1, const StringData *s2) const {
|
||||
assert(s1 && s2);
|
||||
return s1->isame(s2);
|
||||
}
|
||||
};
|
||||
|
||||
struct string_data_lt {
|
||||
bool operator()(const StringData *s1, const StringData *s2) const {
|
||||
int len1 = s1->size();
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "hphp/runtime/base/array/array_iterator.h"
|
||||
#include "hphp/util/parser/hphp.tab.hpp"
|
||||
#include "hphp/runtime/vm/runtime.h"
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/base/tv_arith.h"
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <type_traits>
|
||||
#include <stdint.h>
|
||||
#include <limits>
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -423,6 +425,116 @@ public:
|
||||
#define ACCESSPARAMS_DECL AccessFlags::Type flags = AccessFlags::None
|
||||
#define ACCESSPARAMS_IMPL AccessFlags::Type flags
|
||||
|
||||
/*
|
||||
* Non-enumerated version of type for referring to opcodes or the
|
||||
* bytecode stream. (Use the enum Op in hhbc.h for an enumerated
|
||||
* version.)
|
||||
*/
|
||||
typedef uint8_t Opcode;
|
||||
|
||||
/*
|
||||
* Program counters in the bytecode interpreter.
|
||||
*
|
||||
* Normally points to an Opcode, but has type const uchar* because
|
||||
* during a given instruction it is incremented while decoding
|
||||
* immediates and may point to arbitrary bytes.
|
||||
*/
|
||||
typedef const uchar* PC;
|
||||
|
||||
/*
|
||||
* Id type for various components of a unit that have to have unique
|
||||
* identifiers. For example, function ids, class ids, string literal
|
||||
* ids.
|
||||
*/
|
||||
typedef int Id;
|
||||
const Id kInvalidId = Id(-1);
|
||||
|
||||
// Bytecode offsets. Used for both absolute offsets and relative
|
||||
// offsets.
|
||||
typedef int32_t Offset;
|
||||
constexpr Offset kInvalidOffset = std::numeric_limits<Offset>::max();
|
||||
|
||||
/*
|
||||
* Various fields in the VM's runtime have indexes that are addressed
|
||||
* using this "slot" type. For example: methods, properties, class
|
||||
* constants.
|
||||
*
|
||||
* No slot value greater than or equal to kInvalidSlot will actually
|
||||
* be used for one of these.
|
||||
*/
|
||||
typedef uint32_t Slot;
|
||||
const Slot kInvalidSlot = Slot(-1);
|
||||
|
||||
/*
|
||||
* Special types that are not relevant to the runtime as a whole.
|
||||
* The order for public/protected/private matters in numerous places.
|
||||
*
|
||||
* Attr unions are directly stored as integers in .hhbc repositories, so
|
||||
* incompatible changes here require a schema version bump.
|
||||
*
|
||||
* AttrTrait on a method means that the method is NOT a constructor,
|
||||
* even though it may look like one
|
||||
*
|
||||
* AttrNoOverride (WholeProgram only) on a class means its not extended
|
||||
* and on a method means that no extending class defines the method.
|
||||
*
|
||||
* AttrVariadicByRef indicates a function is a builtin that takes
|
||||
* variadic arguments, where the arguments are either by ref or
|
||||
* optionally by ref. (It is equivalent to having ClassInfo's
|
||||
* (RefVariableArguments | MixedVariableArguments).)
|
||||
*
|
||||
* AttrMayUseVV indicates that a function may need to use a VarEnv or
|
||||
* varargs (aka extraArgs) at run time.
|
||||
*
|
||||
* AttrPhpLeafFn indicates a function does not make any explicit calls
|
||||
* to other php functions. It may still call other user-level
|
||||
* functions via re-entry (e.g. for destructors or autoload), and it
|
||||
* may make calls to builtins using FCallBuiltin.
|
||||
*
|
||||
* AttrBuiltin is set on builtin functions - whether c++ or php
|
||||
*
|
||||
* AttrAllowOverride is set on builtin functions that can be replaced
|
||||
* by user implementations
|
||||
*
|
||||
* AttrSkipFrame is set to indicate that the frame should be ignored
|
||||
* when searching for the context (eg array_map evaluates its
|
||||
* callback in the context of its caller).
|
||||
*/
|
||||
enum Attr {
|
||||
AttrNone = 0, // class property method //
|
||||
AttrReference = (1 << 0), // X //
|
||||
AttrPublic = (1 << 1), // X X //
|
||||
AttrProtected = (1 << 2), // X X //
|
||||
AttrPrivate = (1 << 3), // X X //
|
||||
AttrStatic = (1 << 4), // X X //
|
||||
AttrAbstract = (1 << 5), // X X //
|
||||
AttrFinal = (1 << 6), // X X //
|
||||
AttrInterface = (1 << 7), // X //
|
||||
AttrPhpLeafFn = (1 << 7), // X //
|
||||
AttrTrait = (1 << 8), // X X //
|
||||
AttrNoInjection = (1 << 9), // X //
|
||||
AttrUnique = (1 << 10), // X X //
|
||||
AttrDynamicInvoke = (1 << 11), // X //
|
||||
AttrNoExpandTrait = (1 << 12), // X //
|
||||
AttrNoOverride= (1 << 13), // X X //
|
||||
AttrClone = (1 << 14), // X //
|
||||
AttrVariadicByRef = (1 << 15), // X //
|
||||
AttrMayUseVV = (1 << 16), // X //
|
||||
AttrPersistent= (1 << 17), // X X //
|
||||
AttrDeepInit = (1 << 18), // X //
|
||||
AttrHot = (1 << 19), // X //
|
||||
AttrBuiltin = (1 << 20), // X //
|
||||
AttrAllowOverride = (1 << 21), // X //
|
||||
AttrSkipFrame = (1 << 22), // X //
|
||||
};
|
||||
|
||||
inline Attr operator|(Attr a, Attr b) { return Attr((int)a | (int)b); }
|
||||
|
||||
inline const char* attrToVisibilityStr(Attr attr) {
|
||||
return (attr & AttrPrivate) ? "private" :
|
||||
(attr & AttrProtected) ? "protected" : "public";
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
#include "hphp/runtime/vm/hhbc.h"
|
||||
#include "hphp/runtime/vm/preclass-emit.h"
|
||||
#include "hphp/runtime/base/builtin_functions.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "hphp/runtime/vm/backup_gc.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -18,17 +18,13 @@
|
||||
#define incl_HPHP_VM_BYTECODE_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "hphp/util/util.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/class_info.h"
|
||||
#include "hphp/runtime/base/array/array_iterator.h"
|
||||
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
#include "hphp/runtime/vm/func.h"
|
||||
#include "hphp/runtime/vm/name_value_table.h"
|
||||
|
||||
+14
-322
@@ -13,19 +13,13 @@
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/base/base_includes.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/comparisons.h"
|
||||
#include "hphp/runtime/base/array/hphp_array.h"
|
||||
#include "hphp/util/util.h"
|
||||
#include "hphp/util/debug.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/vm/hhbc.h"
|
||||
#include "hphp/runtime/vm/repo.h"
|
||||
#include "hphp/runtime/vm/jit/targetcache.h"
|
||||
#include "hphp/runtime/vm/jit/translator.h"
|
||||
#include "hphp/runtime/vm/blob_helper.h"
|
||||
#include "hphp/runtime/vm/treadmill.h"
|
||||
#include "hphp/runtime/vm/name_value_table.h"
|
||||
#include "hphp/runtime/vm/name_value_table_wrapper.h"
|
||||
@@ -54,9 +48,9 @@ Class::InstanceBitsMap Class::s_instanceBits;
|
||||
ReadWriteMutex Class::s_instanceBitsLock(RankInstanceBits);
|
||||
std::atomic<bool> Class::s_instanceBitsInit{false};
|
||||
|
||||
static const StringData* manglePropName(const StringData* className,
|
||||
const StringData* propName,
|
||||
Attr attrs) {
|
||||
const StringData* PreClass::manglePropName(const StringData* className,
|
||||
const StringData* propName,
|
||||
Attr attrs) {
|
||||
switch (attrs & (AttrPublic|AttrProtected|AttrPrivate)) {
|
||||
case AttrPublic: {
|
||||
return propName;
|
||||
@@ -198,315 +192,6 @@ void PreClass::prettyPrint(std::ostream &out) const {
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PreClassEmitter::Prop.
|
||||
|
||||
PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
|
||||
const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType)
|
||||
: m_name(n)
|
||||
, m_attrs(attrs)
|
||||
, m_typeConstraint(typeConstraint)
|
||||
, m_docComment(docComment)
|
||||
, m_hphpcType(hphpcType)
|
||||
{
|
||||
m_mangledName = manglePropName(pce->name(), n, attrs);
|
||||
memcpy(&m_val, val, sizeof(TypedValue));
|
||||
}
|
||||
|
||||
PreClassEmitter::Prop::~Prop() {
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PreClassEmitter.
|
||||
|
||||
PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
|
||||
Id id,
|
||||
const StringData* n,
|
||||
PreClass::Hoistable hoistable)
|
||||
: m_ue(ue)
|
||||
, m_name(n)
|
||||
, m_id(id)
|
||||
, m_hoistable(hoistable)
|
||||
, m_InstanceCtor(nullptr)
|
||||
, m_builtinPropSize(0)
|
||||
{}
|
||||
|
||||
void PreClassEmitter::init(int line1, int line2, Offset offset, Attr attrs,
|
||||
const StringData* parent,
|
||||
const StringData* docComment) {
|
||||
m_line1 = line1;
|
||||
m_line2 = line2;
|
||||
m_offset = offset;
|
||||
m_attrs = attrs;
|
||||
m_parent = parent;
|
||||
m_docComment = docComment;
|
||||
}
|
||||
|
||||
PreClassEmitter::~PreClassEmitter() {
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassEmitter::addInterface(const StringData* n) {
|
||||
m_interfaces.push_back(n);
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addMethod(FuncEmitter* method) {
|
||||
MethodMap::const_iterator it = m_methodMap.find(method->name());
|
||||
if (it != m_methodMap.end()) {
|
||||
return false;
|
||||
}
|
||||
m_methods.push_back(method);
|
||||
m_methodMap[method->name()] = method;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addProperty(const StringData* n, Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType) {
|
||||
PropMap::Builder::const_iterator it = m_propMap.find(n);
|
||||
if (it != m_propMap.end()) {
|
||||
return false;
|
||||
}
|
||||
PreClassEmitter::Prop prop(this, n, attrs, typeConstraint, docComment, val,
|
||||
hphpcType);
|
||||
m_propMap.add(prop.name(), prop);
|
||||
return true;
|
||||
}
|
||||
|
||||
const PreClassEmitter::Prop&
|
||||
PreClassEmitter::lookupProp(const StringData* propName) const {
|
||||
PropMap::Builder::const_iterator it = m_propMap.find(propName);
|
||||
assert(it != m_propMap.end());
|
||||
Slot idx = it->second;
|
||||
return m_propMap[idx];
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addConstant(const StringData* n,
|
||||
const StringData* typeConstraint,
|
||||
TypedValue* val,
|
||||
const StringData* phpCode) {
|
||||
ConstMap::Builder::const_iterator it = m_constMap.find(n);
|
||||
if (it != m_constMap.end()) {
|
||||
return false;
|
||||
}
|
||||
PreClassEmitter::Const const_(n, typeConstraint, val, phpCode);
|
||||
m_constMap.add(const_.name(), const_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PreClassEmitter::addUsedTrait(const StringData* traitName) {
|
||||
m_usedTraits.push_back(traitName);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addTraitPrecRule(
|
||||
const PreClass::TraitPrecRule &rule) {
|
||||
m_traitPrecRules.push_back(rule);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addTraitAliasRule(
|
||||
const PreClass::TraitAliasRule &rule) {
|
||||
m_traitAliasRules.push_back(rule);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addUserAttribute(const StringData* name, TypedValue tv) {
|
||||
m_userAttributes[name] = tv;
|
||||
}
|
||||
|
||||
void PreClassEmitter::commit(RepoTxn& txn) const {
|
||||
Repo& repo = Repo::get();
|
||||
PreClassRepoProxy& pcrp = repo.pcrp();
|
||||
int repoId = m_ue.repoId();
|
||||
int64_t usn = m_ue.sn();
|
||||
pcrp.insertPreClass(repoId)
|
||||
.insert(*this, txn, usn, m_id, m_name, m_hoistable);
|
||||
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
(*it)->commit(txn);
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassEmitter::setBuiltinClassInfo(const ClassInfo* info,
|
||||
BuiltinCtorFunction ctorFunc,
|
||||
int sz) {
|
||||
if (info->getAttribute() & ClassInfo::IsFinal) {
|
||||
m_attrs = m_attrs | AttrFinal;
|
||||
}
|
||||
if (info->getAttribute() & ClassInfo::IsAbstract) {
|
||||
m_attrs = m_attrs | AttrAbstract;
|
||||
}
|
||||
if (info->getAttribute() & ClassInfo::IsTrait) {
|
||||
m_attrs = m_attrs | AttrTrait;
|
||||
}
|
||||
m_attrs = m_attrs | AttrUnique;
|
||||
m_InstanceCtor = ctorFunc;
|
||||
m_builtinPropSize = sz - sizeof(ObjectData);
|
||||
}
|
||||
|
||||
PreClass* PreClassEmitter::create(Unit& unit) const {
|
||||
Attr attrs = m_attrs;
|
||||
if (attrs & AttrPersistent &&
|
||||
!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) {
|
||||
attrs = Attr(attrs & ~AttrPersistent);
|
||||
}
|
||||
PreClass* pc = new PreClass(&unit, m_line1, m_line2, m_offset, m_name,
|
||||
attrs, m_parent, m_docComment, m_id,
|
||||
m_hoistable);
|
||||
pc->m_InstanceCtor = m_InstanceCtor;
|
||||
pc->m_builtinPropSize = m_builtinPropSize;
|
||||
pc->m_interfaces = m_interfaces;
|
||||
pc->m_usedTraits = m_usedTraits;
|
||||
pc->m_traitPrecRules = m_traitPrecRules;
|
||||
pc->m_traitAliasRules = m_traitAliasRules;
|
||||
pc->m_userAttributes = m_userAttributes;
|
||||
|
||||
PreClass::MethodMap::Builder methodBuild;
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
Func* f = (*it)->create(unit, pc);
|
||||
methodBuild.add(f->name(), f);
|
||||
}
|
||||
pc->m_methods.create(methodBuild);
|
||||
|
||||
PreClass::PropMap::Builder propBuild;
|
||||
for (unsigned i = 0; i < m_propMap.size(); ++i) {
|
||||
const Prop& prop = m_propMap[i];
|
||||
propBuild.add(prop.name(), PreClass::Prop(pc,
|
||||
prop.name(),
|
||||
prop.attrs(),
|
||||
prop.typeConstraint(),
|
||||
prop.docComment(),
|
||||
prop.val(),
|
||||
prop.hphpcType()));
|
||||
}
|
||||
pc->m_properties.create(propBuild);
|
||||
|
||||
PreClass::ConstMap::Builder constBuild;
|
||||
for (unsigned i = 0; i < m_constMap.size(); ++i) {
|
||||
const Const& const_ = m_constMap[i];
|
||||
constBuild.add(const_.name(), PreClass::Const(pc,
|
||||
const_.name(),
|
||||
const_.typeConstraint(),
|
||||
const_.val(),
|
||||
const_.phpCode()));
|
||||
}
|
||||
pc->m_constants.create(constBuild);
|
||||
return pc;
|
||||
}
|
||||
|
||||
template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
|
||||
// NOTE: name, hoistable, and a few other fields currently
|
||||
// serialized outside of this.
|
||||
sd(m_line1)
|
||||
(m_line2)
|
||||
(m_offset)
|
||||
(m_attrs)
|
||||
(m_parent)
|
||||
(m_docComment)
|
||||
|
||||
(m_interfaces)
|
||||
(m_usedTraits)
|
||||
(m_traitPrecRules)
|
||||
(m_traitAliasRules)
|
||||
(m_userAttributes)
|
||||
(m_propMap)
|
||||
(m_constMap)
|
||||
;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PreClassRepoProxy.
|
||||
|
||||
PreClassRepoProxy::PreClassRepoProxy(Repo& repo)
|
||||
: RepoProxy(repo)
|
||||
#define PCRP_OP(c, o) \
|
||||
, m_##o##Local(repo, RepoIdLocal), m_##o##Central(repo, RepoIdCentral)
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
{
|
||||
#define PCRP_OP(c, o) \
|
||||
m_##o[RepoIdLocal] = &m_##o##Local; \
|
||||
m_##o[RepoIdCentral] = &m_##o##Central;
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
}
|
||||
|
||||
PreClassRepoProxy::~PreClassRepoProxy() {
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::createSchema(int repoId, RepoTxn& txn) {
|
||||
{
|
||||
std::stringstream ssCreate;
|
||||
ssCreate << "CREATE TABLE " << m_repo.table(repoId, "PreClass")
|
||||
<< "(unitSn INTEGER, preClassId INTEGER, name TEXT,"
|
||||
" hoistable INTEGER, extraData BLOB,"
|
||||
" PRIMARY KEY (unitSn, preClassId));";
|
||||
txn.exec(ssCreate.str());
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::InsertPreClassStmt
|
||||
::insert(const PreClassEmitter& pce, RepoTxn& txn,
|
||||
int64_t unitSn, Id preClassId,
|
||||
const StringData* name,
|
||||
PreClass::Hoistable hoistable) {
|
||||
if (!prepared()) {
|
||||
std::stringstream ssInsert;
|
||||
ssInsert << "INSERT INTO " << m_repo.table(m_repoId, "PreClass")
|
||||
<< " VALUES(@unitSn, @preClassId, @name, @hoistable, "
|
||||
"@extraData);";
|
||||
txn.prepare(*this, ssInsert.str());
|
||||
}
|
||||
|
||||
BlobEncoder extraBlob;
|
||||
RepoTxnQuery query(txn, *this);
|
||||
query.bindInt64("@unitSn", unitSn);
|
||||
query.bindId("@preClassId", preClassId);
|
||||
query.bindStaticString("@name", name);
|
||||
query.bindInt("@hoistable", hoistable);
|
||||
const_cast<PreClassEmitter&>(pce).serdeMetaData(extraBlob);
|
||||
query.bindBlob("@extraData", extraBlob, /* static */ true);
|
||||
query.exec();
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::GetPreClassesStmt
|
||||
::get(UnitEmitter& ue) {
|
||||
RepoTxn txn(m_repo);
|
||||
if (!prepared()) {
|
||||
std::stringstream ssSelect;
|
||||
ssSelect << "SELECT preClassId,name,hoistable,extraData FROM "
|
||||
<< m_repo.table(m_repoId, "PreClass")
|
||||
<< " WHERE unitSn == @unitSn ORDER BY preClassId ASC;";
|
||||
txn.prepare(*this, ssSelect.str());
|
||||
}
|
||||
RepoTxnQuery query(txn, *this);
|
||||
query.bindInt64("@unitSn", ue.sn());
|
||||
do {
|
||||
query.step();
|
||||
if (query.row()) {
|
||||
Id preClassId; /**/ query.getId(0, preClassId);
|
||||
StringData* name; /**/ query.getStaticString(1, name);
|
||||
int hoistable; /**/ query.getInt(2, hoistable);
|
||||
BlobDecoder extraBlob = /**/ query.getBlob(3);
|
||||
PreClassEmitter* pce = ue.newPreClassEmitter(
|
||||
name, (PreClass::Hoistable)hoistable);
|
||||
pce->serdeMetaData(extraBlob);
|
||||
assert(pce->id() == preClassId);
|
||||
}
|
||||
} while (!query.done());
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Class.
|
||||
|
||||
@@ -2090,8 +1775,9 @@ void Class::importTraitInstanceProp(ClassPtr trait,
|
||||
prop.m_class = this; // set current class as the first declaring prop
|
||||
// private props' mangled names contain the class name, so regenerate them
|
||||
if (prop.m_attrs & AttrPrivate) {
|
||||
prop.m_mangledName = manglePropName(m_preClass->name(), prop.m_name,
|
||||
prop.m_attrs);
|
||||
prop.m_mangledName = PreClass::manglePropName(m_preClass->name(),
|
||||
prop.m_name,
|
||||
prop.m_attrs);
|
||||
}
|
||||
curPropMap.add(prop.m_name, prop);
|
||||
m_declPropInit.push_back(traitPropVal);
|
||||
@@ -2547,6 +2233,12 @@ void Class::getClassInfo(ClassInfoVM* ci) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t Class::declPropOffset(Slot index) const {
|
||||
assert(index >= 0);
|
||||
return sizeof(ObjectData) + m_builtinPropSize
|
||||
+ index * sizeof(TypedValue);
|
||||
}
|
||||
|
||||
Class::PropInitVec::~PropInitVec() {
|
||||
if (!m_smart) free(m_data);
|
||||
}
|
||||
|
||||
+6
-198
@@ -21,15 +21,11 @@
|
||||
#include "tbb/concurrent_hash_map.h"
|
||||
#include <atomic>
|
||||
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/vm/repo_helpers.h"
|
||||
#include "hphp/runtime/base/runtime_option.h"
|
||||
#include "hphp/util/parser/location.h"
|
||||
#include "hphp/runtime/base/types.h"
|
||||
#include "hphp/util/fixed_vector.h"
|
||||
#include "hphp/util/range.h"
|
||||
#include "hphp/runtime/vm/fixed_string_map.h"
|
||||
#include "hphp/runtime/vm/indexed_string_map.h"
|
||||
#include "hphp/runtime/vm/named_entity.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -319,6 +315,10 @@ class PreClass : public AtomicCountable {
|
||||
|
||||
NamedEntity* namedEntity() const { return m_namedEntity; }
|
||||
|
||||
static const StringData* manglePropName(const StringData* className,
|
||||
const StringData* propName,
|
||||
Attr attrs);
|
||||
|
||||
private:
|
||||
typedef IndexedStringMap<Func*,false,Slot> MethodMap;
|
||||
typedef IndexedStringMap<Prop,true,Slot> PropMap;
|
||||
@@ -354,194 +354,6 @@ private:
|
||||
// use AtomicSmartPtr's to enforce this invariant.
|
||||
typedef AtomicSmartPtr<PreClass> PreClassPtr;
|
||||
|
||||
class PreClassEmitter {
|
||||
public:
|
||||
typedef std::vector<FuncEmitter*> MethodVec;
|
||||
|
||||
class Prop {
|
||||
public:
|
||||
Prop()
|
||||
: m_name(0)
|
||||
, m_mangledName(0)
|
||||
, m_attrs(AttrNone)
|
||||
, m_typeConstraint(0)
|
||||
, m_docComment(0)
|
||||
, m_hphpcType(KindOfInvalid)
|
||||
{}
|
||||
|
||||
Prop(const PreClassEmitter* pce,
|
||||
const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType);
|
||||
~Prop();
|
||||
|
||||
const StringData* name() const { return m_name; }
|
||||
const StringData* mangledName() const { return m_mangledName; }
|
||||
Attr attrs() const { return m_attrs; }
|
||||
const StringData* typeConstraint() const { return m_typeConstraint; }
|
||||
const StringData* docComment() const { return m_docComment; }
|
||||
const TypedValue& val() const { return m_val; }
|
||||
DataType hphpcType() const { return m_hphpcType; }
|
||||
|
||||
template<class SerDe> void serde(SerDe& sd) {
|
||||
sd(m_name)
|
||||
(m_mangledName)
|
||||
(m_attrs)
|
||||
(m_typeConstraint)
|
||||
(m_docComment)
|
||||
(m_val)
|
||||
(m_hphpcType)
|
||||
;
|
||||
}
|
||||
|
||||
private:
|
||||
const StringData* m_name;
|
||||
const StringData* m_mangledName;
|
||||
Attr m_attrs;
|
||||
const StringData* m_typeConstraint;
|
||||
const StringData* m_docComment;
|
||||
TypedValue m_val;
|
||||
DataType m_hphpcType;
|
||||
};
|
||||
|
||||
class Const {
|
||||
public:
|
||||
Const()
|
||||
: m_name(0)
|
||||
, m_typeConstraint(0)
|
||||
, m_phpCode(0)
|
||||
{}
|
||||
Const(const StringData* n, const StringData* typeConstraint,
|
||||
TypedValue* val, const StringData* phpCode)
|
||||
: m_name(n), m_typeConstraint(typeConstraint), m_phpCode(phpCode) {
|
||||
memcpy(&m_val, val, sizeof(TypedValue));
|
||||
}
|
||||
~Const() {}
|
||||
|
||||
const StringData* name() const { return m_name; }
|
||||
const StringData* typeConstraint() const { return m_typeConstraint; }
|
||||
const TypedValue& val() const { return m_val; }
|
||||
const StringData* phpCode() const { return m_phpCode; }
|
||||
|
||||
template<class SerDe> void serde(SerDe& sd) {
|
||||
sd(m_name)(m_val)(m_phpCode);
|
||||
}
|
||||
|
||||
private:
|
||||
const StringData* m_name;
|
||||
const StringData* m_typeConstraint;
|
||||
TypedValue m_val;
|
||||
const StringData* m_phpCode;
|
||||
};
|
||||
|
||||
PreClassEmitter(UnitEmitter& ue, Id id, const StringData* n,
|
||||
PreClass::Hoistable hoistable);
|
||||
~PreClassEmitter();
|
||||
|
||||
void init(int line1, int line2, Offset offset, Attr attrs,
|
||||
const StringData* parent, const StringData* docComment);
|
||||
|
||||
UnitEmitter& ue() const { return m_ue; }
|
||||
const StringData* name() const { return m_name; }
|
||||
Attr attrs() const { return m_attrs; }
|
||||
void setHoistable(PreClass::Hoistable h) { m_hoistable = h; }
|
||||
Id id() const { return m_id; }
|
||||
const MethodVec& methods() const { return m_methods; }
|
||||
|
||||
void addInterface(const StringData* n);
|
||||
bool addMethod(FuncEmitter* method);
|
||||
bool addProperty(const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType);
|
||||
const Prop& lookupProp(const StringData* propName) const;
|
||||
bool addConstant(const StringData* n, const StringData* typeConstraint,
|
||||
TypedValue* val, const StringData* phpCode);
|
||||
void addUsedTrait(const StringData* traitName);
|
||||
void addTraitPrecRule(const PreClass::TraitPrecRule &rule);
|
||||
void addTraitAliasRule(const PreClass::TraitAliasRule &rule);
|
||||
void addUserAttribute(const StringData* name, TypedValue tv);
|
||||
void commit(RepoTxn& txn) const;
|
||||
|
||||
void setBuiltinClassInfo(const ClassInfo* info,
|
||||
BuiltinCtorFunction ctorFunc,
|
||||
int sz);
|
||||
|
||||
PreClass* create(Unit& unit) const;
|
||||
|
||||
template<class SerDe> void serdeMetaData(SerDe&);
|
||||
|
||||
private:
|
||||
typedef IndexedStringMap<Prop,true,Slot> PropMap;
|
||||
typedef IndexedStringMap<Const,true,Slot> ConstMap;
|
||||
typedef hphp_hash_map<const StringData*, FuncEmitter*, string_data_hash,
|
||||
string_data_isame> MethodMap;
|
||||
|
||||
UnitEmitter& m_ue;
|
||||
int m_line1;
|
||||
int m_line2;
|
||||
Offset m_offset;
|
||||
const StringData* m_name;
|
||||
Attr m_attrs;
|
||||
const StringData* m_parent;
|
||||
const StringData* m_docComment;
|
||||
Id m_id;
|
||||
PreClass::Hoistable m_hoistable;
|
||||
BuiltinCtorFunction m_InstanceCtor;
|
||||
int m_builtinPropSize;
|
||||
|
||||
std::vector<const StringData*> m_interfaces;
|
||||
std::vector<const StringData*> m_usedTraits;
|
||||
std::vector<PreClass::TraitPrecRule> m_traitPrecRules;
|
||||
std::vector<PreClass::TraitAliasRule> m_traitAliasRules;
|
||||
PreClass::UserAttributeMap m_userAttributes;
|
||||
MethodVec m_methods;
|
||||
MethodMap m_methodMap;
|
||||
PropMap::Builder m_propMap;
|
||||
ConstMap::Builder m_constMap;
|
||||
};
|
||||
|
||||
class PreClassRepoProxy : public RepoProxy {
|
||||
friend class PreClass;
|
||||
friend class PreClassEmitter;
|
||||
public:
|
||||
explicit PreClassRepoProxy(Repo& repo);
|
||||
~PreClassRepoProxy();
|
||||
void createSchema(int repoId, RepoTxn& txn);
|
||||
|
||||
#define PCRP_IOP(o) PCRP_OP(Insert##o, insert##o)
|
||||
#define PCRP_GOP(o) PCRP_OP(Get##o, get##o)
|
||||
#define PCRP_OPS \
|
||||
PCRP_IOP(PreClass) \
|
||||
PCRP_GOP(PreClasses)
|
||||
class InsertPreClassStmt : public RepoProxy::Stmt {
|
||||
public:
|
||||
InsertPreClassStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
|
||||
void insert(const PreClassEmitter& pce, RepoTxn& txn, int64_t unitSn,
|
||||
Id preClassId, const StringData* name,
|
||||
PreClass::Hoistable hoistable);
|
||||
};
|
||||
class GetPreClassesStmt : public RepoProxy::Stmt {
|
||||
public:
|
||||
GetPreClassesStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
|
||||
void get(UnitEmitter& ue);
|
||||
};
|
||||
#define PCRP_OP(c, o) \
|
||||
public: \
|
||||
c##Stmt& o(int repoId) { return *m_##o[repoId]; } \
|
||||
private: \
|
||||
c##Stmt m_##o##Local; \
|
||||
c##Stmt m_##o##Central; \
|
||||
c##Stmt* m_##o[RepoIdCount];
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
};
|
||||
|
||||
/*
|
||||
* Class represents the full definition of a user class in a given
|
||||
* request context.
|
||||
@@ -832,11 +644,7 @@ public:
|
||||
|
||||
void getClassInfo(ClassInfoVM* ci);
|
||||
|
||||
size_t declPropOffset(Slot index) const {
|
||||
assert(index >= 0);
|
||||
return sizeof(ObjectData) + m_builtinPropSize
|
||||
+ index * sizeof(TypedValue);
|
||||
}
|
||||
size_t declPropOffset(Slot index) const;
|
||||
|
||||
DataType declPropHphpcType(Slot index) const {
|
||||
auto& prop = m_declProperties[index];
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_VM_CORE_TYPES_H_
|
||||
#define incl_HPHP_VM_CORE_TYPES_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Non-enumerated version of type for referring to opcodes or the
|
||||
* bytecode stream. (Use the enum Op in hhbc.h for an enumerated
|
||||
* version.)
|
||||
*/
|
||||
typedef uint8_t Opcode;
|
||||
|
||||
/*
|
||||
* Program counters in the bytecode interpreter.
|
||||
*
|
||||
* Normally points to an Opcode, but has type const uchar* because
|
||||
* during a given instruction it is incremented while decoding
|
||||
* immediates and may point to arbitrary bytes.
|
||||
*/
|
||||
typedef const uchar* PC;
|
||||
|
||||
/*
|
||||
* Id type for various components of a unit that have to have unique
|
||||
* identifiers. For example, function ids, class ids, string literal
|
||||
* ids.
|
||||
*/
|
||||
typedef int Id;
|
||||
const Id kInvalidId = Id(-1);
|
||||
|
||||
// Bytecode offsets. Used for both absolute offsets and relative
|
||||
// offsets.
|
||||
typedef int32_t Offset;
|
||||
constexpr Offset kInvalidOffset = std::numeric_limits<Offset>::max();
|
||||
|
||||
/*
|
||||
* Various fields in the VM's runtime have indexes that are addressed
|
||||
* using this "slot" type. For example: methods, properties, class
|
||||
* constants.
|
||||
*
|
||||
* No slot value greater than or equal to kInvalidSlot will actually
|
||||
* be used for one of these.
|
||||
*/
|
||||
typedef uint32_t Slot;
|
||||
const Slot kInvalidSlot = Slot(-1);
|
||||
|
||||
/*
|
||||
* Special types that are not relevant to the runtime as a whole.
|
||||
* The order for public/protected/private matters in numerous places.
|
||||
*
|
||||
* Attr unions are directly stored as integers in .hhbc repositories, so
|
||||
* incompatible changes here require a schema version bump.
|
||||
*
|
||||
* AttrTrait on a method means that the method is NOT a constructor,
|
||||
* even though it may look like one
|
||||
*
|
||||
* AttrNoOverride (WholeProgram only) on a class means its not extended
|
||||
* and on a method means that no extending class defines the method.
|
||||
*
|
||||
* AttrVariadicByRef indicates a function is a builtin that takes
|
||||
* variadic arguments, where the arguments are either by ref or
|
||||
* optionally by ref. (It is equivalent to having ClassInfo's
|
||||
* (RefVariableArguments | MixedVariableArguments).)
|
||||
*
|
||||
* AttrMayUseVV indicates that a function may need to use a VarEnv or
|
||||
* varargs (aka extraArgs) at run time.
|
||||
*
|
||||
* AttrPhpLeafFn indicates a function does not make any explicit calls
|
||||
* to other php functions. It may still call other user-level
|
||||
* functions via re-entry (e.g. for destructors or autoload), and it
|
||||
* may make calls to builtins using FCallBuiltin.
|
||||
*
|
||||
* AttrBuiltin is set on builtin functions - whether c++ or php
|
||||
*
|
||||
* AttrAllowOverride is set on builtin functions that can be replaced
|
||||
* by user implementations
|
||||
*
|
||||
* AttrSkipFrame is set to indicate that the frame should be ignored
|
||||
* when searching for the context (eg array_map evaluates its
|
||||
* callback in the context of its caller).
|
||||
*/
|
||||
enum Attr {
|
||||
AttrNone = 0, // class property method //
|
||||
AttrReference = (1 << 0), // X //
|
||||
AttrPublic = (1 << 1), // X X //
|
||||
AttrProtected = (1 << 2), // X X //
|
||||
AttrPrivate = (1 << 3), // X X //
|
||||
AttrStatic = (1 << 4), // X X //
|
||||
AttrAbstract = (1 << 5), // X X //
|
||||
AttrFinal = (1 << 6), // X X //
|
||||
AttrInterface = (1 << 7), // X //
|
||||
AttrPhpLeafFn = (1 << 7), // X //
|
||||
AttrTrait = (1 << 8), // X X //
|
||||
AttrNoInjection = (1 << 9), // X //
|
||||
AttrUnique = (1 << 10), // X X //
|
||||
AttrDynamicInvoke = (1 << 11), // X //
|
||||
AttrNoExpandTrait = (1 << 12), // X //
|
||||
AttrNoOverride= (1 << 13), // X X //
|
||||
AttrClone = (1 << 14), // X //
|
||||
AttrVariadicByRef = (1 << 15), // X //
|
||||
AttrMayUseVV = (1 << 16), // X //
|
||||
AttrPersistent= (1 << 17), // X X //
|
||||
AttrDeepInit = (1 << 18), // X //
|
||||
AttrHot = (1 << 19), // X //
|
||||
AttrBuiltin = (1 << 20), // X //
|
||||
AttrAllowOverride = (1 << 21), // X //
|
||||
AttrSkipFrame = (1 << 22), // X //
|
||||
};
|
||||
|
||||
inline Attr operator|(Attr a, Attr b) { return Attr((int)a | (int)b); }
|
||||
|
||||
inline const char * attrToVisibilityStr(Attr attr) {
|
||||
return (attr & AttrPrivate) ? "private" :
|
||||
(attr & AttrProtected) ? "protected" : "public";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/vm/fixed_string_map.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/macros.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "hphp/util/trace.h"
|
||||
#include "hphp/util/debug.h"
|
||||
#include "hphp/runtime/base/strings.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/runtime.h"
|
||||
#include "hphp/runtime/vm/repo.h"
|
||||
#include "hphp/runtime/vm/jit/targetcache.h"
|
||||
|
||||
@@ -29,6 +29,7 @@ const int kNumFixedPrologues = 6;
|
||||
|
||||
struct ActRec;
|
||||
typedef TypedValue*(*BuiltinFunction)(ActRec* ar);
|
||||
class PreClassEmitter;
|
||||
|
||||
/*
|
||||
* Unique identifier for a Func*.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hphp/util/base.h"
|
||||
|
||||
#include "hphp/runtime/base/execution_context.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/ext_hhvm/ext_hhvm.h"
|
||||
#include "hphp/runtime/vm/jit/translator.h"
|
||||
#include "hphp/runtime/vm/jit/targetcache.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef incl_HPHP_VM_HHBC_H_
|
||||
#define incl_HPHP_VM_HHBC_H_
|
||||
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -1,816 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
#include "hphp/runtime/base/base_includes.h"
|
||||
#include "hphp/runtime/base/variable_serializer.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/vm/member_operations.h"
|
||||
#include "hphp/runtime/vm/hhbc.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/object_allocator_sizes.h"
|
||||
#include "hphp/runtime/vm/jit/translator-inline.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
static StaticString s___get(LITSTR_INIT("__get"));
|
||||
static StaticString s___set(LITSTR_INIT("__set"));
|
||||
static StaticString s___isset(LITSTR_INIT("__isset"));
|
||||
static StaticString s___unset(LITSTR_INIT("__unset"));
|
||||
static StaticString s___call(LITSTR_INIT("__call"));
|
||||
static StaticString s___callStatic(LITSTR_INIT("__callStatic"));
|
||||
|
||||
TRACE_SET_MOD(runtime);
|
||||
|
||||
int HPHP::Instance::ObjAllocatorSizeClassCount =
|
||||
HPHP::InitializeAllocators();
|
||||
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps) {
|
||||
auto* dst = propVec;
|
||||
auto* src = propData;
|
||||
for (; src != propData + nProps; ++src, ++dst) {
|
||||
*dst = *src;
|
||||
// m_aux.u_deepInit is true for properties that need "deep" initialization
|
||||
if (src->deepInit()) {
|
||||
tvIncRef(dst);
|
||||
collectionDeepCopyTV(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue* Instance::propVec() {
|
||||
uintptr_t ret = (uintptr_t)this + sizeof(ObjectData) + builtinPropSize();
|
||||
// TODO(#1432007): some builtins still do not have TypedValue-aligned sizes.
|
||||
assert(ret % sizeof(TypedValue) == builtinPropSize() % sizeof(TypedValue));
|
||||
return (TypedValue*) ret;
|
||||
}
|
||||
|
||||
const TypedValue* Instance::propVec() const {
|
||||
return const_cast<Instance*>(this)->propVec();
|
||||
}
|
||||
|
||||
Instance* Instance::callCustomInstanceInit() {
|
||||
static StringData* sd_init = StringData::GetStaticString("__init__");
|
||||
const Func* init = m_cls->lookupMethod(sd_init);
|
||||
if (init != nullptr) {
|
||||
TypedValue tv;
|
||||
// We need to incRef/decRef here because we're still a new (_count
|
||||
// == 0) object and invokeFunc is going to expect us to have a
|
||||
// reasonable refcount.
|
||||
try {
|
||||
incRefCount();
|
||||
g_vmContext->invokeFuncFew(&tv, init, this);
|
||||
decRefCount();
|
||||
assert(!IS_REFCOUNTED_TYPE(tv.m_type));
|
||||
} catch (...) {
|
||||
this->setNoDestruct();
|
||||
decRefObj(this);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
HOT_FUNC_VM
|
||||
Instance* Instance::newInstanceRaw(Class* cls, int idx) {
|
||||
Instance* obj = (Instance*)ALLOCOBJIDX(idx);
|
||||
new (obj) Instance(cls, NoInit::noinit);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Instance::invokeUserMethod(TypedValue* retval, const Func* method,
|
||||
CArrRef params) {
|
||||
g_vmContext->invokeFunc(retval, method, params, this);
|
||||
}
|
||||
|
||||
Object Instance::FromArray(ArrayData *properties) {
|
||||
Instance* retval = Instance::newInstance(SystemLib::s_stdclassClass);
|
||||
retval->initDynProps();
|
||||
HphpArray* props = static_cast<HphpArray*>(retval->o_properties.get());
|
||||
for (ssize_t pos = properties->iter_begin(); pos != ArrayData::invalid_index;
|
||||
pos = properties->iter_advance(pos)) {
|
||||
TypedValue* value = properties->nvGetValueRef(pos);
|
||||
TypedValue key;
|
||||
properties->nvGetKey(&key, pos);
|
||||
if (key.m_type == KindOfInt64) {
|
||||
props->set(key.m_data.num, tvAsCVarRef(value), false);
|
||||
} else {
|
||||
assert(IS_STRING_TYPE(key.m_type));
|
||||
StringData* strKey = key.m_data.pstr;
|
||||
props->set(strKey, tvAsCVarRef(value), false);
|
||||
decRefStr(strKey);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Instance::initDynProps(int numDynamic /* = 0 */) {
|
||||
// Create o_properties with room for numDynamic
|
||||
o_properties.asArray() = ArrayData::Make(numDynamic);
|
||||
}
|
||||
|
||||
Slot Instance::declPropInd(TypedValue* prop) const {
|
||||
// Do an address range check to determine whether prop physically resides
|
||||
// in propVec.
|
||||
const TypedValue* pv = propVec();
|
||||
if (prop >= pv && prop < &pv[m_cls->numDeclProperties()]) {
|
||||
return prop - pv;
|
||||
} else {
|
||||
return kInvalidSlot;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool declOnly>
|
||||
TypedValue* Instance::getPropImpl(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible,
|
||||
bool& unset) {
|
||||
TypedValue* prop = nullptr;
|
||||
unset = false;
|
||||
Slot propInd = m_cls->getDeclPropIndex(ctx, key, accessible);
|
||||
visible = (propInd != kInvalidSlot);
|
||||
if (propInd != kInvalidSlot) {
|
||||
// We found a visible property, but it might not be accessible.
|
||||
// No need to check if there is a dynamic property with this name.
|
||||
prop = &propVec()[propInd];
|
||||
if (prop->m_type == KindOfUninit) {
|
||||
unset = true;
|
||||
}
|
||||
} else {
|
||||
assert(!visible && !accessible);
|
||||
// We could not find a visible property. We need to check for a
|
||||
// dynamic property with this name if declOnly = false.
|
||||
if (!declOnly && o_properties.get()) {
|
||||
prop = static_cast<HphpArray*>(o_properties.get())->nvGet(key);
|
||||
if (prop) {
|
||||
// o_properties.get()->nvGet() returned a non-declared property,
|
||||
// we know that it is visible and accessible (since all
|
||||
// dynamic properties are), and we know it is not unset
|
||||
// (since unset dynamic properties don't appear in o_properties.get()).
|
||||
visible = true;
|
||||
accessible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
TypedValue* Instance::getProp(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible, bool& unset) {
|
||||
return getPropImpl<false>(ctx, key, visible, accessible, unset);
|
||||
}
|
||||
|
||||
TypedValue* Instance::getDeclProp(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible,
|
||||
bool& unset) {
|
||||
return getPropImpl<true>(ctx, key, visible, accessible, unset);
|
||||
}
|
||||
|
||||
void Instance::invokeSet(TypedValue* retval, const StringData* key,
|
||||
TypedValue* val) {
|
||||
AttributeClearer a(UseSet, this);
|
||||
const Func* meth = m_cls->lookupMethod(s___set.get());
|
||||
assert(meth);
|
||||
invokeUserMethod(retval, meth,
|
||||
CREATE_VECTOR2(CStrRef(key), tvAsVariant(val)));
|
||||
}
|
||||
|
||||
#define MAGIC_PROP_BODY(name, attr) \
|
||||
AttributeClearer a((attr), this); \
|
||||
const Func* meth = m_cls->lookupMethod(name); \
|
||||
assert(meth); \
|
||||
invokeUserMethod(retval, meth, CREATE_VECTOR1(CStrRef(key))); \
|
||||
|
||||
void Instance::invokeGet(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___get.get(), UseGet);
|
||||
}
|
||||
|
||||
void Instance::invokeIsset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___isset.get(), UseIsset);
|
||||
}
|
||||
|
||||
void Instance::invokeUnset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___unset.get(), UseUnset);
|
||||
}
|
||||
|
||||
void Instance::invokeGetProp(TypedValue*& retval, TypedValue& tvRef,
|
||||
const StringData* key) {
|
||||
invokeGet(&tvRef, key);
|
||||
retval = &tvRef;
|
||||
}
|
||||
|
||||
template <bool warn, bool define>
|
||||
void Instance::propImpl(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx,
|
||||
const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
|
||||
if (visible) {
|
||||
if (accessible) {
|
||||
if (unset) {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
if (warn) {
|
||||
raiseUndefProp(key);
|
||||
}
|
||||
if (define) {
|
||||
retval = propVal;
|
||||
} else {
|
||||
retval = (TypedValue*)&init_null_variant;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
retval = propVal;
|
||||
}
|
||||
} else {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
// No need to check hasProp since visible is true
|
||||
// Visibility is either protected or private since accessible is false
|
||||
Slot propInd = m_cls->lookupDeclProp(key);
|
||||
bool priv = m_cls->declProperties()[propInd].m_attrs & AttrPrivate;
|
||||
|
||||
raise_error("Cannot access %s property %s::$%s",
|
||||
priv ? "private" : "protected",
|
||||
m_cls->m_preClass->name()->data(),
|
||||
key->data());
|
||||
}
|
||||
}
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else {
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGetProp(retval, tvRef, key);
|
||||
} else {
|
||||
if (warn) {
|
||||
raiseUndefProp(key);
|
||||
}
|
||||
if (define) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&retval), false);
|
||||
} else {
|
||||
retval = (TypedValue*)&init_null_variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::prop(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<false, false>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propD(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<false, true>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propW(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<true, false>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
void Instance::propWD(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
propImpl<true, true>(retval, tvRef, ctx, key);
|
||||
}
|
||||
|
||||
bool Instance::propIsset(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
return isset(tvAsCVarRef(propVal));
|
||||
}
|
||||
if (!getAttribute(UseIsset)) {
|
||||
return false;
|
||||
}
|
||||
TypedValue tv;
|
||||
tvWriteUninit(&tv);
|
||||
invokeIsset(&tv, key);
|
||||
tvCastToBooleanInPlace(&tv);
|
||||
return tv.m_data.num;
|
||||
}
|
||||
|
||||
bool Instance::propEmpty(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
return empty(tvAsCVarRef(propVal));
|
||||
}
|
||||
if (!getAttribute(UseIsset)) {
|
||||
return true;
|
||||
}
|
||||
TypedValue tv;
|
||||
tvWriteUninit(&tv);
|
||||
invokeIsset(&tv, key);
|
||||
tvCastToBooleanInPlace(&tv);
|
||||
if (!tv.m_data.num) {
|
||||
return true;
|
||||
}
|
||||
if (getAttribute(UseGet)) {
|
||||
invokeGet(&tv, key);
|
||||
bool emptyResult = empty(tvAsCVarRef(&tv));
|
||||
tvRefcountedDecRef(&tv);
|
||||
return emptyResult;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setProp(Class* ctx, const StringData* key,
|
||||
TypedValue* val,
|
||||
bool bindingAssignment /* = false */) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseSet)) {
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, val);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
} else {
|
||||
if (UNLIKELY(bindingAssignment)) {
|
||||
tvBind(val, propVal);
|
||||
} else {
|
||||
tvSet(*val, *propVal);
|
||||
}
|
||||
}
|
||||
// Return a pointer to the property if it's a declared property
|
||||
return declPropInd(propVal) != kInvalidSlot ? propVal : nullptr;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
// when seting a dynamic property, do not write
|
||||
// directly to the TypedValue in the HphpArray, since
|
||||
// its _count field is used to store the string hash of
|
||||
// the property name. Instead, call the appropriate
|
||||
// setters (set() or setRef()).
|
||||
if (UNLIKELY(bindingAssignment)) {
|
||||
o_properties.get()->setRef(const_cast<StringData*>(key),
|
||||
tvAsCVarRef(val), false);
|
||||
} else {
|
||||
o_properties.get()->set(const_cast<StringData*>(key),
|
||||
tvAsCVarRef(val), false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseSet));
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, val);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
Cell* val) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseGet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
SETOP_BODY(&tvResult, op, val);
|
||||
if (getAttribute(UseSet)) {
|
||||
assert(tvRef.m_type == KindOfUninit);
|
||||
memcpy(&tvRef, &tvResult, sizeof(TypedValue));
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
} else {
|
||||
memcpy(propVal, &tvResult, sizeof(TypedValue));
|
||||
}
|
||||
} else {
|
||||
SETOP_BODY(propVal, op, val);
|
||||
}
|
||||
return propVal;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseGet) || !getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseGet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
SETOP_BODY(propVal, op, val);
|
||||
return propVal;
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
SETOP_BODY(&tvResult, op, val);
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
return propVal;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseGet) && getAttribute(UseSet));
|
||||
invokeGet(&tvRef, key);
|
||||
SETOP_BODY(&tvRef, op, val);
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
return propVal;
|
||||
}
|
||||
|
||||
template <bool setResult>
|
||||
void Instance::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
assert(propVal);
|
||||
if (unset && getAttribute(UseGet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
IncDecBody<setResult>(op, &tvResult, &dest);
|
||||
if (getAttribute(UseSet)) {
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvResult);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvResult;
|
||||
} else {
|
||||
memcpy((void *)propVal, (void *)&tvResult, sizeof(TypedValue));
|
||||
}
|
||||
} else {
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(!accessible);
|
||||
if (visible) {
|
||||
assert(propVal);
|
||||
if (!getAttribute(UseGet) || !getAttribute(UseSet)) {
|
||||
raise_error("Cannot access protected property");
|
||||
}
|
||||
// Fall through to the last case below
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else if (!getAttribute(UseGet)) {
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
return;
|
||||
} else if (!getAttribute(UseSet)) {
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
invokeGet(&tvResult, key);
|
||||
IncDecBody<setResult>(op, &tvResult, &dest);
|
||||
if (o_properties.get() == nullptr) {
|
||||
initDynProps();
|
||||
}
|
||||
o_properties.get()->createLvalPtr(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
return;
|
||||
}
|
||||
assert(!accessible);
|
||||
assert(getAttribute(UseGet) && getAttribute(UseSet));
|
||||
invokeGet(&tvRef, key);
|
||||
IncDecBody<setResult>(op, &tvRef, &dest);
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, key, &tvRef);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvRef;
|
||||
}
|
||||
|
||||
// Actualize template method so that the method can be defined in instance.cpp
|
||||
// (rather than instance.h), but still be invoked elsewhere.
|
||||
template <>
|
||||
void Instance::incDecProp<false>(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
incDecPropImpl<false>(tvRef, ctx, op, key, dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Instance::incDecProp<true>(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
incDecPropImpl<true>(tvRef, ctx, op, key, dest);
|
||||
}
|
||||
|
||||
void Instance::unsetProp(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
Slot propInd = declPropInd(propVal);
|
||||
if (propInd != kInvalidSlot) {
|
||||
// Declared property.
|
||||
tvSetIgnoreRef(*null_variant.asTypedValue(), *propVal);
|
||||
} else {
|
||||
// Dynamic property.
|
||||
assert(o_properties.get() != nullptr);
|
||||
o_properties.get()->remove(CStrRef(key), false);
|
||||
}
|
||||
} else if (UNLIKELY(!*key->data())) {
|
||||
throw_invalid_property_name(StrNR(key));
|
||||
} else {
|
||||
assert(!accessible);
|
||||
if (getAttribute(UseUnset)) {
|
||||
TypedValue ignored;
|
||||
invokeUnset(&ignored, key);
|
||||
tvRefcountedDecRef(&ignored);
|
||||
} else if (visible) {
|
||||
raise_error("Cannot unset inaccessible property");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::raiseUndefProp(const StringData* key) {
|
||||
raise_notice("Undefined property: %s::$%s",
|
||||
m_cls->name()->data(), key->data());
|
||||
}
|
||||
|
||||
void Instance::getProp(const Class* klass, bool pubOnly,
|
||||
const PreClass::Prop* prop,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
if (prop->attrs() & AttrStatic) {
|
||||
return;
|
||||
}
|
||||
|
||||
Slot propInd = klass->lookupDeclProp(prop->name());
|
||||
assert(propInd != kInvalidSlot);
|
||||
const TypedValue* propVal = &propVec()[propInd];
|
||||
|
||||
if ((!pubOnly || (prop->attrs() & AttrPublic)) &&
|
||||
propVal->m_type != KindOfUninit &&
|
||||
!inserted[propInd]) {
|
||||
inserted[propInd] = true;
|
||||
props.lvalAt(CStrRef(klass->declProperties()[propInd].m_mangledName))
|
||||
.setWithRef(tvAsCVarRef(propVal));
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::getProps(const Class* klass, bool pubOnly,
|
||||
const PreClass* pc,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
PreClass::Prop const* propVec = pc->properties();
|
||||
size_t count = pc->numProperties();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
getProp(klass, pubOnly, &propVec[i], props, inserted);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___destruct() {
|
||||
static StringData* sd__destruct = StringData::GetStaticString("__destruct");
|
||||
const Func* method = m_cls->lookupMethod(sd__destruct);
|
||||
if (method) {
|
||||
Variant v;
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___call(Variant v_name, Variant v_arguments) {
|
||||
static StringData* sd__call = StringData::GetStaticString("__call");
|
||||
const Func* method = m_cls->lookupMethod(sd__call);
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[2];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
tvDup(*v_arguments.asTypedValue(), args[1]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 2,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___set(Variant v_name, Variant v_value) {
|
||||
const Func* method = m_cls->lookupMethod(s___set.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
g_vmContext->invokeFunc(v.asTypedValue(), method,
|
||||
Array(ArrayInit(2).set(v_name).set(withRefBind(v_value)).create()),
|
||||
this);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___get(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___get.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
bool Instance::t___isset(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___isset.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v.toBoolean();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___unset(Variant v_name) {
|
||||
const Func* method = m_cls->lookupMethod(s___unset.get());
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_name.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___sleep() {
|
||||
static StringData* sd__sleep = StringData::GetStaticString("__sleep");
|
||||
const Func *method = m_cls->lookupMethod(sd__sleep);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return tvAsVariant(&tv);
|
||||
} else {
|
||||
clearAttribute(HasSleep);
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___wakeup() {
|
||||
static StringData* sd__wakeup = StringData::GetStaticString("__wakeup");
|
||||
const Func *method = m_cls->lookupMethod(sd__wakeup);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return tvAsVariant(&tv);
|
||||
} else {
|
||||
return uninit_null();
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___set_state(Variant v_properties) {
|
||||
static StringData* sd__set_state = StringData::GetStaticString("__set_state");
|
||||
const Func* method = m_cls->lookupMethod(sd__set_state);
|
||||
if (method) {
|
||||
Variant v;
|
||||
TypedValue args[1];
|
||||
tvDup(*v_properties.asTypedValue(), args[0]);
|
||||
g_vmContext->invokeFuncFew(v.asTypedValue(), method, this, nullptr, 1,
|
||||
args);
|
||||
return v;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String Instance::t___tostring() {
|
||||
const Func *method = m_cls->getToString();
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
if (!IS_STRING_TYPE(tv.m_type)) {
|
||||
void (*notify_user)(const char *, ...) = &raise_error;
|
||||
if (hphpiCompat) {
|
||||
tvCastToStringInPlace(&tv);
|
||||
notify_user = &raise_warning;
|
||||
}
|
||||
notify_user("Method %s::__toString() must return a string value",
|
||||
m_cls->m_preClass->name()->data());
|
||||
}
|
||||
return tv.m_data.pstr;
|
||||
} else {
|
||||
std::string msg = m_cls->m_preClass->name()->data();
|
||||
msg += "::__toString() was not defined";
|
||||
throw BadTypeConversionException(msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___clone() {
|
||||
static StringData* sd__clone = StringData::GetStaticString("__clone");
|
||||
const Func *method = m_cls->lookupMethod(sd__clone);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::cloneSet(ObjectData* clone) {
|
||||
Instance* iclone = static_cast<Instance*>(clone);
|
||||
Slot nProps = m_cls->numDeclProperties();
|
||||
TypedValue* iclonePropVec = (TypedValue *)((uintptr_t)iclone +
|
||||
sizeof(ObjectData) + builtinPropSize());
|
||||
for (Slot i = 0; i < nProps; i++) {
|
||||
tvRefcountedDecRef(&iclonePropVec[i]);
|
||||
tvDupFlattenVars(&propVec()[i], &iclonePropVec[i], nullptr);
|
||||
}
|
||||
if (o_properties.get()) {
|
||||
iclone->initDynProps();
|
||||
ssize_t iter = o_properties.get()->iter_begin();
|
||||
while (iter != HphpArray::ElmIndEmpty) {
|
||||
auto props = static_cast<HphpArray*>(o_properties.get());
|
||||
TypedValue key;
|
||||
props->nvGetKey(&key, iter);
|
||||
assert(tvIsString(&key));
|
||||
StringData* strKey = key.m_data.pstr;
|
||||
TypedValue *val = props->nvGet(strKey);
|
||||
TypedValue *retval;
|
||||
auto cloneProps = iclone->o_properties.get();
|
||||
cloneProps->createLvalPtr(strKey, *(Variant**)&retval, false);
|
||||
tvDupFlattenVars(val, retval, cloneProps);
|
||||
iter = o_properties.get()->iter_advance(iter);
|
||||
decRefStr(strKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjectData* Instance::cloneImpl() {
|
||||
Instance* obj = Instance::newInstance(m_cls);
|
||||
cloneSet(obj);
|
||||
obj->incRefCount();
|
||||
obj->t___clone();
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // HPHP::VM
|
||||
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_VM_INSTANCE_H_
|
||||
#define incl_HPHP_VM_INSTANCE_H_
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/memory/smart_allocator.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
#include "hphp/runtime/base/runtime_option.h"
|
||||
#include "hphp/runtime/base/array/hphp_array.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps);
|
||||
|
||||
class Instance : public ObjectData {
|
||||
// Do not declare any fields directly in Instance; instead embed them in
|
||||
// ObjectData, so that a property vector can always reside immediately past
|
||||
// the end of an object.
|
||||
|
||||
private:
|
||||
// This constructor is used for all pure classes that are not
|
||||
// descendents of cppext classes
|
||||
explicit Instance(Class* cls) : ObjectData(false, cls) {
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
enum class NoInit { noinit };
|
||||
explicit Instance(Class* cls, NoInit) : ObjectData(false, cls) {}
|
||||
|
||||
public:
|
||||
// This constructor is used for all cppext classes (including resources)
|
||||
// and their descendents.
|
||||
Instance(Class* cls, bool isResource)
|
||||
: ObjectData(isResource, cls) {
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
virtual ~Instance() {}
|
||||
|
||||
static int ObjAllocatorSizeClassCount;
|
||||
|
||||
// Call newInstance() to instantiate an Instance
|
||||
static Instance* newInstance(Class* cls) {
|
||||
if (cls->m_InstanceCtor) {
|
||||
return cls->m_InstanceCtor(cls);
|
||||
}
|
||||
Attr attrs = cls->attrs();
|
||||
if (UNLIKELY(attrs & (AttrAbstract | AttrInterface | AttrTrait))) {
|
||||
raise_error("Cannot instantiate %s %s",
|
||||
(attrs & AttrInterface) ? "interface" :
|
||||
(attrs & AttrTrait) ? "trait" : "abstract class",
|
||||
cls->preClass()->name()->data());
|
||||
}
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t size = sizeForNProps(nProps);
|
||||
Instance* obj = (Instance*)ALLOCOBJSZ(size);
|
||||
new (obj) Instance(cls);
|
||||
if (UNLIKELY(cls->callsCustomInstanceInit())) {
|
||||
/*
|
||||
This must happen after the constructor finishes,
|
||||
because it can leak references to obj AND it can
|
||||
throw exceptions. If we have this in the Instance
|
||||
constructor, and it throws, obj will be partially
|
||||
destroyed (ie ~ObjectData will be called, resetting
|
||||
the vtable pointer) leaving dangling references
|
||||
to the object (eg in backtraces).
|
||||
*/
|
||||
obj->callCustomInstanceInit();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Given a Class that is assumed to be a concrete, regular (not a
|
||||
// trait or interface), pure PHP class, and an allocator index,
|
||||
// return a new, uninitialized object of that class.
|
||||
static Instance* newInstanceRaw(Class* cls, int idx);
|
||||
|
||||
private:
|
||||
void instanceInit(Class* cls) {
|
||||
setAttributes(cls->getODAttrs());
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
if (cls->needInitialization()) {
|
||||
cls->initialize();
|
||||
}
|
||||
if (nProps > 0) {
|
||||
if (cls->pinitVec().size() > 0) {
|
||||
const Class::PropInitVec* propInitVec = m_cls->getPropData();
|
||||
assert(propInitVec != nullptr);
|
||||
assert(nProps == propInitVec->size());
|
||||
if (!cls->hasDeepInitProps()) {
|
||||
memcpy(propVec(), &(*propInitVec)[0], nProps * sizeof(TypedValue));
|
||||
} else {
|
||||
deepInitHelper(propVec(), &(*propInitVec)[0], nProps);
|
||||
}
|
||||
} else {
|
||||
assert(nProps == cls->declPropInit().size());
|
||||
memcpy(propVec(), &cls->declPropInit()[0], nProps * sizeof(TypedValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
TypedValue* propVec();
|
||||
const TypedValue* propVec() const;
|
||||
|
||||
public:
|
||||
Instance* callCustomInstanceInit();
|
||||
|
||||
void operator delete(void* p) {
|
||||
Instance* this_ = (Instance*)p;
|
||||
Class* cls = this_->getVMClass();
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
// cppext classes have their own implementation of delete
|
||||
assert(this_->builtinPropSize() == 0);
|
||||
TypedValue* propVec = (TypedValue *)((uintptr_t)this_ + sizeof(ObjectData));
|
||||
for (unsigned i = 0; i < nProps; ++i) {
|
||||
TypedValue* prop = &propVec[i];
|
||||
tvRefcountedDecRef(prop);
|
||||
}
|
||||
DELETEOBJSZ(sizeForNProps(nProps))(this_);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Virtual ObjectData methods that we need to override
|
||||
|
||||
public:
|
||||
virtual Variant t___destruct();
|
||||
virtual Variant t___call(Variant v_name, Variant v_arguments);
|
||||
virtual Variant t___set(Variant v_name, Variant v_value);
|
||||
virtual Variant t___get(Variant v_name);
|
||||
virtual bool t___isset(Variant v_name);
|
||||
virtual Variant t___unset(Variant v_name);
|
||||
virtual Variant t___sleep();
|
||||
virtual Variant t___wakeup();
|
||||
virtual Variant t___set_state(Variant v_properties);
|
||||
virtual String t___tostring();
|
||||
virtual Variant t___clone();
|
||||
|
||||
//============================================================================
|
||||
// Miscellaneous.
|
||||
|
||||
void cloneSet(ObjectData* clone);
|
||||
ObjectData* cloneImpl();
|
||||
|
||||
void invokeUserMethod(TypedValue* retval, const Func* method,
|
||||
CArrRef params);
|
||||
|
||||
const Func* methodNamed(const StringData* sd) const {
|
||||
return getVMClass()->lookupMethod(sd);
|
||||
}
|
||||
|
||||
static size_t sizeForNProps(Slot nProps) {
|
||||
size_t sz = sizeof(Instance) + (sizeof(TypedValue) * nProps);
|
||||
assert((sz & (sizeof(TypedValue) - 1)) == 0);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static Object FromArray(ArrayData *properties);
|
||||
|
||||
//============================================================================
|
||||
// Properties.
|
||||
public:
|
||||
int builtinPropSize() const {
|
||||
return m_cls->builtinPropSize();
|
||||
}
|
||||
|
||||
// public for ObjectData access
|
||||
void initDynProps(int numDynamic = 0);
|
||||
Slot declPropInd(TypedValue* prop) const;
|
||||
private:
|
||||
template <bool declOnly>
|
||||
TypedValue* getPropImpl(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
public:
|
||||
TypedValue* getProp(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
TypedValue* getDeclProp(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
private:
|
||||
template <bool warn, bool define>
|
||||
void propImpl(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void invokeSet(TypedValue* retval, const StringData* key, TypedValue* val);
|
||||
void invokeGet(TypedValue* retval, const StringData* key);
|
||||
void invokeGetProp(TypedValue*& retval, TypedValue& tvRef,
|
||||
const StringData* key);
|
||||
void invokeIsset(TypedValue* retval, const StringData* key);
|
||||
void invokeUnset(TypedValue* retval, const StringData* key);
|
||||
void getProp(const Class* klass, bool pubOnly, const PreClass::Prop* prop,
|
||||
Array& props, std::vector<bool>& inserted) const;
|
||||
void getProps(const Class* klass, bool pubOnly, const PreClass* pc,
|
||||
Array& props, std::vector<bool>& inserted) const;
|
||||
public:
|
||||
void prop(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propD(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propW(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
void propWD(TypedValue*& retval, TypedValue& tvRef, Class* ctx,
|
||||
const StringData* key);
|
||||
bool propIsset(Class* ctx, const StringData* key);
|
||||
bool propEmpty(Class* ctx, const StringData* key);
|
||||
|
||||
TypedValue* setProp(Class* ctx, const StringData* key, TypedValue* val,
|
||||
bool bindingAssignment = false);
|
||||
TypedValue* setOpProp(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, Cell* val);
|
||||
private:
|
||||
template <bool setResult>
|
||||
void incDecPropImpl(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, TypedValue& dest);
|
||||
public:
|
||||
template <bool setResult>
|
||||
void incDecProp(TypedValue& tvRef, Class* ctx, unsigned char op,
|
||||
const StringData* key, TypedValue& dest);
|
||||
void unsetProp(Class* ctx, const StringData* key);
|
||||
|
||||
void raiseUndefProp(const StringData* name);
|
||||
|
||||
friend class ObjectData;
|
||||
};
|
||||
|
||||
inline Instance* instanceFromTv(TypedValue* tv) {
|
||||
assert(dynamic_cast<Instance*>(tv->m_data.pobj));
|
||||
return static_cast<Instance*>(tv->m_data.pobj);
|
||||
}
|
||||
|
||||
} // HPHP::VM
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
class ExtObjectData : public HPHP::Instance {
|
||||
public:
|
||||
explicit ExtObjectData(HPHP::Class* cls)
|
||||
: HPHP::Instance(cls, false) {
|
||||
assert(!m_cls->callsCustomInstanceInit());
|
||||
}
|
||||
};
|
||||
|
||||
template <int flags> class ExtObjectDataFlags : public ExtObjectData {
|
||||
public:
|
||||
explicit ExtObjectDataFlags(HPHP::Class* cb) : ExtObjectData(cb) {
|
||||
ObjectData::setAttributes(flags);
|
||||
}
|
||||
};
|
||||
|
||||
} // HPHP
|
||||
|
||||
#endif
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "hphp/runtime/base/strings.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
#include "hphp/runtime/base/builtin_functions.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/runtime.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/base/tv_conversions.h"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/vm/name_value_table_wrapper.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/array/array_iterator.h"
|
||||
#include "hphp/runtime/base/array/array_init.h"
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "tbb/concurrent_unordered_map.h"
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
#include "hphp/util/atomic.h"
|
||||
#include "folly/AtomicHashMap.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "hphp/runtime/vm/preclass-emit.h"
|
||||
#include "hphp/runtime/vm/repo.h"
|
||||
#include "hphp/runtime/vm/blob_helper.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
//=============================================================================
|
||||
// PreClassEmitter::Prop.
|
||||
|
||||
PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
|
||||
const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType)
|
||||
: m_name(n)
|
||||
, m_attrs(attrs)
|
||||
, m_typeConstraint(typeConstraint)
|
||||
, m_docComment(docComment)
|
||||
, m_hphpcType(hphpcType)
|
||||
{
|
||||
m_mangledName = PreClass::manglePropName(pce->name(), n, attrs);
|
||||
memcpy(&m_val, val, sizeof(TypedValue));
|
||||
}
|
||||
|
||||
PreClassEmitter::Prop::~Prop() {
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PreClassEmitter.
|
||||
|
||||
PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
|
||||
Id id,
|
||||
const StringData* n,
|
||||
PreClass::Hoistable hoistable)
|
||||
: m_ue(ue)
|
||||
, m_name(n)
|
||||
, m_id(id)
|
||||
, m_hoistable(hoistable)
|
||||
, m_InstanceCtor(nullptr)
|
||||
, m_builtinPropSize(0)
|
||||
{}
|
||||
|
||||
void PreClassEmitter::init(int line1, int line2, Offset offset, Attr attrs,
|
||||
const StringData* parent,
|
||||
const StringData* docComment) {
|
||||
m_line1 = line1;
|
||||
m_line2 = line2;
|
||||
m_offset = offset;
|
||||
m_attrs = attrs;
|
||||
m_parent = parent;
|
||||
m_docComment = docComment;
|
||||
}
|
||||
|
||||
PreClassEmitter::~PreClassEmitter() {
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassEmitter::addInterface(const StringData* n) {
|
||||
m_interfaces.push_back(n);
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addMethod(FuncEmitter* method) {
|
||||
MethodMap::const_iterator it = m_methodMap.find(method->name());
|
||||
if (it != m_methodMap.end()) {
|
||||
return false;
|
||||
}
|
||||
m_methods.push_back(method);
|
||||
m_methodMap[method->name()] = method;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addProperty(const StringData* n, Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType) {
|
||||
PropMap::Builder::const_iterator it = m_propMap.find(n);
|
||||
if (it != m_propMap.end()) {
|
||||
return false;
|
||||
}
|
||||
PreClassEmitter::Prop prop(this, n, attrs, typeConstraint, docComment, val,
|
||||
hphpcType);
|
||||
m_propMap.add(prop.name(), prop);
|
||||
return true;
|
||||
}
|
||||
|
||||
const PreClassEmitter::Prop&
|
||||
PreClassEmitter::lookupProp(const StringData* propName) const {
|
||||
PropMap::Builder::const_iterator it = m_propMap.find(propName);
|
||||
assert(it != m_propMap.end());
|
||||
Slot idx = it->second;
|
||||
return m_propMap[idx];
|
||||
}
|
||||
|
||||
bool PreClassEmitter::addConstant(const StringData* n,
|
||||
const StringData* typeConstraint,
|
||||
TypedValue* val,
|
||||
const StringData* phpCode) {
|
||||
ConstMap::Builder::const_iterator it = m_constMap.find(n);
|
||||
if (it != m_constMap.end()) {
|
||||
return false;
|
||||
}
|
||||
PreClassEmitter::Const const_(n, typeConstraint, val, phpCode);
|
||||
m_constMap.add(const_.name(), const_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PreClassEmitter::addUsedTrait(const StringData* traitName) {
|
||||
m_usedTraits.push_back(traitName);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addTraitPrecRule(
|
||||
const PreClass::TraitPrecRule &rule) {
|
||||
m_traitPrecRules.push_back(rule);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addTraitAliasRule(
|
||||
const PreClass::TraitAliasRule &rule) {
|
||||
m_traitAliasRules.push_back(rule);
|
||||
}
|
||||
|
||||
void PreClassEmitter::addUserAttribute(const StringData* name, TypedValue tv) {
|
||||
m_userAttributes[name] = tv;
|
||||
}
|
||||
|
||||
void PreClassEmitter::commit(RepoTxn& txn) const {
|
||||
Repo& repo = Repo::get();
|
||||
PreClassRepoProxy& pcrp = repo.pcrp();
|
||||
int repoId = m_ue.repoId();
|
||||
int64_t usn = m_ue.sn();
|
||||
pcrp.insertPreClass(repoId)
|
||||
.insert(*this, txn, usn, m_id, m_name, m_hoistable);
|
||||
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
(*it)->commit(txn);
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassEmitter::setBuiltinClassInfo(const ClassInfo* info,
|
||||
BuiltinCtorFunction ctorFunc,
|
||||
int sz) {
|
||||
if (info->getAttribute() & ClassInfo::IsFinal) {
|
||||
m_attrs = m_attrs | AttrFinal;
|
||||
}
|
||||
if (info->getAttribute() & ClassInfo::IsAbstract) {
|
||||
m_attrs = m_attrs | AttrAbstract;
|
||||
}
|
||||
if (info->getAttribute() & ClassInfo::IsTrait) {
|
||||
m_attrs = m_attrs | AttrTrait;
|
||||
}
|
||||
m_attrs = m_attrs | AttrUnique;
|
||||
m_InstanceCtor = ctorFunc;
|
||||
m_builtinPropSize = sz - sizeof(ObjectData);
|
||||
}
|
||||
|
||||
PreClass* PreClassEmitter::create(Unit& unit) const {
|
||||
Attr attrs = m_attrs;
|
||||
if (attrs & AttrPersistent &&
|
||||
!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) {
|
||||
attrs = Attr(attrs & ~AttrPersistent);
|
||||
}
|
||||
PreClass* pc = new PreClass(&unit, m_line1, m_line2, m_offset, m_name,
|
||||
attrs, m_parent, m_docComment, m_id,
|
||||
m_hoistable);
|
||||
pc->m_InstanceCtor = m_InstanceCtor;
|
||||
pc->m_builtinPropSize = m_builtinPropSize;
|
||||
pc->m_interfaces = m_interfaces;
|
||||
pc->m_usedTraits = m_usedTraits;
|
||||
pc->m_traitPrecRules = m_traitPrecRules;
|
||||
pc->m_traitAliasRules = m_traitAliasRules;
|
||||
pc->m_userAttributes = m_userAttributes;
|
||||
|
||||
PreClass::MethodMap::Builder methodBuild;
|
||||
for (MethodVec::const_iterator it = m_methods.begin();
|
||||
it != m_methods.end(); ++it) {
|
||||
Func* f = (*it)->create(unit, pc);
|
||||
methodBuild.add(f->name(), f);
|
||||
}
|
||||
pc->m_methods.create(methodBuild);
|
||||
|
||||
PreClass::PropMap::Builder propBuild;
|
||||
for (unsigned i = 0; i < m_propMap.size(); ++i) {
|
||||
const Prop& prop = m_propMap[i];
|
||||
propBuild.add(prop.name(), PreClass::Prop(pc,
|
||||
prop.name(),
|
||||
prop.attrs(),
|
||||
prop.typeConstraint(),
|
||||
prop.docComment(),
|
||||
prop.val(),
|
||||
prop.hphpcType()));
|
||||
}
|
||||
pc->m_properties.create(propBuild);
|
||||
|
||||
PreClass::ConstMap::Builder constBuild;
|
||||
for (unsigned i = 0; i < m_constMap.size(); ++i) {
|
||||
const Const& const_ = m_constMap[i];
|
||||
constBuild.add(const_.name(), PreClass::Const(pc,
|
||||
const_.name(),
|
||||
const_.typeConstraint(),
|
||||
const_.val(),
|
||||
const_.phpCode()));
|
||||
}
|
||||
pc->m_constants.create(constBuild);
|
||||
return pc;
|
||||
}
|
||||
|
||||
template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
|
||||
// NOTE: name, hoistable, and a few other fields currently
|
||||
// serialized outside of this.
|
||||
sd(m_line1)
|
||||
(m_line2)
|
||||
(m_offset)
|
||||
(m_attrs)
|
||||
(m_parent)
|
||||
(m_docComment)
|
||||
|
||||
(m_interfaces)
|
||||
(m_usedTraits)
|
||||
(m_traitPrecRules)
|
||||
(m_traitAliasRules)
|
||||
(m_userAttributes)
|
||||
(m_propMap)
|
||||
(m_constMap)
|
||||
;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PreClassRepoProxy.
|
||||
|
||||
PreClassRepoProxy::PreClassRepoProxy(Repo& repo)
|
||||
: RepoProxy(repo)
|
||||
#define PCRP_OP(c, o) \
|
||||
, m_##o##Local(repo, RepoIdLocal), m_##o##Central(repo, RepoIdCentral)
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
{
|
||||
#define PCRP_OP(c, o) \
|
||||
m_##o[RepoIdLocal] = &m_##o##Local; \
|
||||
m_##o[RepoIdCentral] = &m_##o##Central;
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
}
|
||||
|
||||
PreClassRepoProxy::~PreClassRepoProxy() {
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::createSchema(int repoId, RepoTxn& txn) {
|
||||
{
|
||||
std::stringstream ssCreate;
|
||||
ssCreate << "CREATE TABLE " << m_repo.table(repoId, "PreClass")
|
||||
<< "(unitSn INTEGER, preClassId INTEGER, name TEXT,"
|
||||
" hoistable INTEGER, extraData BLOB,"
|
||||
" PRIMARY KEY (unitSn, preClassId));";
|
||||
txn.exec(ssCreate.str());
|
||||
}
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::InsertPreClassStmt
|
||||
::insert(const PreClassEmitter& pce, RepoTxn& txn,
|
||||
int64_t unitSn, Id preClassId,
|
||||
const StringData* name,
|
||||
PreClass::Hoistable hoistable) {
|
||||
if (!prepared()) {
|
||||
std::stringstream ssInsert;
|
||||
ssInsert << "INSERT INTO " << m_repo.table(m_repoId, "PreClass")
|
||||
<< " VALUES(@unitSn, @preClassId, @name, @hoistable, "
|
||||
"@extraData);";
|
||||
txn.prepare(*this, ssInsert.str());
|
||||
}
|
||||
|
||||
BlobEncoder extraBlob;
|
||||
RepoTxnQuery query(txn, *this);
|
||||
query.bindInt64("@unitSn", unitSn);
|
||||
query.bindId("@preClassId", preClassId);
|
||||
query.bindStaticString("@name", name);
|
||||
query.bindInt("@hoistable", hoistable);
|
||||
const_cast<PreClassEmitter&>(pce).serdeMetaData(extraBlob);
|
||||
query.bindBlob("@extraData", extraBlob, /* static */ true);
|
||||
query.exec();
|
||||
}
|
||||
|
||||
void PreClassRepoProxy::GetPreClassesStmt
|
||||
::get(UnitEmitter& ue) {
|
||||
RepoTxn txn(m_repo);
|
||||
if (!prepared()) {
|
||||
std::stringstream ssSelect;
|
||||
ssSelect << "SELECT preClassId,name,hoistable,extraData FROM "
|
||||
<< m_repo.table(m_repoId, "PreClass")
|
||||
<< " WHERE unitSn == @unitSn ORDER BY preClassId ASC;";
|
||||
txn.prepare(*this, ssSelect.str());
|
||||
}
|
||||
RepoTxnQuery query(txn, *this);
|
||||
query.bindInt64("@unitSn", ue.sn());
|
||||
do {
|
||||
query.step();
|
||||
if (query.row()) {
|
||||
Id preClassId; /**/ query.getId(0, preClassId);
|
||||
StringData* name; /**/ query.getStaticString(1, name);
|
||||
int hoistable; /**/ query.getInt(2, hoistable);
|
||||
BlobDecoder extraBlob = /**/ query.getBlob(3);
|
||||
PreClassEmitter* pce = ue.newPreClassEmitter(
|
||||
name, (PreClass::Hoistable)hoistable);
|
||||
pce->serdeMetaData(extraBlob);
|
||||
assert(pce->id() == preClassId);
|
||||
}
|
||||
} while (!query.done());
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
} // HPHP
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_VM_CLASS_EMIT_H_
|
||||
#define incl_HPHP_VM_CLASS_EMIT_H_
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/repo_helpers.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
class PreClassEmitter {
|
||||
public:
|
||||
typedef std::vector<FuncEmitter*> MethodVec;
|
||||
|
||||
class Prop {
|
||||
public:
|
||||
Prop()
|
||||
: m_name(0)
|
||||
, m_mangledName(0)
|
||||
, m_attrs(AttrNone)
|
||||
, m_typeConstraint(0)
|
||||
, m_docComment(0)
|
||||
, m_hphpcType(KindOfInvalid)
|
||||
{}
|
||||
|
||||
Prop(const PreClassEmitter* pce,
|
||||
const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType);
|
||||
~Prop();
|
||||
|
||||
const StringData* name() const { return m_name; }
|
||||
const StringData* mangledName() const { return m_mangledName; }
|
||||
Attr attrs() const { return m_attrs; }
|
||||
const StringData* typeConstraint() const { return m_typeConstraint; }
|
||||
const StringData* docComment() const { return m_docComment; }
|
||||
const TypedValue& val() const { return m_val; }
|
||||
DataType hphpcType() const { return m_hphpcType; }
|
||||
|
||||
template<class SerDe> void serde(SerDe& sd) {
|
||||
sd(m_name)
|
||||
(m_mangledName)
|
||||
(m_attrs)
|
||||
(m_typeConstraint)
|
||||
(m_docComment)
|
||||
(m_val)
|
||||
(m_hphpcType)
|
||||
;
|
||||
}
|
||||
|
||||
private:
|
||||
const StringData* m_name;
|
||||
const StringData* m_mangledName;
|
||||
Attr m_attrs;
|
||||
const StringData* m_typeConstraint;
|
||||
const StringData* m_docComment;
|
||||
TypedValue m_val;
|
||||
DataType m_hphpcType;
|
||||
};
|
||||
|
||||
class Const {
|
||||
public:
|
||||
Const()
|
||||
: m_name(0)
|
||||
, m_typeConstraint(0)
|
||||
, m_phpCode(0)
|
||||
{}
|
||||
Const(const StringData* n, const StringData* typeConstraint,
|
||||
TypedValue* val, const StringData* phpCode)
|
||||
: m_name(n), m_typeConstraint(typeConstraint), m_phpCode(phpCode) {
|
||||
memcpy(&m_val, val, sizeof(TypedValue));
|
||||
}
|
||||
~Const() {}
|
||||
|
||||
const StringData* name() const { return m_name; }
|
||||
const StringData* typeConstraint() const { return m_typeConstraint; }
|
||||
const TypedValue& val() const { return m_val; }
|
||||
const StringData* phpCode() const { return m_phpCode; }
|
||||
|
||||
template<class SerDe> void serde(SerDe& sd) {
|
||||
sd(m_name)(m_val)(m_phpCode);
|
||||
}
|
||||
|
||||
private:
|
||||
const StringData* m_name;
|
||||
const StringData* m_typeConstraint;
|
||||
TypedValue m_val;
|
||||
const StringData* m_phpCode;
|
||||
};
|
||||
|
||||
PreClassEmitter(UnitEmitter& ue, Id id, const StringData* n,
|
||||
PreClass::Hoistable hoistable);
|
||||
~PreClassEmitter();
|
||||
|
||||
void init(int line1, int line2, Offset offset, Attr attrs,
|
||||
const StringData* parent, const StringData* docComment);
|
||||
|
||||
UnitEmitter& ue() const { return m_ue; }
|
||||
const StringData* name() const { return m_name; }
|
||||
Attr attrs() const { return m_attrs; }
|
||||
void setHoistable(PreClass::Hoistable h) { m_hoistable = h; }
|
||||
Id id() const { return m_id; }
|
||||
const MethodVec& methods() const { return m_methods; }
|
||||
|
||||
void addInterface(const StringData* n);
|
||||
bool addMethod(FuncEmitter* method);
|
||||
bool addProperty(const StringData* n,
|
||||
Attr attrs,
|
||||
const StringData* typeConstraint,
|
||||
const StringData* docComment,
|
||||
TypedValue* val,
|
||||
DataType hphpcType);
|
||||
const Prop& lookupProp(const StringData* propName) const;
|
||||
bool addConstant(const StringData* n, const StringData* typeConstraint,
|
||||
TypedValue* val, const StringData* phpCode);
|
||||
void addUsedTrait(const StringData* traitName);
|
||||
void addTraitPrecRule(const PreClass::TraitPrecRule &rule);
|
||||
void addTraitAliasRule(const PreClass::TraitAliasRule &rule);
|
||||
void addUserAttribute(const StringData* name, TypedValue tv);
|
||||
void commit(RepoTxn& txn) const;
|
||||
|
||||
void setBuiltinClassInfo(const ClassInfo* info,
|
||||
BuiltinCtorFunction ctorFunc,
|
||||
int sz);
|
||||
|
||||
PreClass* create(Unit& unit) const;
|
||||
|
||||
template<class SerDe> void serdeMetaData(SerDe&);
|
||||
|
||||
private:
|
||||
typedef IndexedStringMap<Prop,true,Slot> PropMap;
|
||||
typedef IndexedStringMap<Const,true,Slot> ConstMap;
|
||||
typedef hphp_hash_map<const StringData*, FuncEmitter*, string_data_hash,
|
||||
string_data_isame> MethodMap;
|
||||
|
||||
UnitEmitter& m_ue;
|
||||
int m_line1;
|
||||
int m_line2;
|
||||
Offset m_offset;
|
||||
const StringData* m_name;
|
||||
Attr m_attrs;
|
||||
const StringData* m_parent;
|
||||
const StringData* m_docComment;
|
||||
Id m_id;
|
||||
PreClass::Hoistable m_hoistable;
|
||||
BuiltinCtorFunction m_InstanceCtor;
|
||||
int m_builtinPropSize;
|
||||
|
||||
std::vector<const StringData*> m_interfaces;
|
||||
std::vector<const StringData*> m_usedTraits;
|
||||
std::vector<PreClass::TraitPrecRule> m_traitPrecRules;
|
||||
std::vector<PreClass::TraitAliasRule> m_traitAliasRules;
|
||||
PreClass::UserAttributeMap m_userAttributes;
|
||||
MethodVec m_methods;
|
||||
MethodMap m_methodMap;
|
||||
PropMap::Builder m_propMap;
|
||||
ConstMap::Builder m_constMap;
|
||||
};
|
||||
|
||||
class PreClassRepoProxy : public RepoProxy {
|
||||
friend class PreClass;
|
||||
friend class PreClassEmitter;
|
||||
public:
|
||||
explicit PreClassRepoProxy(Repo& repo);
|
||||
~PreClassRepoProxy();
|
||||
void createSchema(int repoId, RepoTxn& txn);
|
||||
|
||||
#define PCRP_IOP(o) PCRP_OP(Insert##o, insert##o)
|
||||
#define PCRP_GOP(o) PCRP_OP(Get##o, get##o)
|
||||
#define PCRP_OPS \
|
||||
PCRP_IOP(PreClass) \
|
||||
PCRP_GOP(PreClasses)
|
||||
class InsertPreClassStmt : public RepoProxy::Stmt {
|
||||
public:
|
||||
InsertPreClassStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
|
||||
void insert(const PreClassEmitter& pce, RepoTxn& txn, int64_t unitSn,
|
||||
Id preClassId, const StringData* name,
|
||||
PreClass::Hoistable hoistable);
|
||||
};
|
||||
class GetPreClassesStmt : public RepoProxy::Stmt {
|
||||
public:
|
||||
GetPreClassesStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
|
||||
void get(UnitEmitter& ue);
|
||||
};
|
||||
#define PCRP_OP(c, o) \
|
||||
public: \
|
||||
c##Stmt& o(int repoId) { return *m_##o[repoId]; } \
|
||||
private: \
|
||||
c##Stmt m_##o##Local; \
|
||||
c##Stmt m_##o##Central; \
|
||||
c##Stmt* m_##o[RepoIdCount];
|
||||
PCRP_OPS
|
||||
#undef PCRP_OP
|
||||
};
|
||||
|
||||
} // HPHP
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/preclass-emit.h"
|
||||
#include "hphp/runtime/vm/func.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "hphp/runtime/base/md5.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "hphp/runtime/ext/ext_closure.h"
|
||||
#include "hphp/runtime/ext/ext_continuation.h"
|
||||
#include "hphp/runtime/ext/ext_collections.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/vm/bytecode.h"
|
||||
#include "hphp/runtime/vm/repo.h"
|
||||
#include "hphp/util/trace.h"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include "hphp/runtime/vm/func.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/vm/treadmill.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
@@ -24,8 +26,7 @@
|
||||
#include "hphp/util/base.h"
|
||||
#include "hphp/util/rank.h"
|
||||
#include "hphp/runtime/base/macros.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/treadmill.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/jit/translator-x64.h"
|
||||
|
||||
namespace HPHP { namespace Treadmill {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// Expects that runtime/vm/core_types.h is already included.
|
||||
#include "hphp/runtime/base/runtime_option.h"
|
||||
#include "hphp/runtime/vm/hhbc.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/repo_helpers.h"
|
||||
#include "hphp/runtime/vm/named_entity.h"
|
||||
#include "hphp/runtime/base/array/hphp_array.h"
|
||||
@@ -39,6 +39,7 @@ class FuncEmitter;
|
||||
class Repo;
|
||||
class FuncDict;
|
||||
class Unit;
|
||||
class PreClassEmitter;
|
||||
|
||||
enum class UnitOrigin {
|
||||
File = 0,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "folly/ScopeGuard.h"
|
||||
|
||||
#include "hphp/util/trace.h"
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/bytecode.h"
|
||||
#include "hphp/runtime/vm/func.h"
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "hphp/runtime/vm/core_types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
#include "hphp/runtime/vm/instance.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário