/**
 * sp points to the last use variable on the stack.
 * returns the closure so that translator-x64 can just return "rax".
 */
c_Closure* c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) {
  static StringData* invokeName = StringData::GetStaticString("__invoke");
  Func* invokeFunc = getVMClass()->lookupMethod(invokeName);

  if (invokeFunc->attrs() & AttrStatic) {
    // Only set the class for static closures
    m_thisOrClass = (ObjectData*)(intptr_t(ar->m_func->cls()) | 1LL);
  } else {
    // I don't care if it is a $this or a late bound class because we will just
    // put it back in the same place on an ActRec.
    m_thisOrClass = ar->m_this;
    if (ar->hasThis()) {
      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 props to instance variables
  assert(m_cls->numDeclProperties() == numArgs);
  TypedValue* beforeCurUseVar = sp + numArgs;
  TypedValue* curProperty = propVec();
  for (int i = 0; i < numArgs; i++) {
    // teleport the references in here so we don't incref
    *curProperty++ = *--beforeCurUseVar;
  }
  return this;
}
Exemple #2
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++);
  }
}
Exemple #3
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 props to instance variables
  assert(m_cls->numDeclProperties() == numArgs);
  TypedValue* beforeCurUseVar = sp + numArgs;
  TypedValue* curProperty = propVec();
  for (int i = 0; i < numArgs; i++) {
    // teleport the references in here so we don't incref
    tvCopy(*--beforeCurUseVar, *curProperty++);
  }
}
Exemple #4
0
Array c_Closure::t___debuginfo() {
  Array ret = Array::Create();

  // Serialize 'use' parameters.
  if (auto propValues = propVec()) {
    Array use;

    auto propsInfo = getVMClass()->declProperties();
    for (size_t i = 0; i < getVMClass()->numDeclProperties(); ++i) {
      auto value = &propValues[i];
      use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value));
    }

    if (!use.empty()) {
      ret.set(s_static, use);
    }
  }

  auto const func = getInvokeFunc();

  // Serialize function parameters.
  if (func->numParams()) {
   Array params;

   for (int i = 0; i < func->numParams(); ++i) {
      auto str = String::attach(
        StringData::Make(s_varprefix.get(), func->localNames()[i])
      );

      bool optional = func->params()[i].phpCode;
      if (auto mi = func->methInfo()) {
        optional = optional || mi->parameters[i]->valueText;
      }

      params.set(str, optional ? s_optional : s_required);
    }

    ret.set(s_parameter, params);
  }

  // Serialize 'this' object.
  if (hasThis()) {
    ret.set(s_this, Object(getThis()));
  }

  return ret;
}
Exemple #5
0
Object APCObject::createObject() const {
  auto cls = m_cls.left();
  assert(cls != nullptr);

  auto obj = Object::attach(
    m_fast_init ? ObjectData::newInstanceNoPropInit(const_cast<Class*>(cls))
                : ObjectData::newInstance(const_cast<Class*>(cls))
  );

  auto const numProps = cls->numDeclProperties();
  auto const objProp = obj->propVec();
  auto const apcProp = persistentProps();

  if (m_fast_init) {
    // re-entry is possible while we're executing toLocal() on each
    // property, so heap inspectors may see partially initid objects
    // not yet exposed to PHP.
    unsigned i = 0;
    try {
      for (; i < numProps; ++i) {
        new (objProp + i) Variant(apcProp[i]->toLocal());
      }
    } catch (...) {
      for (; i < numProps; ++i) {
        new (objProp + i) Variant();
      }
      throw;
    }
  } else {
    for (unsigned i = 0; i < numProps; ++i) {
      tvAsVariant(&objProp[i]) = apcProp[i]->toLocal();
    }
  }

  if (UNLIKELY(numProps < m_propCount)) {
    auto dynProps = apcProp[numProps];
    assert(dynProps->kind() == APCKind::StaticArray ||
           dynProps->kind() == APCKind::UncountedArray ||
           dynProps->kind() == APCKind::SharedArray);
    obj->setDynPropArray(dynProps->toLocal().asCArrRef());
  }

  if (!m_no_wakeup) obj->invokeWakeup();
  return obj;
}
Exemple #6
0
Object APCObject::createObject() const {
  auto cls = m_cls.left();
  assert(cls != nullptr);

  auto obj = Object::attach(
    m_fast_init ? ObjectData::newInstanceNoPropInit(const_cast<Class*>(cls))
                : ObjectData::newInstance(const_cast<Class*>(cls))
  );

  auto const numProps = cls->numDeclProperties();
  auto const objProp = obj->propVec();
  auto const apcProp = persistentProps();

  if (m_fast_init) {
    unsigned i = 0;
    try {
      while (i < numProps) {
        new (objProp + i) Variant(apcProp[i]->toLocal());
        ++i;
      }
    } catch (...) {
      while (i < numProps) {
        new (objProp + i) Variant();
        ++i;
      }
      throw;
    }
  } else {
    for (unsigned i = 0; i < numProps; ++i) {
      tvAsVariant(&objProp[i]) = apcProp[i]->toLocal();
    }
  }

  if (UNLIKELY(numProps < m_propCount)) {
    auto dynProps = apcProp[numProps];
    assert(dynProps->kind() == APCKind::StaticArray ||
           dynProps->kind() == APCKind::UncountedArray ||
           dynProps->kind() == APCKind::SharedArray);
    obj->setDynPropArray(dynProps->toLocal().asCArrRef());
  }

  if (!m_no_wakeup) obj->invokeWakeup();
  return obj;
}