Esempio n. 1
0
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++);
  }
}
Esempio n. 2
0
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++);
  }
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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);
}
Esempio n. 14
0
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);
}
Esempio n. 15
0
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;
  }
}
Esempio n. 16
0
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();
}