Esempio n. 1
0
/*
 * Helper for empty array -> packed transitions.  Creates an array
 * with one element.  The element is transferred into the array (should
 * already be incref'd).
 */
ALWAYS_INLINE
arr_lval EmptyArray::MakePackedInl(TypedValue tv) {
  auto const ad = static_cast<ArrayData*>(
    tl_heap->objMallocIndex(PackedArray::SmallSizeIndex)
  );
  ad->initHeader_16(
    HeaderKind::Packed,
    OneReference,
    PackedArray::packSizeIndexAndAuxBits(
      PackedArray::SmallSizeIndex,
      ArrayData::kNotDVArray
    )
  );
  ad->m_sizeAndPos = 1; // size=1, pos=0

  auto elem = PackedArray::LvalUncheckedInt(ad, 0);
  tvCopy(tv, elem);

  assertx(ad->kind() == ArrayData::kPackedKind);
  assertx(ad->dvArray() == ArrayData::kNotDVArray);
  assertx(ad->m_size == 1);
  assertx(ad->m_pos == 0);
  assertx(ad->hasExactlyOneRef());
  assertx(PackedArray::checkInvariants(ad));
  return arr_lval { ad, elem };
}
Esempio n. 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++);
  }
}
Esempio n. 3
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. 4
0
MixedArray* StructArray::ToMixed(StructArray* old) {
  auto const oldSize = old->size();
  auto const ad      = ToMixedHeader(oldSize + 1);
  auto const srcData = old->data();
  auto shape         = old->shape();

  memset(ad->hashTab(), static_cast<uint8_t>(MixedArray::Empty),
    sizeof(int32_t) * ad->hashSize());

  for (auto i = 0; i < oldSize; ++i) {
    auto key = const_cast<StringData*>(shape->keyForOffset(i));
    auto& e = ad->addKeyAndGetElem(key);
    tvCopy(srcData[i], e.data);
  }

  old->m_size = 0;
  ad->m_pos = old->m_pos;
  if (debug) {
    // For debug builds, set m_pos to 0 as well to make the
    // asserts in checkInvariants() happy.
    old->m_pos = 0;
  }
  assert(ad->checkInvariants());
  assert(!ad->isFull());
  assert(ad->hasExactlyOneRef());
  return ad;
}
Esempio n. 5
0
/*
 * Converts a packed array to mixed, leaving the packed array in an
 * empty state.  You need ToMixedCopy in cases where the old array
 * needs to remain un-modified (usually if `copy' is true).
 *
 * The returned array is mixed, and is guaranteed not to be isFull().
 * (Note: only unset can call ToMixed when we aren't about to insert.)
 */
