Merge ObjectData and Instance together, part 2
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. This diff moves all of the functionality from the Instance class to the ObjectData and removes the Instance class. In the process, I got rid of a bunch of dead methods and fixed some indentation and other style issues.
Esse commit está contido em:
@@ -3925,7 +3925,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(),
|
||||
AttrUnique | AttrPersistent, parentName, nullptr);
|
||||
|
||||
// Instance variables.
|
||||
// Instance properties.
|
||||
TypedValue uninit;
|
||||
tvWriteUninit(&uninit);
|
||||
for (auto& useVar : useVars) {
|
||||
|
||||
@@ -136,7 +136,7 @@ void ArrayData::release() {
|
||||
// reads
|
||||
|
||||
Object ArrayData::toObject() const {
|
||||
return Instance::FromArray(const_cast<ArrayData *>(this));
|
||||
return ObjectData::FromArray(const_cast<ArrayData*>(this));
|
||||
}
|
||||
|
||||
int ArrayData::compare(const ArrayData *v2) const {
|
||||
|
||||
@@ -339,7 +339,7 @@ Variant vm_call_user_func(CVarRef function, CArrRef params,
|
||||
HPHP::Transl::CallerFrame cf;
|
||||
StringData* invName = nullptr;
|
||||
const HPHP::Func* f = vm_decode_function(function, cf(), forwarding,
|
||||
obj, cls, invName);
|
||||
obj, cls, invName);
|
||||
if (f == nullptr) {
|
||||
return uninit_null();
|
||||
}
|
||||
@@ -681,16 +681,6 @@ void throw_call_non_object(const char *methodName) {
|
||||
throw FatalErrorException(msg.c_str());
|
||||
}
|
||||
|
||||
Object f_clone(CVarRef v) {
|
||||
if (v.isObject()) {
|
||||
Object clone = Object(v.toObject()->clone());
|
||||
clone->t___clone();
|
||||
return clone;
|
||||
}
|
||||
raise_error("Cannot clone non-object");
|
||||
return Object();
|
||||
}
|
||||
|
||||
String f_serialize(CVarRef value) {
|
||||
switch (value.getType()) {
|
||||
case KindOfUninit:
|
||||
|
||||
@@ -360,11 +360,6 @@ void throw_call_non_object() ATTRIBUTE_COLD ATTRIBUTE_NORETURN;
|
||||
void throw_call_non_object(const char *methodName)
|
||||
ATTRIBUTE_COLD ATTRIBUTE_NORETURN;
|
||||
|
||||
/**
|
||||
* Cloning an object.
|
||||
*/
|
||||
Object f_clone(CVarRef v);
|
||||
|
||||
// unserializable default value arguments such as TimeStamp::Current()
|
||||
// are serialized as "\x01"
|
||||
char const kUnserializableString[] = "\x01";
|
||||
|
||||
@@ -417,7 +417,7 @@ public:
|
||||
VMExecutionContext();
|
||||
~VMExecutionContext();
|
||||
|
||||
typedef std::set<HPHP::ObjectData*> LiveObjSet;
|
||||
typedef std::set<ObjectData*> LiveObjSet;
|
||||
LiveObjSet m_liveBCObjs;
|
||||
|
||||
// pcre ini_settings
|
||||
@@ -535,10 +535,10 @@ public:
|
||||
MethodLookup::LookupResult lookupCtorMethod(const HPHP::Func*& f,
|
||||
const HPHP::Class* cls,
|
||||
bool raise = false);
|
||||
HPHP::ObjectData* createObject(StringData* clsName,
|
||||
CArrRef params,
|
||||
bool init = true);
|
||||
HPHP::ObjectData* createObjectOnly(StringData* clsName);
|
||||
ObjectData* createObject(StringData* clsName,
|
||||
CArrRef params,
|
||||
bool init = true);
|
||||
ObjectData* createObjectOnly(StringData* clsName);
|
||||
|
||||
HphpArray* getFuncStaticCtx(const HPHP::Func* f) {
|
||||
FuncStaticCtxMap::iterator it = m_funcStaticCtx.find(f);
|
||||
|
||||
@@ -49,7 +49,7 @@ UserFile::UserFile(Class *cls, int options /*= 0 */,
|
||||
cls->name()->data());
|
||||
}
|
||||
|
||||
m_obj = Instance::newInstance(cls);
|
||||
m_obj = ObjectData::newInstance(cls);
|
||||
m_obj.o_set("context", context);
|
||||
Variant ret;
|
||||
g_vmContext->invokeFuncFew(ret.asTypedValue(), ctor, m_obj.get());
|
||||
|
||||
@@ -253,12 +253,12 @@ void *SmartAllocatorInitSetup() {
|
||||
public: \
|
||||
/* static void *ObjAllocatorInitSetup; */ \
|
||||
inline ALWAYS_INLINE void operator delete(void *p) { \
|
||||
if (T::IsResourceClass) { \
|
||||
if (T::IsResourceClass) { \
|
||||
RELEASEOBJ(NS, T, p); \
|
||||
return; \
|
||||
} \
|
||||
HPHP::Instance* this_ = (HPHP::Instance*)p; \
|
||||
HPHP::Class* cls = this_->getVMClass(); \
|
||||
ObjectData* this_ = (ObjectData*)p; \
|
||||
Class* cls = this_->getVMClass(); \
|
||||
size_t nProps = cls->numDeclProperties(); \
|
||||
size_t builtinPropSize = cls->builtinPropSize(); \
|
||||
TypedValue* propVec = \
|
||||
@@ -268,7 +268,7 @@ void *SmartAllocatorInitSetup() {
|
||||
TypedValue* prop = &propVec[i]; \
|
||||
tvRefcountedDecRef(prop); \
|
||||
} \
|
||||
DELETEOBJSZ(HPHP::Instance::sizeForNProps(nProps) + \
|
||||
DELETEOBJSZ(ObjectData::sizeForNProps(nProps) + \
|
||||
builtinPropSize)(this_); \
|
||||
}
|
||||
|
||||
|
||||
+142
-315
@@ -54,7 +54,7 @@ static StaticString s_serialize("serialize");
|
||||
|
||||
ObjectData::~ObjectData() {
|
||||
if (ArrayData* a = o_properties.get()) decRefArr(a);
|
||||
int &pmax = *os_max_id;
|
||||
int& pmax = *os_max_id;
|
||||
if (o_id && o_id == pmax) {
|
||||
--pmax;
|
||||
}
|
||||
@@ -123,10 +123,6 @@ 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();
|
||||
}
|
||||
@@ -177,7 +173,7 @@ ArrayIter ObjectData::begin(CStrRef context /* = null_string */) {
|
||||
}
|
||||
}
|
||||
|
||||
MutableArrayIter ObjectData::begin(Variant *key, Variant &val,
|
||||
MutableArrayIter ObjectData::begin(Variant* key, Variant& val,
|
||||
CStrRef context /* = null_string */) {
|
||||
bool isIterable;
|
||||
if (isCollection()) {
|
||||
@@ -189,12 +185,12 @@ MutableArrayIter ObjectData::begin(Variant *key, Variant &val,
|
||||
"foreach by reference");
|
||||
}
|
||||
Array properties = iterable->o_toIterArray(context, true);
|
||||
ArrayData *arr = properties.detach();
|
||||
ArrayData* arr = properties.detach();
|
||||
return MutableArrayIter(arr, key, val);
|
||||
}
|
||||
|
||||
void ObjectData::initProperties(int nProp) {
|
||||
if (!o_properties.get()) ((Instance*)this)->initDynProps(nProp);
|
||||
if (!o_properties.get()) initDynProps(nProp);
|
||||
}
|
||||
|
||||
Variant* ObjectData::o_realProp(CStrRef propName, int flags,
|
||||
@@ -210,7 +206,7 @@ Variant* ObjectData::o_realProp(CStrRef propName, int flags,
|
||||
ctx = Unit::lookupClass(context.get());
|
||||
}
|
||||
|
||||
Instance* thiz = (Instance*)this; // sigh
|
||||
auto thiz = const_cast<ObjectData*>(this);
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* ret = (flags & RealPropNoDynamic)
|
||||
? thiz->getDeclProp(ctx, propName.get(), visible,
|
||||
@@ -247,14 +243,16 @@ inline Variant ObjectData::o_getImpl(CStrRef propName, int flags,
|
||||
throw_invalid_property_name(propName);
|
||||
}
|
||||
|
||||
if (Variant *t = o_realProp(propName, flags, context)) {
|
||||
if (Variant* t = o_realProp(propName, flags, context)) {
|
||||
if (t->isInitialized())
|
||||
return *t;
|
||||
}
|
||||
|
||||
if (getAttribute(UseGet)) {
|
||||
AttributeClearer a(UseGet, this);
|
||||
return t___get(propName);
|
||||
TypedValue tvResult;
|
||||
tvWriteNull(&tvResult);
|
||||
invokeGet(&tvResult, propName.get());
|
||||
return tvAsCVarRef(&tvResult);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
@@ -282,7 +280,7 @@ inline ALWAYS_INLINE Variant ObjectData::o_setImpl(CStrRef propName, T v,
|
||||
auto flags = useSet ? 0 : RealPropCreate;
|
||||
if (forInit) flags |= RealPropUnchecked;
|
||||
|
||||
if (Variant *t = o_realProp(propName, flags, context)) {
|
||||
if (Variant* t = o_realProp(propName, flags, context)) {
|
||||
if (!useSet || t->isInitialized()) {
|
||||
*t = v;
|
||||
return variant(v);
|
||||
@@ -290,8 +288,9 @@ inline ALWAYS_INLINE Variant ObjectData::o_setImpl(CStrRef propName, T v,
|
||||
}
|
||||
|
||||
if (useSet) {
|
||||
AttributeClearer a(UseSet, this);
|
||||
t___set(propName, variant(v));
|
||||
TypedValue ignored;
|
||||
invokeSet(&ignored, propName.get(), (TypedValue*)(&variant(v)));
|
||||
tvRefcountedDecRef(&ignored);
|
||||
return variant(v);
|
||||
}
|
||||
|
||||
@@ -324,7 +323,6 @@ Variant ObjectData::o_setRef(CStrRef propName, CVarRef v, CStrRef context) {
|
||||
|
||||
HOT_FUNC
|
||||
void ObjectData::o_setArray(CArrRef properties) {
|
||||
auto thiz = static_cast<Instance*>(this);
|
||||
for (ArrayIter iter(properties); iter; ++iter) {
|
||||
String k = iter.first().toString();
|
||||
Class* ctx = nullptr;
|
||||
@@ -345,12 +343,12 @@ void ObjectData::o_setArray(CArrRef properties) {
|
||||
}
|
||||
|
||||
CVarRef secondRef = iter.secondRef();
|
||||
thiz->setProp(ctx, k.get(), (TypedValue*)(&secondRef),
|
||||
secondRef.isReferenced());
|
||||
setProp(ctx, k.get(), (TypedValue*)(&secondRef),
|
||||
secondRef.isReferenced());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectData::o_getArray(Array &props, bool pubOnly /* = false */) const {
|
||||
void ObjectData::o_getArray(Array& props, bool pubOnly /* = false */) const {
|
||||
// The declared properties in the resultant array should be a permutation of
|
||||
// propVec. They appear in the following order: go most-to-least-derived in
|
||||
// the inheritance hierarchy, inserting properties in declaration order (with
|
||||
@@ -363,13 +361,12 @@ void ObjectData::o_getArray(Array &props, bool pubOnly /* = false */) const {
|
||||
|
||||
// Iterate over declared properties and insert {mangled name --> prop} pairs.
|
||||
const Class* cls = m_cls;
|
||||
auto thiz = static_cast<const Instance*>(this);
|
||||
do {
|
||||
thiz->getProps(cls, pubOnly, cls->m_preClass.get(), props, inserted);
|
||||
getProps(cls, pubOnly, cls->m_preClass.get(), props, inserted);
|
||||
auto& usedTraits = cls->m_usedTraits;
|
||||
for (unsigned t = 0; t < usedTraits.size(); t++) {
|
||||
const ClassPtr& trait = usedTraits[t];
|
||||
thiz->getProps(cls, pubOnly, trait->m_preClass.get(), props, inserted);
|
||||
getProps(cls, pubOnly, trait->m_preClass.get(), props, inserted);
|
||||
}
|
||||
cls = cls->m_parent.get();
|
||||
} while (cls);
|
||||
@@ -384,14 +381,6 @@ void ObjectData::o_getArray(Array &props, bool pubOnly /* = false */) const {
|
||||
}
|
||||
}
|
||||
|
||||
Object ObjectData::FromArray(ArrayData *properties) {
|
||||
ObjectData *ret = SystemLib::AllocStdClassObject();
|
||||
if (!properties->empty()) {
|
||||
ret->o_properties.asArray() = properties;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Array ObjectData::o_toArray() const {
|
||||
Array ret(ArrayData::Create());
|
||||
o_getArray(ret, false);
|
||||
@@ -418,8 +407,7 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
for (size_t i = 0; i < numProps; ++i) {
|
||||
auto key = const_cast<StringData*>(props[i].name());
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* val = ((Instance*)this)->getProp(
|
||||
ctx, key, visible, accessible, unset);
|
||||
TypedValue* val = getProp(ctx, key, visible, accessible, unset);
|
||||
if (accessible && val->m_type != KindOfUninit && !unset) {
|
||||
if (getRef) {
|
||||
if (val->m_type != KindOfRef) {
|
||||
@@ -479,15 +467,10 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
|
||||
static bool decode_invoke(CStrRef s, ObjectData* obj, bool fatal,
|
||||
CallCtx& ctx) {
|
||||
// TODO This duplicates some logic from vm_decode_function and
|
||||
// vm_call_user_func, we should refactor this in the near future
|
||||
ctx.this_ = obj;
|
||||
ctx.cls = obj->getVMClass();
|
||||
ctx.invName = nullptr;
|
||||
|
||||
// XXX The lookup below doesn't take context into account, so it will lead
|
||||
// to incorrect behavior in some corner cases. o_invoke is gradually being
|
||||
// removed from the HPHP runtime this should be ok for the short term.
|
||||
ctx.func = ctx.cls->lookupMethod(s.get());
|
||||
if (ctx.func) {
|
||||
if (ctx.func->attrs() & AttrStatic) {
|
||||
@@ -556,7 +539,7 @@ Variant ObjectData::o_invoke_few_args(CStrRef s, int count,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObjectData::php_sleep(Variant &ret) {
|
||||
bool ObjectData::php_sleep(Variant& ret) {
|
||||
setAttribute(HasSleep);
|
||||
ret = t___sleep();
|
||||
return getAttribute(HasSleep);
|
||||
@@ -564,7 +547,7 @@ bool ObjectData::php_sleep(Variant &ret) {
|
||||
|
||||
StaticString s_zero("\0", 1);
|
||||
|
||||
void ObjectData::serialize(VariableSerializer *serializer) const {
|
||||
void ObjectData::serialize(VariableSerializer* serializer) const {
|
||||
if (UNLIKELY(serializer->incNestedLevel((void*)this, true))) {
|
||||
serializer->writeOverflow((void*)this, true);
|
||||
} else {
|
||||
@@ -576,7 +559,7 @@ void ObjectData::serialize(VariableSerializer *serializer) const {
|
||||
static StaticString s_PHP_Incomplete_Class("__PHP_Incomplete_Class");
|
||||
static StaticString s_PHP_Incomplete_Class_Name("__PHP_Incomplete_Class_Name");
|
||||
|
||||
void ObjectData::serializeImpl(VariableSerializer *serializer) const {
|
||||
void ObjectData::serializeImpl(VariableSerializer* serializer) const {
|
||||
bool handleSleep = false;
|
||||
Variant ret;
|
||||
if (LIKELY(serializer->getType() == VariableSerializer::Type::Serialize ||
|
||||
@@ -631,7 +614,7 @@ void ObjectData::serializeImpl(VariableSerializer *serializer) const {
|
||||
if (UNLIKELY(handleSleep)) {
|
||||
assert(!isCollection());
|
||||
if (ret.isArray()) {
|
||||
auto thiz = (Instance*)this;
|
||||
auto thiz = const_cast<ObjectData*>(this);
|
||||
Array wanted = Array::Create();
|
||||
Array props = ret.toArray();
|
||||
for (ArrayIter iter(props); iter; ++iter) {
|
||||
@@ -706,7 +689,7 @@ void ObjectData::serializeImpl(VariableSerializer *serializer) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectData::hasInternalReference(PointerSet &vars,
|
||||
bool ObjectData::hasInternalReference(PointerSet& vars,
|
||||
bool ds /* = false */) const {
|
||||
if (isCollection()) {
|
||||
return true;
|
||||
@@ -718,33 +701,8 @@ void ObjectData::dump() const {
|
||||
o_toArray().dump();
|
||||
}
|
||||
|
||||
ObjectData *ObjectData::clone() {
|
||||
Instance* instance = static_cast<Instance*>(this);
|
||||
return instance->cloneImpl();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// magic methods that user classes can override, and these are default handlers
|
||||
// or actions to take:
|
||||
|
||||
Variant ObjectData::t___destruct() {
|
||||
// do nothing
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::t___call(Variant v_name, Variant v_arguments) {
|
||||
// do nothing
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::t___set(Variant v_name, Variant v_value) {
|
||||
// not called
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::t___get(Variant v_name) {
|
||||
// not called
|
||||
return uninit_null();
|
||||
ObjectData* ObjectData::clone() {
|
||||
return cloneImpl();
|
||||
}
|
||||
|
||||
Variant ObjectData::offsetGet(Variant key) {
|
||||
@@ -762,36 +720,6 @@ Variant ObjectData::offsetGet(Variant key) {
|
||||
return v;
|
||||
}
|
||||
|
||||
bool ObjectData::t___isset(Variant v_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Variant ObjectData::t___unset(Variant v_name) {
|
||||
// not called
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::t___sleep() {
|
||||
clearAttribute(HasSleep);
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::t___wakeup() {
|
||||
// do nothing
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
String ObjectData::t___tostring() {
|
||||
string msg = o_getClassName().data();
|
||||
msg += "::__toString() was not defined";
|
||||
throw BadTypeConversionException(msg.c_str());
|
||||
}
|
||||
|
||||
Variant ObjectData::t___clone() {
|
||||
// do nothing
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
@@ -850,8 +778,7 @@ static StaticString s___unset(LITSTR_INIT("__unset"));
|
||||
|
||||
TRACE_SET_MOD(runtime);
|
||||
|
||||
int HPHP::Instance::ObjAllocatorSizeClassCount =
|
||||
HPHP::InitializeAllocators();
|
||||
int ObjectData::ObjAllocatorSizeClassCount = InitializeAllocators();
|
||||
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps) {
|
||||
@@ -867,26 +794,18 @@ void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
TypedValue* ObjectData::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();
|
||||
const TypedValue* ObjectData::propVec() const {
|
||||
return const_cast<ObjectData*>(this)->propVec();
|
||||
}
|
||||
|
||||
Instance* Instance::callCustomInstanceInit() {
|
||||
ObjectData* ObjectData::callCustomInstanceInit() {
|
||||
static StringData* sd_init = StringData::GetStaticString("__init__");
|
||||
const Func* init = m_cls->lookupMethod(sd_init);
|
||||
if (init != nullptr) {
|
||||
@@ -908,13 +827,20 @@ Instance* Instance::callCustomInstanceInit() {
|
||||
return this;
|
||||
}
|
||||
|
||||
void Instance::operator delete(void* p) {
|
||||
Instance* this_ = (Instance*)p;
|
||||
HOT_FUNC_VM
|
||||
ObjectData* ObjectData::newInstanceRaw(Class* cls, int idx) {
|
||||
ObjectData* obj = (ObjectData*)ALLOCOBJIDX(idx);
|
||||
new (obj) ObjectData(cls, NoInit::noinit);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ObjectData::operator delete(void* p) {
|
||||
ObjectData* this_ = (ObjectData*)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));
|
||||
TypedValue* propVec = (TypedValue*)((uintptr_t)this_ + sizeof(ObjectData));
|
||||
for (unsigned i = 0; i < nProps; ++i) {
|
||||
TypedValue* prop = &propVec[i];
|
||||
tvRefcountedDecRef(prop);
|
||||
@@ -922,20 +848,13 @@ void Instance::operator delete(void* p) {
|
||||
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) {
|
||||
void ObjectData::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);
|
||||
Object ObjectData::FromArray(ArrayData* properties) {
|
||||
ObjectData* retval = ObjectData::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;
|
||||
@@ -955,12 +874,12 @@ Object Instance::FromArray(ArrayData *properties) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Instance::initDynProps(int numDynamic /* = 0 */) {
|
||||
void ObjectData::initDynProps(int numDynamic /* = 0 */) {
|
||||
// Create o_properties with room for numDynamic
|
||||
o_properties.asArray() = ArrayData::Make(numDynamic);
|
||||
}
|
||||
|
||||
Slot Instance::declPropInd(TypedValue* prop) const {
|
||||
Slot ObjectData::declPropInd(TypedValue* prop) const {
|
||||
// Do an address range check to determine whether prop physically resides
|
||||
// in propVec.
|
||||
const TypedValue* pv = propVec();
|
||||
@@ -972,9 +891,9 @@ Slot Instance::declPropInd(TypedValue* prop) const {
|
||||
}
|
||||
|
||||
template <bool declOnly>
|
||||
TypedValue* Instance::getPropImpl(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible,
|
||||
bool& unset) {
|
||||
TypedValue* ObjectData::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);
|
||||
@@ -1005,19 +924,19 @@ TypedValue* Instance::getPropImpl(Class* ctx, const StringData* key,
|
||||
return prop;
|
||||
}
|
||||
|
||||
TypedValue* Instance::getProp(Class* ctx, const StringData* key,
|
||||
bool& visible, bool& accessible, bool& unset) {
|
||||
TypedValue* ObjectData::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) {
|
||||
TypedValue* ObjectData::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) {
|
||||
void ObjectData::invokeSet(TypedValue* retval, const StringData* key,
|
||||
TypedValue* val) {
|
||||
AttributeClearer a(UseSet, this);
|
||||
const Func* meth = m_cls->lookupMethod(s___set.get());
|
||||
assert(meth);
|
||||
@@ -1031,28 +950,28 @@ void Instance::invokeSet(TypedValue* retval, const StringData* key,
|
||||
assert(meth); \
|
||||
invokeUserMethod(retval, meth, CREATE_VECTOR1(CStrRef(key))); \
|
||||
|
||||
void Instance::invokeGet(TypedValue* retval, const StringData* key) {
|
||||
void ObjectData::invokeGet(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___get.get(), UseGet);
|
||||
}
|
||||
|
||||
void Instance::invokeIsset(TypedValue* retval, const StringData* key) {
|
||||
void ObjectData::invokeIsset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___isset.get(), UseIsset);
|
||||
}
|
||||
|
||||
void Instance::invokeUnset(TypedValue* retval, const StringData* key) {
|
||||
void ObjectData::invokeUnset(TypedValue* retval, const StringData* key) {
|
||||
MAGIC_PROP_BODY(s___unset.get(), UseUnset);
|
||||
}
|
||||
|
||||
void Instance::invokeGetProp(TypedValue*& retval, TypedValue& tvRef,
|
||||
const StringData* key) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::propImpl(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx,
|
||||
const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
|
||||
@@ -1111,27 +1030,27 @@ void Instance::propImpl(TypedValue*& retval, TypedValue& tvRef,
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::prop(TypedValue*& retval, TypedValue& tvRef,
|
||||
Class* ctx, const StringData* key) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::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 ObjectData::propIsset(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
@@ -1147,7 +1066,7 @@ bool Instance::propIsset(Class* ctx, const StringData* key) {
|
||||
return tv.m_data.num;
|
||||
}
|
||||
|
||||
bool Instance::propEmpty(Class* ctx, const StringData* key) {
|
||||
bool ObjectData::propEmpty(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible && !unset) {
|
||||
@@ -1172,9 +1091,9 @@ bool Instance::propEmpty(Class* ctx, const StringData* key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setProp(Class* ctx, const StringData* key,
|
||||
TypedValue* val,
|
||||
bool bindingAssignment /* = false */) {
|
||||
TypedValue* ObjectData::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) {
|
||||
@@ -1228,9 +1147,9 @@ TypedValue* Instance::setProp(Class* ctx, const StringData* key,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedValue* Instance::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
Cell* val) {
|
||||
TypedValue* ObjectData::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) {
|
||||
@@ -1303,9 +1222,9 @@ TypedValue* Instance::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
|
||||
template <bool setResult>
|
||||
void Instance::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
void ObjectData::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) {
|
||||
@@ -1321,7 +1240,7 @@ void Instance::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
tvRefcountedDecRef(&ignored);
|
||||
propVal = &tvResult;
|
||||
} else {
|
||||
memcpy((void *)propVal, (void *)&tvResult, sizeof(TypedValue));
|
||||
memcpy((void*)propVal, (void*)&tvResult, sizeof(TypedValue));
|
||||
}
|
||||
} else {
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
@@ -1375,20 +1294,20 @@ void Instance::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
|
||||
template <>
|
||||
void Instance::incDecProp<false>(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, const StringData* key,
|
||||
TypedValue& dest) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::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) {
|
||||
void ObjectData::unsetProp(Class* ctx, const StringData* key) {
|
||||
bool visible, accessible, unset;
|
||||
TypedValue* propVal = getProp(ctx, key, visible, accessible, unset);
|
||||
if (visible && accessible) {
|
||||
@@ -1415,15 +1334,27 @@ void Instance::unsetProp(Class* ctx, const StringData* key) {
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::raiseUndefProp(const StringData* key) {
|
||||
void ObjectData::raiseObjToIntNotice(const char* clsName) {
|
||||
raise_notice("Object of class %s could not be converted to int", clsName);
|
||||
}
|
||||
|
||||
void ObjectData::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());
|
||||
}
|
||||
|
||||
void ObjectData::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 {
|
||||
void ObjectData::getProp(const Class* klass, bool pubOnly,
|
||||
const PreClass::Prop* prop,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
if (prop->attrs() & AttrStatic) {
|
||||
return;
|
||||
}
|
||||
@@ -1441,10 +1372,10 @@ void Instance::getProp(const Class* klass, bool pubOnly,
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::getProps(const Class* klass, bool pubOnly,
|
||||
const PreClass* pc,
|
||||
Array& props,
|
||||
std::vector<bool>& inserted) const {
|
||||
void ObjectData::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) {
|
||||
@@ -1452,92 +1383,9 @@ void Instance::getProps(const Class* klass, bool pubOnly,
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
Variant ObjectData::t___sleep() {
|
||||
static StringData* sd__sleep = StringData::GetStaticString("__sleep");
|
||||
const Func *method = m_cls->lookupMethod(sd__sleep);
|
||||
const Func* method = m_cls->lookupMethod(sd__sleep);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
@@ -1548,9 +1396,9 @@ Variant Instance::t___sleep() {
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___wakeup() {
|
||||
Variant ObjectData::t___wakeup() {
|
||||
static StringData* sd__wakeup = StringData::GetStaticString("__wakeup");
|
||||
const Func *method = m_cls->lookupMethod(sd__wakeup);
|
||||
const Func* method = m_cls->lookupMethod(sd__wakeup);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
g_vmContext->invokeFuncFew(&tv, method, this);
|
||||
@@ -1560,28 +1408,13 @@ Variant Instance::t___wakeup() {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
String ObjectData::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;
|
||||
void (*notify_user)(const char*, ...) = &raise_error;
|
||||
if (hphpiCompat) {
|
||||
tvCastToStringInPlace(&tv);
|
||||
notify_user = &raise_warning;
|
||||
@@ -1597,29 +1430,16 @@ String Instance::t___tostring() {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void ObjectData::cloneSet(ObjectData* clone) {
|
||||
Slot nProps = m_cls->numDeclProperties();
|
||||
TypedValue* iclonePropVec = (TypedValue *)((uintptr_t)iclone +
|
||||
TypedValue* clonePropVec = (TypedValue*)((uintptr_t)clone +
|
||||
sizeof(ObjectData) + builtinPropSize());
|
||||
for (Slot i = 0; i < nProps; i++) {
|
||||
tvRefcountedDecRef(&iclonePropVec[i]);
|
||||
tvDupFlattenVars(&propVec()[i], &iclonePropVec[i], nullptr);
|
||||
tvRefcountedDecRef(&clonePropVec[i]);
|
||||
tvDupFlattenVars(&propVec()[i], &clonePropVec[i], nullptr);
|
||||
}
|
||||
if (o_properties.get()) {
|
||||
iclone->initDynProps();
|
||||
clone->initDynProps();
|
||||
ssize_t iter = o_properties.get()->iter_begin();
|
||||
while (iter != HphpArray::ElmIndEmpty) {
|
||||
auto props = static_cast<HphpArray*>(o_properties.get());
|
||||
@@ -1627,9 +1447,9 @@ void Instance::cloneSet(ObjectData* clone) {
|
||||
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();
|
||||
TypedValue* val = props->nvGet(strKey);
|
||||
TypedValue* retval;
|
||||
auto cloneProps = clone->o_properties.get();
|
||||
cloneProps->createLvalPtr(strKey, *(Variant**)&retval, false);
|
||||
tvDupFlattenVars(val, retval, cloneProps);
|
||||
iter = o_properties.get()->iter_advance(iter);
|
||||
@@ -1638,14 +1458,21 @@ void Instance::cloneSet(ObjectData* clone) {
|
||||
}
|
||||
}
|
||||
|
||||
ObjectData* Instance::cloneImpl() {
|
||||
Instance* obj = Instance::newInstance(m_cls);
|
||||
ObjectData* ObjectData::cloneImpl() {
|
||||
ObjectData* obj;
|
||||
Object o = obj = ObjectData::newInstance(m_cls);
|
||||
cloneSet(obj);
|
||||
obj->incRefCount();
|
||||
obj->t___clone();
|
||||
return obj;
|
||||
static StringData* sd__clone = StringData::GetStaticString("__clone");
|
||||
const Func* method = obj->m_cls->lookupMethod(sd__clone);
|
||||
if (method) {
|
||||
TypedValue tv;
|
||||
tvWriteNull(&tv);
|
||||
g_vmContext->invokeFuncFew(&tv, method, obj);
|
||||
tvRefcountedDecRef(&tv);
|
||||
}
|
||||
return o.detach();
|
||||
}
|
||||
|
||||
} // HPHP::VM
|
||||
} // HPHP
|
||||
|
||||
|
||||
|
||||
+363
-401
@@ -37,16 +37,11 @@ class TypedValue;
|
||||
class PreClass;
|
||||
class Class;
|
||||
|
||||
extern StaticString ssIterator;
|
||||
void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
size_t nProps);
|
||||
|
||||
/**
|
||||
* Base class of all PHP objects and PHP resources.
|
||||
*
|
||||
* 1. Properties:
|
||||
* o_get() -> t___get() as fallback
|
||||
* o_set() -> t___set() as fallback
|
||||
* 2. Methods:
|
||||
* o_invoke() -> t___call() as fallback
|
||||
*/
|
||||
class ObjectData : public CountableNF {
|
||||
public:
|
||||
@@ -77,375 +72,49 @@ class ObjectData : public CountableNF {
|
||||
RealPropExist = 16, // For property_exists
|
||||
};
|
||||
|
||||
ObjectData(bool noId, Class* type)
|
||||
: o_attribute(0), m_cls(type) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
if (!noId) {
|
||||
o_id = ++(*os_max_id);
|
||||
}
|
||||
}
|
||||
|
||||
void setId(const ObjectData *r) { if (r) o_id = r->o_id; }
|
||||
|
||||
virtual ~ObjectData(); // all PHP classes need virtual tables
|
||||
|
||||
Class* getVMClass() const {
|
||||
return m_cls;
|
||||
}
|
||||
static size_t getVMClassOffset() {
|
||||
// For assembly linkage.
|
||||
return offsetof(ObjectData, m_cls);
|
||||
}
|
||||
static size_t attributeOff() { return offsetof(ObjectData, o_attribute); }
|
||||
bool instanceof(const Class* c) const;
|
||||
|
||||
bool isCollection() const {
|
||||
return getCollectionType() != Collection::InvalidType;
|
||||
}
|
||||
Collection::Type getCollectionType() const {
|
||||
// Return the upper 3 bits of o_attribute
|
||||
return (Collection::Type)((uint16_t)(o_attribute >> 13) & 7);
|
||||
}
|
||||
|
||||
bool implementsIterator() {
|
||||
return (instanceof(SystemLib::s_IteratorClass));
|
||||
}
|
||||
|
||||
void setAttributes(int attrs) { o_attribute |= attrs; }
|
||||
void setAttributes(const ObjectData *o) { o_attribute |= o->o_attribute; }
|
||||
bool getAttribute(Attribute attr) const { return o_attribute & attr; }
|
||||
void setAttribute(Attribute attr) const { o_attribute |= attr;}
|
||||
void clearAttribute(Attribute attr) const { o_attribute &= ~attr;}
|
||||
bool noDestruct() const { return getAttribute(NoDestructor); }
|
||||
void setNoDestruct() { setAttribute(NoDestructor); }
|
||||
ObjectData *clearNoDestruct() { clearAttribute(NoDestructor); return this; }
|
||||
|
||||
Object iterableObject(bool& isIterable, bool mayImplementIterator = true);
|
||||
ArrayIter begin(CStrRef context = null_string);
|
||||
MutableArrayIter begin(Variant *key, Variant &val,
|
||||
CStrRef context = null_string);
|
||||
|
||||
/**
|
||||
* o_instanceof() can be used for both classes and interfaces.
|
||||
* It is also worth noting that o_instanceof will always return
|
||||
* false for classes that are descendents of ResourceData.
|
||||
*/
|
||||
bool o_instanceof(CStrRef s) const;
|
||||
|
||||
// class info
|
||||
CStrRef o_getClassName() const;
|
||||
CStrRef o_getParentName() const;
|
||||
virtual CStrRef o_getClassNameHook() const;
|
||||
virtual bool isResource() const { return false; }
|
||||
int o_getId() const { return o_id;}
|
||||
|
||||
bool o_toBoolean() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toBooleanImpl();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void raiseObjToIntNotice(const char*);
|
||||
|
||||
int64_t o_toInt64() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toInt64Impl();
|
||||
}
|
||||
raiseObjToIntNotice(o_getClassName().data());
|
||||
return 1;
|
||||
}
|
||||
|
||||
double o_toDouble() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toDoubleImpl();
|
||||
}
|
||||
return o_toInt64();
|
||||
}
|
||||
|
||||
// overridable casting
|
||||
virtual bool o_toBooleanImpl() const noexcept;
|
||||
virtual int64_t o_toInt64Impl() const noexcept;
|
||||
virtual double o_toDoubleImpl() const noexcept;
|
||||
|
||||
void destruct();
|
||||
|
||||
// properties
|
||||
virtual Array o_toArray() const;
|
||||
Array o_toIterArray(CStrRef context, bool getRef = false);
|
||||
|
||||
Array o_getDynamicProperties() const {
|
||||
return o_properties;
|
||||
}
|
||||
|
||||
Variant* o_realProp(CStrRef s, int flags,
|
||||
CStrRef context = null_string) const;
|
||||
|
||||
Variant o_get(CStrRef s, bool error = true,
|
||||
CStrRef context = null_string);
|
||||
|
||||
Variant o_set(CStrRef s, CVarRef v);
|
||||
Variant o_set(CStrRef s, RefResult v);
|
||||
Variant o_setRef(CStrRef s, CVarRef v);
|
||||
|
||||
Variant o_set(CStrRef s, CVarRef v, CStrRef context);
|
||||
Variant o_set(CStrRef s, RefResult v, CStrRef context);
|
||||
Variant o_setRef(CStrRef s, CVarRef v, CStrRef context);
|
||||
|
||||
void o_setArray(CArrRef properties);
|
||||
void o_getArray(Array &props, bool pubOnly = false) const;
|
||||
|
||||
static Object FromArray(ArrayData *properties);
|
||||
|
||||
// method invocation with CStrRef
|
||||
Variant o_invoke(CStrRef s, CArrRef params, bool fatal = true);
|
||||
Variant o_invoke_few_args(CStrRef s, int count,
|
||||
INVOKE_FEW_ARGS_DECL_ARGS);
|
||||
|
||||
// misc
|
||||
void serialize(VariableSerializer *serializer) const;
|
||||
virtual void serializeImpl(VariableSerializer *serializer) const;
|
||||
bool hasInternalReference(PointerSet &vars, bool ds = false) const;
|
||||
virtual void dump() const;
|
||||
virtual ObjectData *clone();
|
||||
|
||||
Variant offsetGet(Variant key);
|
||||
|
||||
// magic methods
|
||||
// __construct is handled in a special way
|
||||
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 String t___tostring();
|
||||
virtual Variant t___clone();
|
||||
|
||||
static int GetMaxId() ATTRIBUTE_COLD;
|
||||
protected:
|
||||
virtual bool php_sleep(Variant &ret);
|
||||
public:
|
||||
CArrRef getProperties() const { return o_properties; }
|
||||
void initProperties(int nProp);
|
||||
private:
|
||||
static DECLARE_THREAD_LOCAL_NO_CHECK(int, os_max_id);
|
||||
ObjectData(const ObjectData &) { assert(false);}
|
||||
inline Variant o_getImpl(CStrRef propName, int flags,
|
||||
bool error = true, CStrRef context = null_string);
|
||||
template <typename T>
|
||||
inline Variant o_setImpl(CStrRef propName, T v,
|
||||
bool forInit, CStrRef context);
|
||||
public:
|
||||
// ResourceData overrides this setting IsResourceClass to true;
|
||||
// various macros check whether type T is a resource type by
|
||||
// inspecting "T::IsResourceClass".
|
||||
static const bool IsResourceClass = false;
|
||||
|
||||
// this will be hopefully packed together with _count from parent class
|
||||
static int ObjAllocatorSizeClassCount;
|
||||
private:
|
||||
mutable int16_t o_attribute; // various flags
|
||||
protected:
|
||||
// 16 bits of unused memory that can be reused by subclasses
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint8_t u8[2];
|
||||
} o_subclassData;
|
||||
|
||||
protected:
|
||||
Class* m_cls;
|
||||
|
||||
protected:
|
||||
ArrNR o_properties; // dynamic properties (VM and hphpc)
|
||||
int o_id; // a numeric identifier of this object
|
||||
|
||||
private:
|
||||
static void compileTimeAssertions() {
|
||||
static_assert(offsetof(ObjectData, _count) == FAST_REFCOUNT_OFFSET,
|
||||
"Offset of ObjectData._count must be FAST_REFCOUNT_OFFSET");
|
||||
}
|
||||
|
||||
public:
|
||||
void release() {
|
||||
assert(getCount() == 0);
|
||||
destruct();
|
||||
if (UNLIKELY(getCount() != 0)) {
|
||||
// Object was resurrected.
|
||||
return;
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
public:
|
||||
void getChildren(std::vector<TypedValue *> &out) {
|
||||
ArrayData *props = o_properties.get();
|
||||
if (props) {
|
||||
props->getChildren(out);
|
||||
}
|
||||
}
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
template<> inline SmartPtr<ObjectData>::~SmartPtr() {}
|
||||
|
||||
typedef GlobalNameValueTableWrapper GlobalVariables;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Calculate item sizes for object allocators
|
||||
|
||||
#define WORD_SIZE sizeof(TypedValue)
|
||||
#define ALIGN_WORD(n) ((n) + (WORD_SIZE - (n) % WORD_SIZE) % WORD_SIZE)
|
||||
|
||||
// Mapping from index to size class for objects. Mapping in the other
|
||||
// direction is available from ObjectSizeClass<> below.
|
||||
template<int Idx> class ObjectSizeTable {
|
||||
enum { prevSize = ObjectSizeTable<Idx - 1>::value };
|
||||
public:
|
||||
enum {
|
||||
value = ALIGN_WORD(prevSize + (prevSize >> 1))
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct ObjectSizeTable<0> {
|
||||
enum { value = sizeof(ObjectData) };
|
||||
};
|
||||
|
||||
#undef WORD_SIZE
|
||||
#undef ALIGN_WORD
|
||||
|
||||
/*
|
||||
* This determines the highest size class we can have by looking for
|
||||
* the first entry in our table that is larger than the hard coded
|
||||
* SmartAllocator SLAB_SIZE. This is because you can't (currently)
|
||||
* SmartAllocate chunks that are potentially bigger than a slab. If
|
||||
* you introduce a bigger size class, SmartAllocator will hit an
|
||||
* assertion at runtime. The last size class currently goes up to
|
||||
* 97096 bytes -- enough room for 6064 TypedValues. Hopefully that's
|
||||
* enough.
|
||||
*/
|
||||
template<int Index>
|
||||
struct DetermineLargestSizeClass {
|
||||
typedef typename boost::mpl::eval_if_c<
|
||||
(ObjectSizeTable<Index>::value > SLAB_SIZE),
|
||||
boost::mpl::int_<Index>,
|
||||
DetermineLargestSizeClass<Index + 1>
|
||||
>::type type;
|
||||
};
|
||||
const int NumObjectSizeClasses = DetermineLargestSizeClass<0>::type::value;
|
||||
|
||||
template<size_t Sz, int Index> struct LookupObjSizeIndex {
|
||||
enum { index =
|
||||
Sz <= ObjectSizeTable<Index>::value
|
||||
? Index : LookupObjSizeIndex<Sz,Index + 1>::index };
|
||||
};
|
||||
template<size_t Sz> struct LookupObjSizeIndex<Sz,NumObjectSizeClasses> {
|
||||
enum { index = NumObjectSizeClasses };
|
||||
};
|
||||
|
||||
template<size_t Sz>
|
||||
struct ObjectSizeClass {
|
||||
enum {
|
||||
index = LookupObjSizeIndex<Sz,0>::index,
|
||||
value = ObjectSizeTable<index>::value
|
||||
};
|
||||
};
|
||||
|
||||
typedef ObjectAllocatorBase *(*ObjectAllocatorBaseGetter)(void);
|
||||
|
||||
class ObjectAllocatorCollector {
|
||||
public:
|
||||
static std::map<int, ObjectAllocatorBaseGetter> &getWrappers() {
|
||||
static std::map<int, ObjectAllocatorBaseGetter> wrappers;
|
||||
return wrappers;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void *ObjectAllocatorInitSetup() {
|
||||
ThreadLocalSingleton<ObjectAllocator<
|
||||
ObjectSizeClass<sizeof(T)>::value> > tls;
|
||||
int index = ObjectSizeClass<sizeof(T)>::index;
|
||||
ObjectAllocatorCollector::getWrappers()[index] =
|
||||
(ObjectAllocatorBaseGetter)tls.getCheck;
|
||||
GetAllocatorInitList().insert((AllocatorThreadLocalInit)(tls.getCheck));
|
||||
return (void*)tls.getNoCheck;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the index in ThreadInfo::m_allocators for the allocator
|
||||
* responsible for a given object size.
|
||||
*
|
||||
* There is a maximum limit on the size of allocatable objects. If
|
||||
* this is reached, this function returns -1.
|
||||
*/
|
||||
int object_alloc_size_to_index(size_t size);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Attribute helpers
|
||||
class AttributeSetter {
|
||||
public:
|
||||
AttributeSetter(ObjectData::Attribute a, ObjectData *o) : m_a(a), m_o(o) {
|
||||
o->setAttribute(a);
|
||||
}
|
||||
~AttributeSetter() {
|
||||
m_o->clearAttribute(m_a);
|
||||
}
|
||||
private:
|
||||
ObjectData::Attribute m_a;
|
||||
ObjectData *m_o;
|
||||
};
|
||||
|
||||
class AttributeClearer {
|
||||
public:
|
||||
AttributeClearer(ObjectData::Attribute a, ObjectData *o) : m_a(a), m_o(o) {
|
||||
o->clearAttribute(a);
|
||||
}
|
||||
~AttributeClearer() {
|
||||
m_o->setAttribute(m_a);
|
||||
}
|
||||
private:
|
||||
ObjectData::Attribute m_a;
|
||||
ObjectData *m_o;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE inline void decRefObj(ObjectData* obj) {
|
||||
if (obj->decRefCount() == 0) obj->release();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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) {}
|
||||
static DECLARE_THREAD_LOCAL_NO_CHECK(int, os_max_id);
|
||||
|
||||
public:
|
||||
// This constructor is used for all cppext classes (including resources)
|
||||
// and their descendents.
|
||||
Instance(Class* cls, bool isResource)
|
||||
: ObjectData(isResource, cls) {
|
||||
ObjectData(Class* cls, bool isResource) : o_attribute(0), m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
if (!isResource) {
|
||||
o_id = ++(*os_max_id);
|
||||
}
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
virtual ~Instance() {}
|
||||
private:
|
||||
// The two constructors below are used for all pure classes that are not
|
||||
// descendents of cppext classes
|
||||
explicit ObjectData(Class* cls) : o_attribute(0), m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
o_id = ++(*os_max_id);
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
static int ObjAllocatorSizeClassCount;
|
||||
enum class NoInit { noinit };
|
||||
explicit ObjectData(Class* cls, NoInit) : o_attribute(0), m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
o_id = ++(*os_max_id);
|
||||
}
|
||||
|
||||
static void raiseAbstractClassError(Class* cls);
|
||||
// Disallow copy construction
|
||||
ObjectData(const ObjectData&) = delete;
|
||||
|
||||
// Call newInstance() to instantiate an Instance
|
||||
static Instance* newInstance(Class* cls) {
|
||||
public:
|
||||
virtual ~ObjectData(); // all PHP classes need virtual tables
|
||||
|
||||
// Call newInstance() to instantiate a PHP object
|
||||
static ObjectData* newInstance(Class* cls) {
|
||||
if (cls->m_InstanceCtor) {
|
||||
return cls->m_InstanceCtor(cls);
|
||||
}
|
||||
@@ -455,13 +124,13 @@ class Instance : public ObjectData {
|
||||
}
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t size = sizeForNProps(nProps);
|
||||
Instance* obj = (Instance*)ALLOCOBJSZ(size);
|
||||
new (obj) Instance(cls);
|
||||
ObjectData* obj = (ObjectData*)ALLOCOBJSZ(size);
|
||||
new (obj) ObjectData(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
|
||||
throw exceptions. If we have this in the ObjectData
|
||||
constructor, and it throws, obj will be partially
|
||||
destroyed (ie ~ObjectData will be called, resetting
|
||||
the vtable pointer) leaving dangling references
|
||||
@@ -475,7 +144,7 @@ class Instance : public ObjectData {
|
||||
// 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);
|
||||
static ObjectData* newInstanceRaw(Class* cls, int idx);
|
||||
|
||||
private:
|
||||
void instanceInit(Class* cls) {
|
||||
@@ -501,30 +170,166 @@ class Instance : public ObjectData {
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void operator delete(void* p);
|
||||
|
||||
void release() {
|
||||
assert(getCount() == 0);
|
||||
destruct();
|
||||
if (UNLIKELY(getCount() != 0)) {
|
||||
// Object was resurrected.
|
||||
return;
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
void setId(const ObjectData* r) { if (r) o_id = r->o_id; }
|
||||
|
||||
Class* getVMClass() const {
|
||||
return m_cls;
|
||||
}
|
||||
static size_t getVMClassOffset() {
|
||||
// For assembly linkage.
|
||||
return offsetof(ObjectData, m_cls);
|
||||
}
|
||||
static size_t attributeOff() { return offsetof(ObjectData, o_attribute); }
|
||||
bool instanceof(const Class* c) const;
|
||||
|
||||
bool isCollection() const {
|
||||
return getCollectionType() != Collection::InvalidType;
|
||||
}
|
||||
Collection::Type getCollectionType() const {
|
||||
// Return the upper 3 bits of o_attribute
|
||||
return (Collection::Type)((uint16_t)(o_attribute >> 13) & 7);
|
||||
}
|
||||
|
||||
bool implementsIterator() {
|
||||
return (instanceof(SystemLib::s_IteratorClass));
|
||||
}
|
||||
|
||||
void setAttributes(int attrs) { o_attribute |= attrs; }
|
||||
void setAttributes(const ObjectData* o) { o_attribute |= o->o_attribute; }
|
||||
bool getAttribute(Attribute attr) const { return o_attribute & attr; }
|
||||
void setAttribute(Attribute attr) const { o_attribute |= attr;}
|
||||
void clearAttribute(Attribute attr) const { o_attribute &= ~attr;}
|
||||
bool noDestruct() const { return getAttribute(NoDestructor); }
|
||||
void setNoDestruct() { setAttribute(NoDestructor); }
|
||||
ObjectData* clearNoDestruct() { clearAttribute(NoDestructor); return this; }
|
||||
|
||||
Object iterableObject(bool& isIterable, bool mayImplementIterator = true);
|
||||
ArrayIter begin(CStrRef context = null_string);
|
||||
MutableArrayIter begin(Variant* key, Variant& val,
|
||||
CStrRef context = null_string);
|
||||
|
||||
/**
|
||||
* o_instanceof() can be used for both classes and interfaces.
|
||||
* It is also worth noting that o_instanceof will always return
|
||||
* false for classes that are descendents of ResourceData.
|
||||
*/
|
||||
bool o_instanceof(CStrRef s) const;
|
||||
|
||||
// class info
|
||||
CStrRef o_getClassName() const;
|
||||
CStrRef o_getParentName() const;
|
||||
virtual CStrRef o_getClassNameHook() const;
|
||||
virtual bool isResource() const { return false; }
|
||||
int o_getId() const { return o_id;}
|
||||
|
||||
bool o_toBoolean() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toBooleanImpl();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t o_toInt64() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toInt64Impl();
|
||||
}
|
||||
raiseObjToIntNotice(o_getClassName().data());
|
||||
return 1;
|
||||
}
|
||||
|
||||
double o_toDouble() const {
|
||||
if (getAttribute(CallToImpl)) {
|
||||
return o_toDoubleImpl();
|
||||
}
|
||||
return o_toInt64();
|
||||
}
|
||||
|
||||
// overridable casting
|
||||
virtual bool o_toBooleanImpl() const noexcept;
|
||||
virtual int64_t o_toInt64Impl() const noexcept;
|
||||
virtual double o_toDoubleImpl() const noexcept;
|
||||
virtual Array o_toArray() const;
|
||||
|
||||
void destruct();
|
||||
|
||||
Array o_toIterArray(CStrRef context, bool getRef = false);
|
||||
|
||||
Variant* o_realProp(CStrRef s, int flags,
|
||||
CStrRef context = null_string) const;
|
||||
|
||||
Variant o_get(CStrRef s, bool error = true,
|
||||
CStrRef context = null_string);
|
||||
|
||||
Variant o_set(CStrRef s, CVarRef v);
|
||||
Variant o_set(CStrRef s, RefResult v);
|
||||
Variant o_setRef(CStrRef s, CVarRef v);
|
||||
|
||||
Variant o_set(CStrRef s, CVarRef v, CStrRef context);
|
||||
Variant o_set(CStrRef s, RefResult v, CStrRef context);
|
||||
Variant o_setRef(CStrRef s, CVarRef v, CStrRef context);
|
||||
|
||||
void o_setArray(CArrRef properties);
|
||||
void o_getArray(Array& props, bool pubOnly = false) const;
|
||||
|
||||
static Object FromArray(ArrayData* properties);
|
||||
|
||||
// TODO Task #2584896: o_invoke and o_invoke_few_args are deprecated. These
|
||||
// APIs don't properly take class context into account when looking up the
|
||||
// method, and they duplicate some of the functionality from invokeFunc(),
|
||||
// invokeFuncFew(), and vm_decode_function(). We should remove these APIs
|
||||
// and migrate all callers to use invokeFunc(), invokeFuncFew(), and
|
||||
// vm_decode_function() instead.
|
||||
Variant o_invoke(CStrRef s, CArrRef params, bool fatal = true);
|
||||
Variant o_invoke_few_args(CStrRef s, int count,
|
||||
INVOKE_FEW_ARGS_DECL_ARGS);
|
||||
|
||||
void serialize(VariableSerializer* serializer) const;
|
||||
virtual void serializeImpl(VariableSerializer* serializer) const;
|
||||
bool hasInternalReference(PointerSet& vars, bool ds = false) const;
|
||||
virtual void dump() const;
|
||||
virtual ObjectData* clone();
|
||||
|
||||
Variant offsetGet(Variant key);
|
||||
|
||||
virtual Variant t___sleep();
|
||||
virtual Variant t___wakeup();
|
||||
virtual String t___tostring();
|
||||
|
||||
static int GetMaxId() ATTRIBUTE_COLD;
|
||||
|
||||
protected:
|
||||
virtual bool php_sleep(Variant& ret);
|
||||
|
||||
public:
|
||||
CArrRef getDynProps() const { return o_properties; }
|
||||
void initProperties(int nProp);
|
||||
|
||||
void getChildren(std::vector<TypedValue*> &out) {
|
||||
ArrayData* props = o_properties.get();
|
||||
if (props) {
|
||||
props->getChildren(out);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
ObjectData* callCustomInstanceInit();
|
||||
|
||||
//============================================================================
|
||||
// Miscellaneous.
|
||||
@@ -540,24 +345,25 @@ class Instance : public ObjectData {
|
||||
}
|
||||
|
||||
static size_t sizeForNProps(Slot nProps) {
|
||||
size_t sz = sizeof(Instance) + (sizeof(TypedValue) * nProps);
|
||||
size_t sz = sizeof(ObjectData) + (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();
|
||||
}
|
||||
int builtinPropSize() const { return m_cls->builtinPropSize(); }
|
||||
|
||||
// public for ObjectData access
|
||||
private:
|
||||
void initDynProps(int numDynamic = 0);
|
||||
Slot declPropInd(TypedValue* prop) const;
|
||||
private:
|
||||
|
||||
inline Variant o_getImpl(CStrRef propName, int flags,
|
||||
bool error = true, CStrRef context = null_string);
|
||||
template <typename T>
|
||||
inline Variant o_setImpl(CStrRef propName, T v,
|
||||
bool forInit, CStrRef context);
|
||||
template <bool declOnly>
|
||||
TypedValue* getPropImpl(Class* ctx, const StringData* key, bool& visible,
|
||||
bool& accessible, bool& unset);
|
||||
@@ -606,20 +412,176 @@ class Instance : public ObjectData {
|
||||
const StringData* key, TypedValue& dest);
|
||||
void unsetProp(Class* ctx, const StringData* key);
|
||||
|
||||
static void raiseObjToIntNotice(const char*);
|
||||
static void raiseAbstractClassError(Class* cls);
|
||||
void raiseUndefProp(const StringData* name);
|
||||
|
||||
friend class ObjectData;
|
||||
private:
|
||||
static void compileTimeAssertions() {
|
||||
static_assert(offsetof(ObjectData, _count) == FAST_REFCOUNT_OFFSET,
|
||||
"Offset of ObjectData._count must be FAST_REFCOUNT_OFFSET");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// ObjectData fields
|
||||
|
||||
// o_attribute and o_subclassData will hopefully be packed together
|
||||
// with _count from parent class
|
||||
private:
|
||||
// Various per-instance flags
|
||||
mutable int16_t o_attribute;
|
||||
protected:
|
||||
// 16 bits of memory that can be reused by subclasses
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint8_t u8[2];
|
||||
} o_subclassData;
|
||||
// Pointer to this object's class
|
||||
Class* m_cls;
|
||||
// Storage for dynamic properties
|
||||
ArrNR o_properties;
|
||||
// Numeric identifier of this object (used for var_dump())
|
||||
int o_id;
|
||||
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
template<> inline SmartPtr<ObjectData>::~SmartPtr() {}
|
||||
|
||||
typedef GlobalNameValueTableWrapper GlobalVariables;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Calculate item sizes for object allocators
|
||||
|
||||
#define WORD_SIZE sizeof(TypedValue)
|
||||
#define ALIGN_WORD(n) ((n) + (WORD_SIZE - (n) % WORD_SIZE) % WORD_SIZE)
|
||||
|
||||
// Mapping from index to size class for objects. Mapping in the other
|
||||
// direction is available from ObjectSizeClass<> below.
|
||||
template<int Idx> class ObjectSizeTable {
|
||||
enum { prevSize = ObjectSizeTable<Idx - 1>::value };
|
||||
public:
|
||||
enum {
|
||||
value = ALIGN_WORD(prevSize + (prevSize >> 1))
|
||||
};
|
||||
};
|
||||
|
||||
inline Instance* instanceFromTv(TypedValue* tv) {
|
||||
assert(dynamic_cast<Instance*>(tv->m_data.pobj));
|
||||
return static_cast<Instance*>(tv->m_data.pobj);
|
||||
template<> struct ObjectSizeTable<0> {
|
||||
enum { value = sizeof(ObjectData) };
|
||||
};
|
||||
|
||||
#undef WORD_SIZE
|
||||
#undef ALIGN_WORD
|
||||
|
||||
/*
|
||||
* This determines the highest size class we can have by looking for
|
||||
* the first entry in our table that is larger than the hard coded
|
||||
* SmartAllocator SLAB_SIZE. This is because you can't (currently)
|
||||
* SmartAllocate chunks that are potentially bigger than a slab. If
|
||||
* you introduce a bigger size class, SmartAllocator will hit an
|
||||
* assertion at runtime. The last size class currently goes up to
|
||||
* 97096 bytes -- enough room for 6064 TypedValues. Hopefully that's
|
||||
* enough.
|
||||
*/
|
||||
template<int Index>
|
||||
struct DetermineLargestSizeClass {
|
||||
typedef typename boost::mpl::eval_if_c<
|
||||
(ObjectSizeTable<Index>::value > SLAB_SIZE),
|
||||
boost::mpl::int_<Index>,
|
||||
DetermineLargestSizeClass<Index + 1>
|
||||
>::type type;
|
||||
};
|
||||
const int NumObjectSizeClasses = DetermineLargestSizeClass<0>::type::value;
|
||||
|
||||
template<size_t Sz, int Index> struct LookupObjSizeIndex {
|
||||
enum { index =
|
||||
Sz <= ObjectSizeTable<Index>::value
|
||||
? Index : LookupObjSizeIndex<Sz,Index + 1>::index };
|
||||
};
|
||||
template<size_t Sz> struct LookupObjSizeIndex<Sz,NumObjectSizeClasses> {
|
||||
enum { index = NumObjectSizeClasses };
|
||||
};
|
||||
|
||||
template<size_t Sz>
|
||||
struct ObjectSizeClass {
|
||||
enum {
|
||||
index = LookupObjSizeIndex<Sz,0>::index,
|
||||
value = ObjectSizeTable<index>::value
|
||||
};
|
||||
};
|
||||
|
||||
typedef ObjectAllocatorBase*(*ObjectAllocatorBaseGetter)(void);
|
||||
|
||||
class ObjectAllocatorCollector {
|
||||
public:
|
||||
static std::map<int, ObjectAllocatorBaseGetter> &getWrappers() {
|
||||
static std::map<int, ObjectAllocatorBaseGetter> wrappers;
|
||||
return wrappers;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void* ObjectAllocatorInitSetup() {
|
||||
ThreadLocalSingleton<ObjectAllocator<
|
||||
ObjectSizeClass<sizeof(T)>::value> > tls;
|
||||
int index = ObjectSizeClass<sizeof(T)>::index;
|
||||
ObjectAllocatorCollector::getWrappers()[index] =
|
||||
(ObjectAllocatorBaseGetter)tls.getCheck;
|
||||
GetAllocatorInitList().insert((AllocatorThreadLocalInit)(tls.getCheck));
|
||||
return (void*)tls.getNoCheck;
|
||||
}
|
||||
|
||||
class ExtObjectData : public HPHP::Instance {
|
||||
/*
|
||||
* Return the index in ThreadInfo::m_allocators for the allocator
|
||||
* responsible for a given object size.
|
||||
*
|
||||
* There is a maximum limit on the size of allocatable objects. If
|
||||
* this is reached, this function returns -1.
|
||||
*/
|
||||
int object_alloc_size_to_index(size_t size);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Attribute helpers
|
||||
class AttributeSetter {
|
||||
public:
|
||||
AttributeSetter(ObjectData::Attribute a, ObjectData* o) : m_a(a), m_o(o) {
|
||||
o->setAttribute(a);
|
||||
}
|
||||
~AttributeSetter() {
|
||||
m_o->clearAttribute(m_a);
|
||||
}
|
||||
private:
|
||||
ObjectData::Attribute m_a;
|
||||
ObjectData* m_o;
|
||||
};
|
||||
|
||||
class AttributeClearer {
|
||||
public:
|
||||
AttributeClearer(ObjectData::Attribute a, ObjectData* o) : m_a(a), m_o(o) {
|
||||
o->clearAttribute(a);
|
||||
}
|
||||
~AttributeClearer() {
|
||||
m_o->setAttribute(m_a);
|
||||
}
|
||||
private:
|
||||
ObjectData::Attribute m_a;
|
||||
ObjectData* m_o;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE inline void decRefObj(ObjectData* obj) {
|
||||
if (obj->decRefCount() == 0) obj->release();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline ObjectData* instanceFromTv(TypedValue* tv) {
|
||||
assert(tv->m_type == KindOfObject);
|
||||
assert(dynamic_cast<ObjectData*>(tv->m_data.pobj));
|
||||
return tv->m_data.pobj;
|
||||
}
|
||||
|
||||
class ExtObjectData : public ObjectData {
|
||||
public:
|
||||
explicit ExtObjectData(HPHP::Class* cls)
|
||||
: HPHP::Instance(cls, false) {
|
||||
explicit ExtObjectData(HPHP::Class* cls) : ObjectData(cls, false) {
|
||||
assert(!m_cls->callsCustomInstanceInit());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ int ResourceData::GetMaxResourceId() {
|
||||
}
|
||||
|
||||
ResourceData::ResourceData()
|
||||
: Instance(SystemLib::s_resourceClass, true) {
|
||||
: ObjectData(SystemLib::s_resourceClass, true) {
|
||||
assert(!m_cls->callsCustomInstanceInit());
|
||||
ObjectData::setAttributes(ObjectData::CallToImpl);
|
||||
int &pmax = *os_max_resource_id;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace HPHP {
|
||||
* Base class of all resources used by extensions for opaquely passing object
|
||||
* pointers.
|
||||
*/
|
||||
class ResourceData : public Instance {
|
||||
class ResourceData : public ObjectData {
|
||||
public:
|
||||
ResourceData();
|
||||
virtual ~ResourceData();
|
||||
|
||||
@@ -2455,12 +2455,12 @@ void Variant::unserialize(VariableUnserializer *uns,
|
||||
}
|
||||
}
|
||||
if (cls) {
|
||||
obj = Instance::newInstance(cls);
|
||||
obj = ObjectData::newInstance(cls);
|
||||
if (UNLIKELY(cls == c_Pair::s_cls && size != 2)) {
|
||||
throw Exception("Pair objects must have exactly 2 elements");
|
||||
}
|
||||
} else {
|
||||
obj = Instance::newInstance(
|
||||
obj = ObjectData::newInstance(
|
||||
SystemLib::s___PHP_Incomplete_ClassClass);
|
||||
obj->o_set(s_PHP_Incomplete_Class_Name, clsName);
|
||||
}
|
||||
|
||||
@@ -217,11 +217,6 @@ void c_Continuation::copyContinuationVars(ActRec* fp) {
|
||||
}
|
||||
}
|
||||
|
||||
// unused
|
||||
Variant c_Continuation::t___clone() {
|
||||
not_reached();
|
||||
}
|
||||
|
||||
c_Continuation *c_Continuation::clone() {
|
||||
const Func *origFunc = m_origFunc;
|
||||
const Func *genFunc = actRec()->m_func;
|
||||
|
||||
@@ -79,7 +79,6 @@ public:
|
||||
void t_raise(CVarRef v);
|
||||
String t_getorigfuncname();
|
||||
String t_getcalledclass();
|
||||
Variant t___clone();
|
||||
|
||||
c_Continuation* clone();
|
||||
|
||||
|
||||
@@ -574,7 +574,7 @@ static Object pdo_stmt_instantiate(sp_PDOConnection dbh, CStrRef clsname,
|
||||
if (!cls) {
|
||||
return Object();
|
||||
}
|
||||
return HPHP::Instance::newInstance(cls);
|
||||
return ObjectData::newInstance(cls);
|
||||
}
|
||||
|
||||
static void pdo_stmt_construct(sp_PDOStatement stmt, Object object,
|
||||
@@ -588,7 +588,7 @@ static void pdo_stmt_construct(sp_PDOStatement stmt, Object object,
|
||||
}
|
||||
object->o_set("queryString", stmt->query_string);
|
||||
TypedValue ret;
|
||||
Instance* inst = static_cast<Instance*>(object.get());
|
||||
ObjectData* inst = object.get();
|
||||
inst->invokeUserMethod(&ret, cls->getCtor(), ctor_args.toArray());
|
||||
tvRefcountedDecRef(&ret);
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ Variant c_SimpleXMLElement::t___set(Variant name, Variant value) {
|
||||
}
|
||||
|
||||
bool c_SimpleXMLElement::o_toBooleanImpl() const noexcept {
|
||||
return m_node != NULL || getProperties().size();
|
||||
return (m_node || getDynProps().size());
|
||||
}
|
||||
|
||||
int64_t c_SimpleXMLElement::o_toInt64Impl() const noexcept {
|
||||
|
||||
@@ -24,8 +24,7 @@ namespace HPHP {
|
||||
|
||||
struct ActRec;
|
||||
|
||||
class Instance;
|
||||
;
|
||||
class ObjectData;
|
||||
|
||||
struct HhbcExtFuncInfo {
|
||||
const char* m_name;
|
||||
@@ -40,7 +39,7 @@ struct HhbcExtMethodInfo {
|
||||
|
||||
struct HhbcExtClassInfo {
|
||||
const char* m_name;
|
||||
HPHP::Instance* (*m_InstanceCtor)(HPHP::Class*);
|
||||
ObjectData* (*m_InstanceCtor)(HPHP::Class*);
|
||||
int m_sizeof;
|
||||
long long m_methodCount;
|
||||
const HhbcExtMethodInfo* m_methods;
|
||||
|
||||
@@ -246,12 +246,12 @@ void traceImpl(const Visitor& visit, ObjectData* obj) {
|
||||
// Dynamic properties. We have to visit the dynamic property array
|
||||
// itself, since it is an object living in the smart heap (all the
|
||||
// top-level walks visit it anyway).
|
||||
if (ArrayData* dyn = obj->getProperties().get()) {
|
||||
if (ArrayData* dyn = obj->getDynProps().get()) {
|
||||
visit(dyn);
|
||||
}
|
||||
|
||||
// Declared properties. We need to indirect through the TypedValue
|
||||
// before visiting, since these are in-situ in the Instance.
|
||||
// Declared properties. We need to indirect through the TypedValue
|
||||
// before visiting, since these are in-situ in the ObjectData.
|
||||
void* vpObj = obj;
|
||||
unsigned char* address = static_cast<unsigned char*>(vpObj);
|
||||
|
||||
|
||||
@@ -2531,9 +2531,8 @@ void VMExecutionContext::treadmillSharedVars() {
|
||||
void VMExecutionContext::destructObjects() {
|
||||
if (UNLIKELY(RuntimeOption::EnableObjDestructCall)) {
|
||||
while (!m_liveBCObjs.empty()) {
|
||||
ObjectData* o = *m_liveBCObjs.begin();
|
||||
Instance* instance = static_cast<Instance*>(o);
|
||||
instance->destruct(); // Let the instance remove the node.
|
||||
ObjectData* obj = *m_liveBCObjs.begin();
|
||||
obj->destruct(); // Let the instance remove the node.
|
||||
}
|
||||
m_liveBCObjs.clear();
|
||||
}
|
||||
@@ -4270,8 +4269,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopUnwind(PC& pc) {
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopThrow(PC& pc) {
|
||||
Cell* c1 = m_stack.topC();
|
||||
if (c1->m_type != KindOfObject ||
|
||||
!static_cast<Instance*>(c1->m_data.pobj)->
|
||||
instanceof(SystemLib::s_ExceptionClass)) {
|
||||
!c1->m_data.pobj->instanceof(SystemLib::s_ExceptionClass)) {
|
||||
raise_error("Exceptions must be valid objects derived from the "
|
||||
"Exception base class");
|
||||
}
|
||||
|
||||
+11
-13
@@ -43,7 +43,6 @@ class FuncEmitter;
|
||||
class Unit;
|
||||
class UnitEmitter;
|
||||
class Class;
|
||||
class Instance;
|
||||
class NamedEntity;
|
||||
class PreClass;
|
||||
|
||||
@@ -51,7 +50,7 @@ typedef hphp_hash_set<const StringData*, string_data_hash,
|
||||
string_data_isame> TraitNameSet;
|
||||
typedef hphp_hash_set<const Class*, pointer_hash<Class> > ClassSet;
|
||||
|
||||
typedef Instance*(*BuiltinCtorFunction)(Class*);
|
||||
typedef ObjectData*(*BuiltinCtorFunction)(Class*);
|
||||
|
||||
/*
|
||||
* A PreClass represents the source-level definition of a php class,
|
||||
@@ -364,8 +363,7 @@ typedef AtomicSmartPtr<Class> ClassPtr;
|
||||
class Class : public AtomicCountable {
|
||||
public:
|
||||
friend class ExecutionContext;
|
||||
friend class HPHP::ObjectData;
|
||||
friend class Instance;
|
||||
friend class ObjectData;
|
||||
friend class Unit;
|
||||
|
||||
enum class Avail {
|
||||
@@ -540,7 +538,7 @@ public:
|
||||
const InitVec& pinitVec() const { return m_pinitVec; }
|
||||
const PropInitVec& declPropInit() const { return m_declPropInit; }
|
||||
|
||||
// ObjectData attributes, to be set during Instance initialization.
|
||||
// ObjectData attributes, to be set during instance initialization.
|
||||
int getODAttrs() const { return m_ODAttrs; }
|
||||
|
||||
int builtinPropSize() const { return m_builtinPropSize; }
|
||||
@@ -819,14 +817,14 @@ private:
|
||||
|
||||
// Properties.
|
||||
//
|
||||
// Each Instance is created with enough trailing space to directly store the
|
||||
// vector of declared properties. To look up a property by name and
|
||||
// determine whether it is declared, use m_declPropMap. If the declared
|
||||
// property index is already known (as may be the case when executing via the
|
||||
// TC), property metadata in m_declPropInfo can be directly accessed.
|
||||
// Each ObjectData is created with enough trailing space to directly store
|
||||
// the vector of declared properties. To look up a property by name and
|
||||
// determine whether it is declared, use m_declPropMap. If the declared
|
||||
// property index is already known (as may be the case when executing via
|
||||
// the TC), property metadata in m_declPropInfo can be directly accessed.
|
||||
//
|
||||
// m_declPropInit is indexed by the Slot values from
|
||||
// m_declProperties, and contains initialization information.
|
||||
// m_declPropInit is indexed by the Slot values from m_declProperties, and
|
||||
// contains initialization information.
|
||||
|
||||
PropMap m_declProperties;
|
||||
PropInitVec m_declPropInit;
|
||||
@@ -866,6 +864,6 @@ struct class_same {
|
||||
}
|
||||
};
|
||||
|
||||
} // HPHP::VM
|
||||
} // HPHP
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3402,8 +3402,9 @@ const Func* loadClassCtor(Class* cls) {
|
||||
return f;
|
||||
}
|
||||
|
||||
Instance* createClHelper(Class* cls, int numArgs, ActRec* ar, TypedValue* sp) {
|
||||
Instance* newObj = newInstance(cls);
|
||||
ObjectData* createClHelper(Class* cls, int numArgs, ActRec* ar,
|
||||
TypedValue* sp) {
|
||||
ObjectData* newObj = newInstance(cls);
|
||||
newObj->incRefCount();
|
||||
return static_cast<c_Closure*>(newObj)->init(numArgs, ar, sp);
|
||||
}
|
||||
@@ -3449,11 +3450,11 @@ void CodeGenerator::cgAllocObjFast(IRInstruction* inst) {
|
||||
SyncOptions::kSyncPoint,
|
||||
ArgGroup(m_regs).imm((uint64_t)cls));
|
||||
} else {
|
||||
size_t size = Instance::sizeForNProps(cls->numDeclProperties());
|
||||
size_t size = ObjectData::sizeForNProps(cls->numDeclProperties());
|
||||
int allocator = object_alloc_size_to_index(size);
|
||||
assert(allocator != -1);
|
||||
cgCallHelper(m_as,
|
||||
(TCA)getMethodPtr(&Instance::newInstanceRaw),
|
||||
(TCA)getMethodPtr(&ObjectData::newInstanceRaw),
|
||||
dstReg,
|
||||
SyncOptions::kSyncPoint,
|
||||
ArgGroup(m_regs).imm((uint64_t)cls).imm(allocator));
|
||||
@@ -3518,7 +3519,7 @@ void CodeGenerator::cgAllocObjFast(IRInstruction* inst) {
|
||||
if (cls->callsCustomInstanceInit()) {
|
||||
// callCustomInstanceInit returns the instance in rax
|
||||
cgCallHelper(m_as,
|
||||
(TCA)getMethodPtr(&Instance::callCustomInstanceInit),
|
||||
(TCA)getMethodPtr(&ObjectData::callCustomInstanceInit),
|
||||
dstReg,
|
||||
SyncOptions::kSyncPoint,
|
||||
ArgGroup(m_regs).reg(dstReg));
|
||||
|
||||
@@ -547,7 +547,7 @@ private:
|
||||
|
||||
const Func* loadClassCtor(Class* cls);
|
||||
|
||||
Instance* createClHelper(Class*, int, ActRec*, TypedValue*);
|
||||
ObjectData* createClHelper(Class*, int, ActRec*, TypedValue*);
|
||||
|
||||
void genCodeForTrace(IRTrace* trace,
|
||||
CodeGenerator::Asm& a,
|
||||
|
||||
@@ -226,7 +226,7 @@ void raisePropertyOnNonObject() {
|
||||
}
|
||||
|
||||
void raiseUndefProp(ObjectData* base, const StringData* name) {
|
||||
static_cast<Instance*>(base)->raiseUndefProp(name);
|
||||
base->raiseUndefProp(name);
|
||||
}
|
||||
|
||||
void raise_error_sd(const StringData *msg) {
|
||||
|
||||
@@ -2893,11 +2893,11 @@ bool TranslatorX64::eagerRecord(const Func* func) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance*
|
||||
ObjectData*
|
||||
HOT_FUNC_VM
|
||||
newInstanceHelper(Class* cls, int numArgs, ActRec* ar, ActRec* prevAr) {
|
||||
const Func* f = cls->getCtor();
|
||||
Instance* ret = nullptr;
|
||||
ObjectData* ret = nullptr;
|
||||
if (UNLIKELY(!(f->attrs() & AttrPublic))) {
|
||||
VMRegAnchor _;
|
||||
UNUSED MethodLookup::LookupResult res =
|
||||
|
||||
@@ -637,13 +637,13 @@ int64_t decodeCufIterHelper(Iter* it, TypedValue func);
|
||||
// These could be static but are used in hopt/codegen.cpp
|
||||
void raiseUndefVariable(StringData* nm);
|
||||
void defFuncHelper(Func *f);
|
||||
Instance* newInstanceHelper(Class* cls, int numArgs, ActRec* ar,
|
||||
ActRec* prevAr);
|
||||
Instance* newInstanceHelperCached(Class** classCache,
|
||||
const StringData* clsName, int numArgs,
|
||||
ActRec* ar, ActRec* prevAr);
|
||||
Instance* newInstanceHelperNoCtorCached(Class** classCache,
|
||||
const StringData* clsName);
|
||||
ObjectData* newInstanceHelper(Class* cls, int numArgs, ActRec* ar,
|
||||
ActRec* prevAr);
|
||||
ObjectData* newInstanceHelperCached(Class** classCache,
|
||||
const StringData* clsName, int numArgs,
|
||||
ActRec* ar, ActRec* prevAr);
|
||||
ObjectData* newInstanceHelperNoCtorCached(Class** classCache,
|
||||
const StringData* clsName);
|
||||
|
||||
bool isNormalPropertyAccess(const NormalizedInstruction& i,
|
||||
int propInput,
|
||||
|
||||
@@ -29,14 +29,14 @@ StringData* prepareAnyKey(TypedValue* tv) {
|
||||
}
|
||||
}
|
||||
|
||||
void objArrayAccess(Instance* base) {
|
||||
void objArrayAccess(ObjectData* base) {
|
||||
assert(!base->isCollection());
|
||||
if (!base->getVMClass()->classof(SystemLib::s_ArrayAccessClass)) {
|
||||
raise_error("Object does not implement ArrayAccess");
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue* objOffsetGet(TypedValue& tvRef, Instance* base,
|
||||
TypedValue* objOffsetGet(TypedValue& tvRef, ObjectData* base,
|
||||
CVarRef offset, bool validate /* = true */) {
|
||||
if (validate) {
|
||||
objArrayAccess(base);
|
||||
@@ -51,7 +51,7 @@ TypedValue* objOffsetGet(TypedValue& tvRef, Instance* base,
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool objOffsetExists(Instance* base, CVarRef offset) {
|
||||
static bool objOffsetExists(ObjectData* base, CVarRef offset) {
|
||||
objArrayAccess(base);
|
||||
TypedValue tvResult;
|
||||
tvWriteUninit(&tvResult);
|
||||
@@ -65,12 +65,12 @@ static bool objOffsetExists(Instance* base, CVarRef offset) {
|
||||
return bool(tvResult.m_data.num);
|
||||
}
|
||||
|
||||
bool objOffsetIsset(TypedValue& tvRef, Instance* base, CVarRef offset,
|
||||
bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, CVarRef offset,
|
||||
bool validate /* = true */) {
|
||||
return objOffsetExists(base, offset);
|
||||
}
|
||||
|
||||
bool objOffsetEmpty(TypedValue& tvRef, Instance* base, CVarRef offset,
|
||||
bool objOffsetEmpty(TypedValue& tvRef, ObjectData* base, CVarRef offset,
|
||||
bool validate /* = true */) {
|
||||
if (!objOffsetExists(base, offset)) {
|
||||
return true;
|
||||
@@ -80,7 +80,7 @@ bool objOffsetEmpty(TypedValue& tvRef, Instance* base, CVarRef offset,
|
||||
return empty(tvAsCVarRef(result));
|
||||
}
|
||||
|
||||
void objOffsetAppend(Instance* base, TypedValue* val,
|
||||
void objOffsetAppend(ObjectData* base, TypedValue* val,
|
||||
bool validate /* = true */) {
|
||||
assert(!base->isCollection());
|
||||
if (validate) {
|
||||
@@ -89,7 +89,7 @@ void objOffsetAppend(Instance* base, TypedValue* val,
|
||||
objOffsetSet(base, init_null_variant, val, false);
|
||||
}
|
||||
|
||||
void objOffsetSet(Instance* base, CVarRef offset, TypedValue* val,
|
||||
void objOffsetSet(ObjectData* base, CVarRef offset, TypedValue* val,
|
||||
bool validate /* = true */) {
|
||||
if (validate) {
|
||||
objArrayAccess(base);
|
||||
@@ -105,7 +105,7 @@ void objOffsetSet(Instance* base, CVarRef offset, TypedValue* val,
|
||||
tvRefcountedDecRef(&tvResult);
|
||||
}
|
||||
|
||||
void objOffsetUnset(Instance* base, CVarRef offset) {
|
||||
void objOffsetUnset(ObjectData* base, CVarRef offset) {
|
||||
objArrayAccess(base);
|
||||
static StringData* sd__offsetUnset
|
||||
= StringData::GetStaticString("offsetUnset");
|
||||
|
||||
@@ -126,17 +126,17 @@ inline void initScratchKey(TypedValue& tv, TypedValue*& key) {
|
||||
}
|
||||
}
|
||||
|
||||
void objArrayAccess(Instance* base);
|
||||
TypedValue* objOffsetGet(TypedValue& tvRef, Instance* base,
|
||||
void objArrayAccess(ObjectData* base);
|
||||
TypedValue* objOffsetGet(TypedValue& tvRef, ObjectData* base,
|
||||
CVarRef offset, bool validate=true);
|
||||
bool objOffsetIsset(TypedValue& tvRef, Instance* base, CVarRef offset,
|
||||
bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, CVarRef offset,
|
||||
bool validate=true);
|
||||
bool objOffsetEmpty(TypedValue& tvRef, Instance* base, CVarRef offset,
|
||||
bool objOffsetEmpty(TypedValue& tvRef, ObjectData* base, CVarRef offset,
|
||||
bool validate=true);
|
||||
void objOffsetSet(Instance* base, CVarRef offset, TypedValue* val,
|
||||
void objOffsetSet(ObjectData* base, CVarRef offset, TypedValue* val,
|
||||
bool validate=true);
|
||||
void objOffsetAppend(Instance* base, TypedValue* val, bool validate=true);
|
||||
void objOffsetUnset(Instance* base, CVarRef offset);
|
||||
void objOffsetAppend(ObjectData* base, TypedValue* val, bool validate=true);
|
||||
void objOffsetUnset(ObjectData* base, CVarRef offset);
|
||||
|
||||
StringData* prepareAnyKey(TypedValue* tv);
|
||||
|
||||
@@ -169,14 +169,12 @@ inline ALWAYS_INLINE void opPre(TypedValue*& base, DataType& type) {
|
||||
}
|
||||
}
|
||||
|
||||
inline TypedValue* ElemArrayRawKey(ArrayData* base,
|
||||
int64_t key) {
|
||||
inline TypedValue* ElemArrayRawKey(ArrayData* base, int64_t key) {
|
||||
TypedValue* result = base->nvGet(key);
|
||||
return result ? result : (TypedValue*)&null_variant;
|
||||
}
|
||||
|
||||
inline TypedValue* ElemArrayRawKey(ArrayData* base,
|
||||
StringData* key) {
|
||||
inline TypedValue* ElemArrayRawKey(ArrayData* base, StringData* key) {
|
||||
int64_t n;
|
||||
TypedValue* result = !key->isStrictlyInteger(n) ? base->nvGet(key) :
|
||||
base->nvGet(n);
|
||||
@@ -184,8 +182,7 @@ inline TypedValue* ElemArrayRawKey(ArrayData* base,
|
||||
}
|
||||
|
||||
template <bool warn, KeyType keyType>
|
||||
inline TypedValue* ElemArray(ArrayData* base,
|
||||
TypedValue* key) {
|
||||
inline TypedValue* ElemArray(ArrayData* base, TypedValue* key) {
|
||||
TypedValue* result;
|
||||
if (keyType == KeyType::Any) {
|
||||
DataType rtt = key->m_type;
|
||||
@@ -323,7 +320,7 @@ inline TypedValue* ElemDArray(TypedValue* base, TypedValue* key) {
|
||||
// $result
|
||||
template <bool warn, bool reffy, KeyType keyType = KeyType::Any>
|
||||
inline TypedValue* ElemD(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
TypedValue* base, TypedValue* key) {
|
||||
TypedValue* base, TypedValue* key) {
|
||||
TypedValue scratch;
|
||||
TypedValue* result;
|
||||
DataType type;
|
||||
@@ -414,7 +411,7 @@ inline TypedValue* ElemD(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
// $result
|
||||
template <KeyType keyType = KeyType::Any>
|
||||
inline TypedValue* ElemU(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
TypedValue* base, TypedValue* key) {
|
||||
TypedValue* base, TypedValue* key) {
|
||||
TypedValue* result = nullptr;
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
@@ -589,16 +586,16 @@ arrayRefShuffle(ArrayData* oldData, ArrayData* newData, TypedValue* base) {
|
||||
}
|
||||
|
||||
inline ArrayData* SetElemArrayRawKey(ArrayData* a,
|
||||
int64_t key,
|
||||
Cell* value,
|
||||
bool copy) {
|
||||
int64_t key,
|
||||
Cell* value,
|
||||
bool copy) {
|
||||
return a->set(key, tvCellAsCVarRef(value), copy);
|
||||
}
|
||||
|
||||
inline ArrayData* SetElemArrayRawKey(ArrayData* a,
|
||||
StringData* key,
|
||||
Cell* value,
|
||||
bool copy) {
|
||||
StringData* key,
|
||||
Cell* value,
|
||||
bool copy) {
|
||||
int64_t n;
|
||||
if (key->isStrictlyInteger(n)) {
|
||||
return a->set(n, tvCellAsCVarRef(value), copy);
|
||||
@@ -609,7 +606,7 @@ inline ArrayData* SetElemArrayRawKey(ArrayData* a,
|
||||
|
||||
template <bool setResult, KeyType keyType>
|
||||
inline void SetElemArray(TypedValue* base, TypedValue* key,
|
||||
Cell* value) {
|
||||
Cell* value) {
|
||||
ArrayData* a = base->m_data.parr;
|
||||
ArrayData* newData = a;
|
||||
bool copy = (a->getCount() > 1)
|
||||
@@ -849,7 +846,7 @@ inline void SetNewElem(TypedValue* base, Cell* value) {
|
||||
}
|
||||
|
||||
inline TypedValue* SetOpElemEmptyish(unsigned char op, TypedValue* base,
|
||||
TypedValue* key, Cell* rhs) {
|
||||
TypedValue* key, Cell* rhs) {
|
||||
Array a = Array::Create();
|
||||
TypedValue* result = (TypedValue*)&a.lvalAt(tvAsCVarRef(key));
|
||||
tvAsVariant(base) = a;
|
||||
@@ -868,8 +865,8 @@ inline TypedValue* SetOpElemNumberish(TypedValue& tvScratch) {
|
||||
|
||||
template <KeyType keyType = KeyType::Any>
|
||||
inline TypedValue* SetOpElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue* key, Cell* rhs) {
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue* key, Cell* rhs) {
|
||||
TypedValue scratch;
|
||||
TypedValue* result;
|
||||
DataType type;
|
||||
@@ -930,7 +927,7 @@ inline TypedValue* SetOpElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
|
||||
inline TypedValue* SetOpNewElemEmptyish(unsigned char op,
|
||||
TypedValue* base, Cell* rhs) {
|
||||
TypedValue* base, Cell* rhs) {
|
||||
Array a = Array::Create();
|
||||
TypedValue* result = (TypedValue*)&a.lvalAt();
|
||||
tvAsVariant(base) = a;
|
||||
@@ -943,8 +940,8 @@ inline TypedValue* SetOpNewElemNumberish(TypedValue& tvScratch) {
|
||||
return &tvScratch;
|
||||
}
|
||||
inline TypedValue* SetOpNewElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
unsigned char op, TypedValue* base,
|
||||
Cell* rhs) {
|
||||
unsigned char op, TypedValue* base,
|
||||
Cell* rhs) {
|
||||
TypedValue* result;
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
@@ -1001,7 +998,7 @@ inline TypedValue* SetOpNewElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
|
||||
template <bool setResult>
|
||||
inline void IncDecBody(unsigned char op, TypedValue* fr,
|
||||
TypedValue* to) {
|
||||
TypedValue* to) {
|
||||
if (fr->m_type == KindOfInt64) {
|
||||
switch ((IncDecOp)op) {
|
||||
case PreInc: {
|
||||
@@ -1083,7 +1080,7 @@ inline void IncDecBody(unsigned char op, TypedValue* fr,
|
||||
|
||||
template <bool setResult>
|
||||
inline void IncDecElemEmptyish(unsigned char op, TypedValue* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
Array a = Array::Create();
|
||||
TypedValue* result = (TypedValue*)&a.lvalAt(tvAsCVarRef(key));
|
||||
tvAsVariant(base) = a;
|
||||
@@ -1102,8 +1099,8 @@ inline void IncDecElemNumberish(TypedValue& dest) {
|
||||
}
|
||||
template <bool setResult, KeyType keyType = KeyType::Any>
|
||||
inline void IncDecElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
TypedValue scratch;
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
@@ -1159,7 +1156,7 @@ inline void IncDecElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
|
||||
template <bool setResult>
|
||||
inline void IncDecNewElemEmptyish(unsigned char op, TypedValue* base,
|
||||
TypedValue& dest) {
|
||||
TypedValue& dest) {
|
||||
Array a = Array::Create();
|
||||
TypedValue* result = (TypedValue*)&a.lvalAt();
|
||||
tvAsVariant(base) = a;
|
||||
@@ -1174,8 +1171,8 @@ inline void IncDecNewElemNumberish(TypedValue& dest) {
|
||||
}
|
||||
template <bool setResult>
|
||||
inline void IncDecNewElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue& dest) {
|
||||
unsigned char op, TypedValue* base,
|
||||
TypedValue& dest) {
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
switch (type) {
|
||||
@@ -1226,12 +1223,12 @@ inline void IncDecNewElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
|
||||
inline ArrayData* UnsetElemArrayRawKey(ArrayData* a, int64_t key,
|
||||
bool copy) {
|
||||
bool copy) {
|
||||
return a->remove(key, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* UnsetElemArrayRawKey(ArrayData* a, StringData* key,
|
||||
bool copy) {
|
||||
bool copy) {
|
||||
int64_t n;
|
||||
if (!key->isStrictlyInteger(n)) {
|
||||
return a->remove(StrNR(key), copy);
|
||||
@@ -1303,19 +1300,19 @@ inline DataType propPreNull(TypedValue& tvScratch, TypedValue*& result) {
|
||||
}
|
||||
return KindOfNull;
|
||||
}
|
||||
inline Instance* createDefaultObject() {
|
||||
inline ObjectData* createDefaultObject() {
|
||||
raise_warning(Strings::CREATING_DEFAULT_OBJECT);
|
||||
Instance* obj = newInstance(SystemLib::s_stdclassClass);
|
||||
ObjectData* obj = newInstance(SystemLib::s_stdclassClass);
|
||||
return obj;
|
||||
}
|
||||
template <bool warn, bool define>
|
||||
inline DataType propPreStdclass(TypedValue& tvScratch,
|
||||
TypedValue*& result, TypedValue* base) {
|
||||
TypedValue*& result, TypedValue* base) {
|
||||
if (!define) {
|
||||
return propPreNull<warn>(tvScratch, result);
|
||||
}
|
||||
// TODO(#1124706): We don't want to do this anymore.
|
||||
Instance* obj = createDefaultObject();
|
||||
ObjectData* obj = createDefaultObject();
|
||||
tvRefcountedDecRef(base);
|
||||
base->m_type = KindOfObject;
|
||||
base->m_data.pobj = obj;
|
||||
@@ -1326,7 +1323,7 @@ inline DataType propPreStdclass(TypedValue& tvScratch,
|
||||
|
||||
template <bool warn, bool define, bool issetEmpty>
|
||||
inline DataType propPre(TypedValue& tvScratch, TypedValue*& result,
|
||||
TypedValue*& base) {
|
||||
TypedValue*& base) {
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
switch (type) {
|
||||
@@ -1378,9 +1375,9 @@ inline TypedValue* Prop(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
assert(!warn || !unset);
|
||||
TypedValue* result = nullptr;
|
||||
StringData* keySD = nullptr;
|
||||
Instance* instance;
|
||||
ObjectData* instance;
|
||||
if (baseIsObj) {
|
||||
instance = reinterpret_cast<Instance*>(base);
|
||||
instance = reinterpret_cast<ObjectData*>(base);
|
||||
} else {
|
||||
DataType t = propPre<warn, define, false>(tvScratch, result, base);
|
||||
if (t == KindOfNull) {
|
||||
@@ -1404,7 +1401,7 @@ inline TypedValue* Prop(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
|
||||
template<bool useEmpty>
|
||||
inline bool IssetEmptyElemObj(TypedValue& tvRef, Instance* instance,
|
||||
inline bool IssetEmptyElemObj(TypedValue& tvRef, ObjectData* instance,
|
||||
TypedValue* key) {
|
||||
if (useEmpty) {
|
||||
if (LIKELY(instance->isCollection())) {
|
||||
@@ -1423,13 +1420,12 @@ inline bool IssetEmptyElemObj(TypedValue& tvRef, Instance* instance,
|
||||
|
||||
template <bool useEmpty, bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
TypedValue* base,
|
||||
TypedValue* key) {
|
||||
TypedValue* base, TypedValue* key) {
|
||||
TypedValue scratch;
|
||||
if (isObj) {
|
||||
initScratchKey<keyType>(scratch, key);
|
||||
return IssetEmptyElemObj<useEmpty>(
|
||||
tvRef, reinterpret_cast<Instance*>(base), key);
|
||||
tvRef, reinterpret_cast<ObjectData*>(base), key);
|
||||
}
|
||||
|
||||
TypedValue* result;
|
||||
@@ -1461,8 +1457,7 @@ inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
case KindOfObject: {
|
||||
initScratchKey<keyType>(scratch, key);
|
||||
return IssetEmptyElemObj<useEmpty>(
|
||||
tvRef, static_cast<Instance*>(base->m_data.pobj), key);
|
||||
return IssetEmptyElemObj<useEmpty>(tvRef, base->m_data.pobj, key);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1478,8 +1473,8 @@ inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
|
||||
template <bool useEmpty, KeyType keyType>
|
||||
inline bool IssetEmptyPropObj(Class* ctx, Instance* instance,
|
||||
TypedValue* key) {
|
||||
inline bool IssetEmptyPropObj(Class* ctx, ObjectData* instance,
|
||||
TypedValue* key) {
|
||||
StringData* keySD;
|
||||
bool issetEmptyResult;
|
||||
keySD = prepareKey<keyType>(key);
|
||||
@@ -1491,11 +1486,10 @@ inline bool IssetEmptyPropObj(Class* ctx, Instance* instance,
|
||||
}
|
||||
|
||||
template <bool useEmpty, bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline bool IssetEmptyProp(Class* ctx, TypedValue* base,
|
||||
TypedValue* key) {
|
||||
inline bool IssetEmptyProp(Class* ctx, TypedValue* base, TypedValue* key) {
|
||||
if (isObj) {
|
||||
return IssetEmptyPropObj<useEmpty, keyType>(
|
||||
ctx, reinterpret_cast<Instance*>(base), key);
|
||||
ctx, reinterpret_cast<ObjectData*>(base), key);
|
||||
}
|
||||
|
||||
TypedValue tvScratch;
|
||||
@@ -1523,8 +1517,8 @@ inline void SetPropNull(Cell* val) {
|
||||
}
|
||||
}
|
||||
inline void SetPropStdclass(TypedValue* base, TypedValue* key,
|
||||
Cell* val) {
|
||||
Instance* obj = createDefaultObject();
|
||||
Cell* val) {
|
||||
ObjectData* obj = createDefaultObject();
|
||||
obj->incRefCount();
|
||||
StringData* keySD = prepareKey(key);
|
||||
obj->setProp(nullptr, keySD, (TypedValue*)val);
|
||||
@@ -1535,8 +1529,8 @@ inline void SetPropStdclass(TypedValue* base, TypedValue* key,
|
||||
}
|
||||
|
||||
template <KeyType keyType>
|
||||
inline void SetPropObj(Class* ctx, Instance* instance,
|
||||
TypedValue* key, Cell* val) {
|
||||
inline void SetPropObj(Class* ctx, ObjectData* instance,
|
||||
TypedValue* key, Cell* val) {
|
||||
StringData* keySD = prepareKey<keyType>(key);
|
||||
// Set property.
|
||||
instance->setProp(ctx, keySD, val);
|
||||
@@ -1545,11 +1539,9 @@ inline void SetPropObj(Class* ctx, Instance* instance,
|
||||
|
||||
// $base->$key = $val
|
||||
template <bool setResult, bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline void SetProp(Class* ctx, TypedValue* base, TypedValue* key,
|
||||
Cell* val) {
|
||||
inline void SetProp(Class* ctx, TypedValue* base, TypedValue* key, Cell* val) {
|
||||
if (isObj) {
|
||||
SetPropObj<keyType>(ctx, reinterpret_cast<Instance*>(base),
|
||||
key, val);
|
||||
SetPropObj<keyType>(ctx, reinterpret_cast<ObjectData*>(base), key, val);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1583,8 +1575,7 @@ inline void SetProp(Class* ctx, TypedValue* base, TypedValue* key,
|
||||
break;
|
||||
}
|
||||
case KindOfObject: {
|
||||
SetPropObj<keyType>(ctx, static_cast<Instance*>(base->m_data.pobj),
|
||||
key, val);
|
||||
SetPropObj<keyType>(ctx, base->m_data.pobj, key, val);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1600,9 +1591,9 @@ inline TypedValue* SetOpPropNull(TypedValue& tvScratch) {
|
||||
return &tvScratch;
|
||||
}
|
||||
inline TypedValue* SetOpPropStdclass(TypedValue& tvRef, unsigned char op,
|
||||
TypedValue* base, TypedValue* key,
|
||||
Cell* rhs) {
|
||||
Instance* obj = createDefaultObject();
|
||||
TypedValue* base, TypedValue* key,
|
||||
Cell* rhs) {
|
||||
ObjectData* obj = createDefaultObject();
|
||||
obj->incRefCount();
|
||||
tvRefcountedDecRef(base);
|
||||
base->m_type = KindOfObject;
|
||||
@@ -1618,8 +1609,8 @@ inline TypedValue* SetOpPropStdclass(TypedValue& tvRef, unsigned char op,
|
||||
|
||||
template <KeyType keyType>
|
||||
inline TypedValue* SetOpPropObj(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, Instance* instance,
|
||||
TypedValue* key, Cell* rhs) {
|
||||
unsigned char op, ObjectData* instance,
|
||||
TypedValue* key, Cell* rhs) {
|
||||
StringData* keySD = prepareKey<keyType>(key);
|
||||
TypedValue* result = instance->setOpProp(tvRef, ctx, op, keySD, rhs);
|
||||
releaseKey<keyType>(keySD);
|
||||
@@ -1629,13 +1620,14 @@ inline TypedValue* SetOpPropObj(TypedValue& tvRef, Class* ctx,
|
||||
// $base->$key <op>= $rhs
|
||||
template<bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline TypedValue* SetOpProp(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
Class* ctx, unsigned char op,
|
||||
TypedValue* base, TypedValue* key,
|
||||
Cell* rhs) {
|
||||
Class* ctx, unsigned char op,
|
||||
TypedValue* base, TypedValue* key,
|
||||
Cell* rhs) {
|
||||
TypedValue scratch;
|
||||
if (isObj) {
|
||||
return SetOpPropObj<keyType>(tvRef, ctx, op,
|
||||
reinterpret_cast<Instance*>(base), key, rhs);
|
||||
reinterpret_cast<ObjectData*>(base),
|
||||
key, rhs);
|
||||
}
|
||||
|
||||
TypedValue* result;
|
||||
@@ -1689,8 +1681,8 @@ inline void IncDecPropNull(TypedValue& dest) {
|
||||
}
|
||||
template <bool setResult>
|
||||
inline void IncDecPropStdclass(unsigned char op, TypedValue* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
Instance* obj = createDefaultObject();
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
ObjectData* obj = createDefaultObject();
|
||||
obj->incRefCount();
|
||||
tvRefcountedDecRef(base);
|
||||
base->m_type = KindOfObject;
|
||||
@@ -1717,8 +1709,8 @@ inline void IncDecPropStdclass(unsigned char op, TypedValue* base,
|
||||
|
||||
template <bool setResult, KeyType keyType>
|
||||
inline void IncDecPropObj(TypedValue& tvRef, Class* ctx,
|
||||
unsigned char op, Instance* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
unsigned char op, ObjectData* base,
|
||||
TypedValue* key, TypedValue& dest) {
|
||||
StringData* keySD = prepareKey<keyType>(key);
|
||||
base->incDecProp<setResult>(tvRef, ctx, op, keySD, dest);
|
||||
releaseKey<keyType>(keySD);
|
||||
@@ -1726,13 +1718,13 @@ inline void IncDecPropObj(TypedValue& tvRef, Class* ctx,
|
||||
|
||||
template <bool setResult, bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline void IncDecProp(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
Class* ctx, unsigned char op,
|
||||
TypedValue* base, TypedValue* key,
|
||||
TypedValue& dest) {
|
||||
Class* ctx, unsigned char op,
|
||||
TypedValue* base, TypedValue* key,
|
||||
TypedValue& dest) {
|
||||
TypedValue scratch;
|
||||
if (isObj) {
|
||||
IncDecPropObj<setResult, keyType>(tvRef, ctx, op,
|
||||
reinterpret_cast<Instance*>(base),
|
||||
reinterpret_cast<ObjectData*>(base),
|
||||
key, dest);
|
||||
return;
|
||||
}
|
||||
@@ -1778,9 +1770,8 @@ inline void IncDecProp(TypedValue& tvScratch, TypedValue& tvRef,
|
||||
}
|
||||
|
||||
template<bool isObj = false, KeyType keyType = KeyType::Any>
|
||||
inline void UnsetProp(Class* ctx, TypedValue* base,
|
||||
TypedValue* key) {
|
||||
Instance* instance;
|
||||
inline void UnsetProp(Class* ctx, TypedValue* base, TypedValue* key) {
|
||||
ObjectData* instance;
|
||||
if (!isObj) {
|
||||
DataType type;
|
||||
opPre(base, type);
|
||||
@@ -1791,7 +1782,7 @@ inline void UnsetProp(Class* ctx, TypedValue* base,
|
||||
}
|
||||
instance = instanceFromTv(base);
|
||||
} else {
|
||||
instance = reinterpret_cast<Instance*>(base);
|
||||
instance = reinterpret_cast<ObjectData*>(base);
|
||||
}
|
||||
// Prepare key.
|
||||
StringData* keySD = prepareKey<keyType>(key);
|
||||
|
||||
@@ -19,16 +19,16 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
// SmartAllocator (or, to be more specific, ObjectAllocator) is templatized by
|
||||
// the size of the chunks it allocates. This works fine when we're only
|
||||
// allocating objects of fixed sizes, known at compile time. However, the VM
|
||||
// class "Instance" is of variable size (having room for a property vector at
|
||||
// the end), and the range of sizes it will take on is unknowable at compile
|
||||
// time.
|
||||
// SmartAllocator (or, to be more specific, ObjectAllocator) is templatized
|
||||
// by the size of the chunks it allocates. This works fine when we're only
|
||||
// allocating objects of fixed sizes, known at compile time. However, the
|
||||
// ObjectData class is of variable size (having room for a property vector
|
||||
// at the end), and the range of sizes it will take on is unknowable at
|
||||
// compile time.
|
||||
//
|
||||
// To work around this, we instantiate the ObjectAllocator template with a size
|
||||
// from every possible size class. This way, any size class that Instance might
|
||||
// end up falling into will have an ObjectAllocator.
|
||||
// from every possible size class. This way, any size class that ObjectData
|
||||
// might end up falling into will have an ObjectAllocator.
|
||||
int InitializeAllocators();
|
||||
|
||||
}
|
||||
|
||||
@@ -182,10 +182,10 @@ Unit* build_native_class_unit(const HhbcExtClassInfo* builtinClasses,
|
||||
|
||||
HphpArray* pack_args_into_array(ActRec* ar, int nargs);
|
||||
|
||||
inline Instance*
|
||||
inline ObjectData*
|
||||
newInstance(Class* cls) {
|
||||
assert(cls);
|
||||
auto* inst = Instance::newInstance(cls);
|
||||
auto* inst = ObjectData::newInstance(cls);
|
||||
if (UNLIKELY(RuntimeOption::EnableObjDestructCall)) {
|
||||
g_vmContext->m_liveBCObjs.insert(inst);
|
||||
}
|
||||
|
||||
@@ -190,16 +190,6 @@
|
||||
],
|
||||
"args": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "__clone",
|
||||
"return": {
|
||||
"type": "Variant"
|
||||
},
|
||||
"flags": [
|
||||
],
|
||||
"args": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"consts": [
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ALLOC_OBJECT_STUB_RETURN(name) \
|
||||
HPHP::Instance::newInstance(SystemLib::s_##name##Class)
|
||||
ObjectData::newInstance(SystemLib::s_##name##Class)
|
||||
|
||||
#define ALLOC_OBJECT_STUB(name) \
|
||||
ObjectData* SystemLib::Alloc##name##Object() { \
|
||||
@@ -45,16 +45,16 @@ SYSTEMLIB_CLASSES(DEFINE_SYSTEMLIB_CLASS)
|
||||
#undef DEFINE_SYSTEMLIB_CLASS
|
||||
|
||||
ObjectData* SystemLib::AllocStdClassObject() {
|
||||
return HPHP::Instance::newInstance(SystemLib::s_stdclassClass);
|
||||
return ObjectData::newInstance(SystemLib::s_stdclassClass);
|
||||
}
|
||||
|
||||
ObjectData* SystemLib::AllocPinitSentinel() {
|
||||
return HPHP::Instance::newInstance(SystemLib::s_pinitSentinelClass);
|
||||
return ObjectData::newInstance(SystemLib::s_pinitSentinelClass);
|
||||
}
|
||||
|
||||
#define CREATE_AND_CONSTRUCT(clsname, params) \
|
||||
HPHP::Instance* inst = \
|
||||
HPHP::Instance::newInstance(SystemLib::s_##clsname##Class); \
|
||||
ObjectData* inst = \
|
||||
ObjectData::newInstance(SystemLib::s_##clsname##Class); \
|
||||
TypedValue ret; \
|
||||
{ \
|
||||
/* Increment refcount across call to ctor, so the object doesn't */ \
|
||||
|
||||
@@ -58,11 +58,11 @@ constexpr char* g_allIncludes = R"(
|
||||
void emitCtorHelper(const fbstring& className, std::ostream& out) {
|
||||
out << folly::format(
|
||||
R"(
|
||||
HPHP::Instance* new_{0:s}_Instance(HPHP::Class* cls) {{
|
||||
ObjectData* new_{0:s}_Instance(HPHP::Class* cls) {{
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t builtinPropSize = sizeof(c_{0:s}) - sizeof(ObjectData);
|
||||
size_t size = HPHP::Instance::sizeForNProps(nProps) + builtinPropSize;
|
||||
HPHP::Instance *inst = (HPHP::Instance*)ALLOCOBJSZ(size);
|
||||
size_t size = ObjectData::sizeForNProps(nProps) + builtinPropSize;
|
||||
ObjectData *inst = (ObjectData*)ALLOCOBJSZ(size);
|
||||
new ((void *)inst) c_{0:s}(cls);
|
||||
return inst;
|
||||
}})",
|
||||
|
||||
@@ -69,7 +69,7 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
for (auto const& klass : classes) {
|
||||
if (!(klass.flags() & IsCppAbstract)) {
|
||||
cpp << "Instance* new_" << klass.name() << "_Instance(Class*);\n";
|
||||
cpp << "ObjectData* new_" << klass.name() << "_Instance(Class*);\n";
|
||||
classesWithCtors.insert(klass.name());
|
||||
}
|
||||
for (auto const& func : klass.methods()) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário