void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const invokeFunc = getVMClass()->lookupMethod(s_uuinvoke.get()); m_ctx = ar->m_this; if (ar->hasThis()) { if (invokeFunc->isStatic()) { // Only set the class for static closures. setClass(ar->getThis()->getVMClass()); } else { ar->getThis()->incRefCount(); } } /* * Copy the use vars to instance variables, and initialize any * instance properties that are for static locals to KindOfUninit. */ auto const numDeclProperties = getVMClass()->numDeclProperties(); assert(numDeclProperties - numArgs == getInvokeFunc()->numStaticLocals()); TypedValue* beforeCurUseVar = sp + numArgs; TypedValue* curProperty = propVec(); int i = 0; assert(numArgs <= numDeclProperties); for (; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } for (; i < numDeclProperties; ++i) { tvWriteUninit(curProperty++); } }
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const cls = getVMClass(); auto const invokeFunc = getInvokeFunc(); if (invokeFunc->cls()) { setThisOrClass(ar->getThisOrClass()); if (invokeFunc->isStatic()) { if (!hasClass()) { setClass(getThisUnchecked()->getVMClass()); } } else if (!hasClass()) { getThisUnchecked()->incRefCount(); } } else { hdr()->ctx = nullptr; } /* * Copy the use vars to instance variables, and initialize any * instance properties that are for static locals to KindOfUninit. */ auto const numDeclProperties = cls->numDeclProperties(); assertx(numDeclProperties - numArgs == getInvokeFunc()->numStaticLocals()); auto beforeCurUseVar = sp + numArgs; auto curProperty = getUseVars(); int i = 0; assertx(numArgs <= numDeclProperties); for (; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } for (; i < numDeclProperties; ++i) { tvWriteUninit(*curProperty++); } }
bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, const Variant& offset, bool validate /* = true */) { auto exists = objOffsetExists(base, offset); // Unless we called ArrayObject::offsetExists, there's nothing more to do if (exists != OffsetExistsResult::IssetIfNonNull) { return (int)exists; } // For ArrayObject::offsetExists, we need to check the value at `offset`. // If it's null, then we return false. TypedValue tvResult; tvWriteUninit(&tvResult); // We can't call the offsetGet method on `base` because users aren't // expecting offsetGet to be called for `isset(...)` expressions, so call // the method on the base ArrayObject class. auto const method = SystemLib::s_ArrayObjectClass->lookupMethod(s_offsetGet.get()); assert(method != nullptr); g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1, offset.asCell()); auto const result = !IS_NULL_TYPE(tvResult.m_type); tvRefcountedDecRef(&tvResult); return result; }
void objOffsetUnset(ObjectData* base, const Variant& offset) { objArrayAccess(base); assert(!base->isCollection()); const Func* method = base->methodNamed(s_offsetUnset.get()); assert(method != nullptr); TypedValue tv; tvWriteUninit(&tv); g_context->invokeFuncFew(&tv, method, base, nullptr, 1, offset.asCell()); tvRefcountedDecRef(&tv); }
void objOffsetUnset(ObjectData* base, CVarRef offset) { objArrayAccess(base); static StringData* sd__offsetUnset = StringData::GetStaticString("offsetUnset"); assert(!base->isCollection()); const Func* method = base->methodNamed(sd__offsetUnset); assert(method != nullptr); TypedValue tv; tvWriteUninit(&tv); base->invokeUserMethod(&tv, method, CREATE_VECTOR1(offset)); tvRefcountedDecRef(&tv); }
void objOffsetUnset(ObjectData* base, CVarRef offset) { objArrayAccess(base); static StringData* sd__offsetUnset = makeStaticString("offsetUnset"); assert(!base->isCollection()); const Func* method = base->methodNamed(sd__offsetUnset); assert(method != nullptr); TypedValue tv; tvWriteUninit(&tv); g_vmContext->invokeFuncFew(&tv, method, base, nullptr, 1, offset.asCell()); tvRefcountedDecRef(&tv); }
static bool objOffsetExists(ObjectData* base, CVarRef offset) { objArrayAccess(base); TypedValue tvResult; tvWriteUninit(&tvResult); static StringData* sd__offsetExists = StringData::GetStaticString("offsetExists"); assert(!base->isCollection()); const Func* method = base->methodNamed(sd__offsetExists); assert(method != nullptr); base->invokeUserMethod(&tvResult, method, CREATE_VECTOR1(offset)); tvCastToBooleanInPlace(&tvResult); return bool(tvResult.m_data.num); }
void objOffsetUnset(TypedValue* base, CVarRef offset) { objArrayAccess(base); static StringData* sd__offsetUnset = StringData::GetStaticString("offsetUnset"); ObjectData* obj = base->m_data.pobj; Instance* instance = static_cast<Instance*>(obj); const Func* method = instance->methodNamed(sd__offsetUnset); ASSERT(method != NULL); TypedValue tv; tvWriteUninit(&tv); instance->invokeUserMethod(&tv, method, CREATE_VECTOR1(offset)); tvRefcountedDecRef(&tv); }
static bool objOffsetExists(ObjectData* base, CVarRef offset) { objArrayAccess(base); TypedValue tvResult; tvWriteUninit(&tvResult); static StringData* sd__offsetExists = makeStaticString("offsetExists"); assert(!base->isCollection()); const Func* method = base->methodNamed(sd__offsetExists); assert(method != nullptr); g_vmContext->invokeFuncFew(&tvResult, method, base, nullptr, 1, offset.asCell()); tvCastToBooleanInPlace(&tvResult); return bool(tvResult.m_data.num); }
bool objOffsetExists(TypedValue* base, CVarRef offset) { objArrayAccess(base); TypedValue tvResult; tvWriteUninit(&tvResult); static StringData* sd__offsetExists = StringData::GetStaticString("offsetExists"); ObjectData* obj = base->m_data.pobj; Instance* instance = static_cast<Instance*>(obj); const Func* method = instance->methodNamed(sd__offsetExists); ASSERT(method != NULL); instance->invokeUserMethod(&tvResult, method, CREATE_VECTOR1(offset)); tvCastToBooleanInPlace(&tvResult); return bool(tvResult.m_data.num); }
void objOffsetSet(ObjectData* base, const Variant& offset, TypedValue* val, bool validate /* = true */) { if (validate) { objArrayAccess(base); } assert(!base->isCollection()); const Func* method = base->methodNamed(s_offsetSet.get()); assert(method != nullptr); TypedValue tvResult; tvWriteUninit(&tvResult); TypedValue args[2] = { *offset.asCell(), *tvToCell(val) }; g_context->invokeFuncFew(&tvResult, method, base, nullptr, 2, args); tvRefcountedDecRef(&tvResult); }
static OffsetExistsResult objOffsetExists(ObjectData* base, const Variant& offset) { objArrayAccess(base); TypedValue tvResult; tvWriteUninit(&tvResult); assert(!base->isCollection()); const Func* method = base->methodNamed(s_offsetExists.get()); assert(method != nullptr); g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1, offset.asCell()); tvCastToBooleanInPlace(&tvResult); if (!tvResult.m_data.num) return OffsetExistsResult::DoesNotExist; return method->cls() == SystemLib::s_ArrayObjectClass ? OffsetExistsResult::IssetIfNonNull : OffsetExistsResult::DefinitelyExists; }
void objOffsetSet(ObjectData* base, CVarRef offset, TypedValue* val, bool validate /* = true */) { if (validate) { objArrayAccess(base); } static StringData* sd__offsetSet = StringData::GetStaticString("offsetSet"); assert(!base->isCollection()); const Func* method = base->methodNamed(sd__offsetSet); assert(method != nullptr); TypedValue tvResult; tvWriteUninit(&tvResult); base->invokeUserMethod(&tvResult, method, CREATE_VECTOR2(offset, tvAsCVarRef(val))); tvRefcountedDecRef(&tvResult); }
void objOffsetSet(TypedValue* base, CVarRef offset, TypedValue* val, bool validate /* = true */) { if (validate) { objArrayAccess(base); } static StringData* sd__offsetSet = StringData::GetStaticString("offsetSet"); ObjectData* obj = base->m_data.pobj; Instance* instance = static_cast<Instance*>(obj); const Func* method = instance->methodNamed(sd__offsetSet); ASSERT(method != NULL); TypedValue tvResult; tvWriteUninit(&tvResult); instance->invokeUserMethod(&tvResult, method, CREATE_VECTOR2(offset, tvAsCVarRef(val))); tvRefcountedDecRef(&tvResult); }
void RepoQuery::getTypedValue(int iCol, TypedValue& tv) { const void* blob; size_t size; getBlob(iCol, blob, size); tvWriteUninit(&tv); if (size > 0) { String s = String((const char*)blob, size, CopyString); Variant v = unserialize_from_string(s); if (v.isString()) { v = String(StringData::GetStaticString(v.asCStrRef().get())); } else if (v.isArray()) { v = Array(ArrayData::GetScalarArray(v.asCArrRef().get())); } else { // Serialized variants and objects shouldn't ever make it into the repo. assert(!IS_REFCOUNTED_TYPE(v.getType())); } tvAsVariant(&tv) = v; } }
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const invokeFunc = getVMClass()->lookupMethod(s_uuinvoke.get()); m_thisOrClass = ar->m_this; if (ar->hasThis()) { if (invokeFunc->attrs() & AttrStatic) { // Only set the class for static closures. m_thisOrClass = reinterpret_cast<ObjectData*>( reinterpret_cast<intptr_t>(ar->getThis()->getVMClass()) | 1LL ); } else { ar->getThis()->incRefCount(); } } // Change my __invoke's m_cls to be the same as my creator's Class* scope = ar->m_func->cls(); m_func = invokeFunc->cloneAndSetClass(scope); /* * Copy the use vars to instance variables, and initialize any * instance properties that are for static locals to KindOfUninit. */ auto const numDeclProperties = getVMClass()->numDeclProperties(); assert(numDeclProperties - numArgs == m_func->numStaticLocals()); TypedValue* beforeCurUseVar = sp + numArgs; TypedValue* curProperty = propVec(); int i = 0; assert(numArgs <= numDeclProperties); for (; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } for (; i < numDeclProperties; ++i) { tvWriteUninit(curProperty++); } }
PreClass* PreClassEmitter::create(Unit& unit) const { Attr attrs = m_attrs; if (attrs & AttrPersistent && !RuntimeOption::RepoAuthoritative && SystemLib::s_inited) { attrs = Attr(attrs & ~AttrPersistent); } auto pc = folly::make_unique<PreClass>( &unit, m_line1, m_line2, m_offset, m_name, attrs, m_parent, m_docComment, m_id, m_hoistable); pc->m_instanceCtor = m_instanceCtor; pc->m_instanceDtor = m_instanceDtor; pc->m_builtinObjSize = m_builtinObjSize; pc->m_builtinODOffset = m_builtinODOffset; pc->m_interfaces = m_interfaces; pc->m_usedTraits = m_usedTraits; pc->m_requirements = m_requirements; pc->m_traitPrecRules = m_traitPrecRules; pc->m_traitAliasRules = m_traitAliasRules; pc->m_enumBaseTy = m_enumBaseTy; pc->m_numDeclMethods = m_numDeclMethods; pc->m_ifaceVtableSlot = m_ifaceVtableSlot; // Set user attributes. [&] { pc->m_userAttributes = m_userAttributes; pc->m_nativeDataInfo = nullptr; if (!m_userAttributes.size()) return; // Check for <<__NativeData("Type")>>. auto it = m_userAttributes.find(s_nativedata.get()); if (it == m_userAttributes.end()) return; TypedValue ndiInfo = it->second; if (ndiInfo.m_type != KindOfArray) return; // Use the first string label which references a registered type. In // practice, there should generally only be one item and it should be a // string, but maybe that'll be extended... for (ArrayIter it(ndiInfo.m_data.parr); it; ++it) { Variant val = it.second(); if (!val.isString()) continue; pc->m_nativeDataInfo = Native::getNativeDataInfo(val.toString().get()); if (pc->m_nativeDataInfo) break; } }(); PreClass::MethodMap::Builder methodBuild; for (MethodVec::const_iterator it = m_methods.begin(); it != m_methods.end(); ++it) { Func* f = (*it)->create(unit, pc.get()); methodBuild.add(f->name(), f); } pc->m_methods.create(methodBuild); PreClass::PropMap::Builder propBuild; for (unsigned i = 0; i < m_propMap.size(); ++i) { const Prop& prop = m_propMap[i]; propBuild.add(prop.name(), PreClass::Prop(pc.get(), prop.name(), prop.attrs(), prop.typeConstraint(), prop.docComment(), prop.val(), prop.repoAuthType())); } pc->m_properties.create(propBuild); PreClass::ConstMap::Builder constBuild; for (unsigned i = 0; i < m_constMap.size(); ++i) { const Const& const_ = m_constMap[i]; TypedValueAux tvaux; if (const_.isAbstract()) { tvWriteUninit(&tvaux); tvaux.constModifiers().m_isAbstract = true; } else { tvCopy(const_.val(), tvaux); tvaux.constModifiers().m_isAbstract = false; } tvaux.constModifiers().m_isType = const_.isTypeconst(); constBuild.add(const_.name(), PreClass::Const(const_.name(), tvaux, const_.phpCode())); } if (auto nativeConsts = Native::getClassConstants(m_name)) { for (auto cnsMap : *nativeConsts) { TypedValueAux tvaux; tvCopy(cnsMap.second, tvaux); tvaux.constModifiers() = { false, false }; constBuild.add(cnsMap.first, PreClass::Const(cnsMap.first, tvaux, staticEmptyString())); } } pc->m_constants.create(constBuild); return pc.release(); }