MixedArray* PackedArray::ToMixed(ArrayData* old) {
  auto const oldSize = old->m_size;
  auto const ad      = ToMixedHeader(old, oldSize + 1);
  auto const mask    = ad->m_tableMask;
  auto dstData       = ad->data();
  auto dstHash       = ad->hashTab();
  auto const srcData = packedData(old);

  auto i = uint32_t{0};
  for (; i < oldSize; ++i) {
    dstData->setIntKey(i);
    tvCopy(srcData[i], dstData->data);
    *dstHash = i;
    ++dstData;
    ++dstHash;
  }
  for (; i <= mask; ++i) {
    *dstHash++ = MixedArray::Empty;
  }

  old->m_size = 0;

  assert(ad->checkInvariants());
  assert(!ad->isFull());
  return ad;
}
int SocketSet::wait( timeval *tv )
{
    //assert( _blockmain ); // can't call wait if we haven't ordered the feature (?)
    if (_blockmain_pending == 0) {
        int ret;
        do {
            if (tv == NULL) {
                ret = private_select( NULL );
            } else {
                timeval tvCopy( *tv );                 //select resets timeval.
                ret = private_select( &tvCopy );
            }
        } while (ret == 1);
        return ret;
    } else {
#ifdef VSNET_DEBUG
        std::ostringstream ostr;
        for (int i = 0; i < _blockmain_pending; i++)
            if ( FD_ISSET( i, &_blockmain_set ) ) ostr<<" "<<i;
        COUT<<"something pending for sockets:"
            <<ostr.str()
            <<" ("<<_blockmain_pending<<")"<<endl;
#endif
        struct timeval zerotv;
        zerotv.tv_sec  = 0;
        zerotv.tv_usec = 0;
        return private_select( &zerotv );
    }
}
Esempio n. 7
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++);
  }
}
Esempio n. 8
0
static UBool enumCharNames_callback(CallCtx *ctx,
                                    UChar32 code, UCharNameChoice nameChoice,
                                    const char *name, int32_t length) {
  TypedValue args[3];
  args[0].m_type = args[1].m_type = KindOfInt64;
  args[0].m_data.num = code;
  args[1].m_data.num = nameChoice;

  Variant charName = String(name, length, CopyString);
  tvCopy(*charName.asTypedValue(), args[2]);

  Variant retval;
  g_context->invokeFuncFew(retval.asTypedValue(), *ctx, 3, args);
  return true;
}
Esempio n. 9
0
TypedValue* methodWrapper(ActRec* ar) {
  auto func = ar->m_func;
  auto numArgs = func->numParams();
  auto numNonDefault = ar->numArgs();
  bool isStatic = func->isStatic();
  assert(!func->hasVariadicCaptureParam());
  TypedValue* args = ((TypedValue*)ar) - 1;
  TypedValue rv;
  rv.m_type = KindOfNull;

  if (LIKELY(numNonDefault == numArgs) ||
      LIKELY(nativeWrapperCheckArgs(ar))) {
    if (coerceFCallArgs(args, numArgs, numNonDefault, func)) {

      // Prepend a context arg for methods
      // KindOfClass when it's being called statically Foo::bar()
      // KindOfObject when it's being called on an instance $foo->bar()
      TypedValue ctx;
      if (ar->hasThis()) {
        if (isStatic) {
          throw_instance_method_fatal(getInvokeName(ar)->data());
        }
        ctx.m_type = KindOfObject;
        ctx.m_data.pobj = ar->getThis();
      } else {
        if (!isStatic) {
          throw_instance_method_fatal(getInvokeName(ar)->data());
        }
        ctx.m_type = KindOfClass;
        ctx.m_data.pcls = const_cast<Class*>(ar->getClass());
      }

      callFunc(func, &ctx, args, numArgs, rv);
    } else if (func->attrs() & AttrParamCoerceModeFalse) {
      rv.m_type = KindOfBoolean;
      rv.m_data.num = 0;
    }
  }

  assert(rv.m_type != KindOfUninit);
  if (isStatic) {
    frame_free_locals_no_this_inl(ar, func->numLocals(), &rv);
  } else {
    frame_free_locals_inl(ar, func->numLocals(), &rv);
  }
  tvCopy(rv, ar->m_r);
  return &ar->m_r;
}
Esempio n. 10
0
void NameValueTable::detach(ActRec* fp) {
  assert(m_fp == fp);
  m_fp = nullptr;

  const auto func = fp->m_func;
  const Id numNames = func->numNamedLocals();
  TypedValue* loc = frame_local(fp, 0);

  for (Id i = 0; i < numNames; ++i, --loc) {
    assert(func->lookupVarId(func->localVarName(i)) == i);

    auto elm = findElm(func->localVarName(i));
    assert(elm && elm->m_tv.m_type == KindOfNamedLocal);
    tvCopy(*loc, elm->m_tv);
    tvDebugTrash(loc);
  }
}
Esempio n. 11
0
void c_ConditionWaitHandle::onUnblocked() {
  decRefObj(m_child);
  m_child = nullptr;

  // Unblocked after notification.
  if (LIKELY(isFinished())) {
    decRefObj(this);
    return;
  }

  auto parentChain = getParentChain();
  setState(STATE_FAILED);
  tvCopy(
    make_tv<KindOfObject>(getNotNotifiedException().detach()),
    m_resultOrException
  );
  parentChain.unblock();
  decRefObj(this);
}
Esempio n. 12
0
ArrayData* StructArray::MakeUncounted(ArrayData* array) {
  auto structArray = asStructArray(array);
  // We don't need to copy the full capacity, since the array won't
  // change once it's uncounted.
  auto size = structArray->size();
  StructArray* result = createUncounted(structArray->shape(), size);
  result->m_hdr.init(HeaderKind::Struct, UncountedValue);
  result->m_sizeAndPos = array->m_sizeAndPos;
  auto const srcData = structArray->data();
  auto const stop    = srcData + size;
  auto targetData    = result->data();
  for (auto ptr = srcData; ptr != stop; ++ptr, ++targetData) {
    auto srcVariant = MixedArray::CreateVarForUncountedArray(tvAsCVarRef(ptr));
    tvCopy(*srcVariant.asTypedValue(),
           *targetData);
  }
  assert(result->m_pos == structArray->m_pos);
  assert(result->isUncounted());
  return result;
}
Esempio n. 13
0
void NameValueTable::attach(ActRec* fp) {
  assert(m_fp == nullptr);
  m_fp = fp;

  const auto func = fp->m_func;
  const Id numNames = func->numNamedLocals();
  TypedValue* loc = frame_local(fp, 0);

  for (Id i = 0; i < numNames; ++i, --loc) {
    assert(func->lookupVarId(func->localVarName(i)) == i);

    auto elm = insert(func->localVarName(i));
    assert(elm);
    if (elm->m_tv.m_type != KindOfInvalid) {
      assert(elm->m_tv.m_type != KindOfNamedLocal);
      tvCopy(elm->m_tv, *loc);
    }

    elm->m_tv.m_type = KindOfNamedLocal;
    elm->m_tv.m_data.num = i;
  }
}
Esempio n. 14
0
TypedValue* functionWrapper(ActRec* ar) {
  auto func = ar->m_func;
  auto numArgs = func->numParams();
  auto numNonDefault = ar->numArgs();
  assert(!func->hasVariadicCaptureParam());
  TypedValue* args = ((TypedValue*)ar) - 1;
  TypedValue rv;
  rv.m_type = KindOfNull;

  if (LIKELY(numNonDefault == numArgs) ||
      LIKELY(nativeWrapperCheckArgs(ar))) {
    if (coerceFCallArgs(args, numArgs, numNonDefault, func)) {
      callFunc(func, nullptr, args, numArgs, rv);
    } else if (func->attrs() & AttrParamCoerceModeFalse) {
      rv.m_type = KindOfBoolean;
      rv.m_data.num = 0;
    }
  }

  assert(rv.m_type != KindOfUninit);
  frame_free_locals_no_this_inl(ar, func->numLocals(), &rv);
  tvCopy(rv, ar->m_r);
  return &ar->m_r;
}
Esempio n. 15
0
TypedValue* zend_wrap_func(ActRec* ar) {
  // Sync the translator state.
  // We need to do this before a native function calls into a C library
  // compiled with -fomit-frame-pointer with the intention of having it call
  // back. Normal HHVM extensions have the luxury of only when such a thing
  // will be attempted, but we have no way to know in advance.
  VMRegAnchor _;

  TSRMLS_FETCH();
  zend_ext_func native_func = reinterpret_cast<zend_ext_func>(ar->func()->nativeFuncPtr());

  // Using Variant so exceptions will decref them
  Variant return_value_var(Variant::NullInit{});
  auto const return_value = return_value_var.asTypedValue();
  tvBox(return_value);

  Variant this_ptr_var(Variant::NullInit{});
  auto const this_ptr = this_ptr_var.asTypedValue();
  tvBox(this_ptr);

  if (ar->func()->cls() && ar->hasThis()) {
    tvWriteObject(
      ar->getThis(),
      this_ptr->m_data.pref->tv()
    );
  }

  auto *return_value_ptr = &return_value->m_data.pref;

  // Clear any stored exception
  zend_clear_exception(TSRMLS_C);

  // Invoke the PHP extension function/method
  ZendExecutionStack::pushHHVMStack((void*)ar);
  try {
    native_func(
      ar->numArgs(),
      return_value->m_data.pref,
      return_value_ptr,
      this_ptr_var.isNull() ? nullptr : this_ptr->m_data.pref,
      1
      TSRMLS_CC
    );
  } catch (...) {
    zend_wrap_func_cleanup();
    throw;
  }
  zend_wrap_func_cleanup();

  // If an exception was caught, rethrow it
  ZendExceptionStore& exceptionStore = ZendExceptionStore::getInstance();
  if (!exceptionStore.empty()) {
    exceptionStore.rethrow();
  }

  // Take care of freeing the args, tearing down the ActRec, and moving the
  // return value to the right place.  Note that frame_free_locals expects to
  // be able to free return_value in the event of an exception, so we have to
  // take it out of our Variant /before/ calling that.
  TypedValue return_value_copy = *return_value;
  return_value->m_type = KindOfNull; // clear the Variant's copy
  frame_free_locals_inl(ar, ar->func()->numLocals(), &return_value_copy);
  if (ar->func()->isReturnRef()) {
    if (!return_value_copy.m_data.pref->isReferenced()) {
      tvUnbox(&return_value_copy);
    }
  } else {
    tvUnbox(&return_value_copy);
  }
  auto ret_slot = ar->retSlot();
  tvCopy(return_value_copy, *ret_slot);
  return ret_slot;
}
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();
}