Esempio n. 1
0
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const {
  bool isGenerated = isdigit(name->data()[0]) ||
    ParserBase::IsClosureName(name->toCppString());

  Attr attrs = this->attrs;
  if (preClass && preClass->attrs() & AttrInterface) {
    attrs |= AttrAbstract;
  }
  if (attrs & AttrPersistent &&
      ((RuntimeOption::EvalJitEnableRenameFunction && !isGenerated) ||
       (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) ||
       attrs & AttrInterceptable)) {
    if (attrs & AttrBuiltin) {
      SystemLib::s_anyNonPersistentBuiltins = true;
    }
    attrs = Attr(attrs & ~AttrPersistent);
  }
  if (!RuntimeOption::RepoAuthoritative) {
    // In non-RepoAuthoritative mode, any function could get a VarEnv because
    // of evalPHPDebugger.
    attrs |= AttrMayUseVV;
  } else if (RuntimeOption::EvalJitEnableRenameFunction &&
      !name->empty() &&
      !Func::isSpecial(name) &&
      !isClosureBody) {
    // intercepted functions need to pass all args through
    // to the interceptee
    attrs |= AttrMayUseVV;
  }
  if (isVariadic()) { attrs |= AttrVariadicParam; }

  if (!containsCalls) { attrs |= AttrPhpLeafFn; }

  assert(!m_pce == !preClass);
  auto f = m_ue.newFunc(this, unit, name, attrs, params.size());

  f->m_isPreFunc = !!preClass;

  bool const needsExtendedSharedData =
    m_info ||
    m_builtinFuncPtr ||
    m_nativeFuncPtr ||
    (attrs & AttrNative) ||
    line2 - line1 >= Func::kSmallDeltaLimit ||
    past - base >= Func::kSmallDeltaLimit;

  f->m_shared.reset(
    needsExtendedSharedData
      ? new Func::ExtendedSharedData(preClass, base, past, line1, line2,
                                     top, docComment)
      : new Func::SharedData(preClass, base, past,
                             line1, line2, top, docComment)
  );

  f->init(params.size());

  if (auto const ex = f->extShared()) {
    ex->m_hasExtendedSharedData = true;
    ex->m_builtinFuncPtr = m_builtinFuncPtr;
    ex->m_nativeFuncPtr = m_nativeFuncPtr;
    ex->m_info = m_info;
    ex->m_line2 = line2;
    ex->m_past = past;
    ex->m_returnByValue = false;
  }

  std::vector<Func::ParamInfo> fParams;
  for (unsigned i = 0; i < params.size(); ++i) {
    Func::ParamInfo pi = params[i];
    if (pi.isVariadic()) {
      pi.builtinType = KindOfArray;
    }
    f->appendParam(params[i].byRef, pi, fParams);
  }

  f->shared()->m_returnType = returnType;
  f->shared()->m_localNames.create(m_localNames);
  f->shared()->m_numLocals = m_numLocals;
  f->shared()->m_numIterators = m_numIterators;
  f->m_maxStackCells = maxStackCells;
  f->shared()->m_staticVars = staticVars;
  f->shared()->m_ehtab = toFixed(ehtab);
  f->shared()->m_fpitab = fpitab;
  f->shared()->m_isClosureBody = isClosureBody;
  f->shared()->m_isAsync = isAsync;
  f->shared()->m_isGenerator = isGenerator;
  f->shared()->m_isPairGenerator = isPairGenerator;
  f->shared()->m_userAttributes = userAttributes;
  f->shared()->m_retTypeConstraint = retTypeConstraint;
  f->shared()->m_retUserType = retUserType;
  f->shared()->m_originalFilename = originalFilename;
  f->shared()->m_isGenerated = isGenerated;

  if (attrs & AttrNative) {
    auto const ex = f->extShared();

    auto const& info = Native::GetBuiltinFunction(
      name,
      m_pce ? m_pce->name() : nullptr,
      f->isStatic()
    );

    Attr dummy = AttrNone;
    auto nativeAttributes = parseNativeAttributes(dummy);
    Native::getFunctionPointers(
      info,
      nativeAttributes,
      ex->m_builtinFuncPtr,
      ex->m_nativeFuncPtr
    );

    if (ex->m_nativeFuncPtr &&
        !(nativeAttributes & Native::AttrZendCompat)) {
      if (info.sig.ret == Native::NativeSig::Type::MixedTV) {
        ex->m_returnByValue = true;
      }
      int extra =
        (attrs & AttrNumArgs ? 1 : 0) +
        (isMethod() ? 1 : 0);
      assert(info.sig.args.size() == params.size() + extra);
      for (auto i = params.size(); i--; ) {
        switch (info.sig.args[extra + i]) {
          case Native::NativeSig::Type::ObjectArg:
          case Native::NativeSig::Type::StringArg:
          case Native::NativeSig::Type::ArrayArg:
          case Native::NativeSig::Type::ResourceArg:
          case Native::NativeSig::Type::OutputArg:
          case Native::NativeSig::Type::MixedTV:
            fParams[i].nativeArg = true;
            break;
          default:
            break;
        }
      }
    }
  }

  f->finishedEmittingParams(fParams);
  return f;
}
Esempio n. 2
0
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const {
  bool isGenerated = isdigit(name->data()[0]) || needsStripInOut(name);

  Attr attrs = this->attrs;
  if (preClass && preClass->attrs() & AttrInterface) {
    attrs |= AttrAbstract;
  }
  if (!RuntimeOption::RepoAuthoritative) {
    if (RuntimeOption::EvalJitEnableRenameFunction) {
      attrs |= AttrInterceptable;
    } else {
      attrs = Attr(attrs & ~AttrInterceptable);
    }
  }
  if (attrs & AttrPersistent && !preClass) {
    if ((RuntimeOption::EvalJitEnableRenameFunction ||
         attrs & AttrInterceptable ||
         (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited))) {
      if (attrs & AttrBuiltin) {
        SystemLib::s_anyNonPersistentBuiltins = true;
      }
      attrs = Attr(attrs & ~AttrPersistent);
    }
  } else {
    assertx(preClass || !(attrs & AttrBuiltin));
  }
  if (!RuntimeOption::RepoAuthoritative) {
    // In non-RepoAuthoritative mode, any function could get a VarEnv because
    // of evalPHPDebugger.
    attrs |= AttrMayUseVV;
  } else if ((attrs & AttrInterceptable) &&
             !name->empty() &&
             !Func::isSpecial(name) &&
             !isClosureBody) {
    // intercepted functions need to pass all args through
    // to the interceptee
    attrs |= AttrMayUseVV;
  }
  if (isVariadic()) {
    attrs |= AttrVariadicParam;
    if (isVariadicByRef()) {
      attrs |= AttrVariadicByRef;
    }
  }

  assertx(!m_pce == !preClass);
  auto f = m_ue.newFunc(this, unit, name, attrs, params.size());

  f->m_isPreFunc = !!preClass;

  bool const needsExtendedSharedData =
    isNative ||
    line2 - line1 >= Func::kSmallDeltaLimit ||
    past - base >= Func::kSmallDeltaLimit ||
    m_numClsRefSlots > 3;

  f->m_shared.reset(
    needsExtendedSharedData
      ? new Func::ExtendedSharedData(preClass, base, past, line1, line2,
                                     top, !containsCalls, docComment)
      : new Func::SharedData(preClass, base, past,
                             line1, line2, top, !containsCalls, docComment)
  );

  f->init(params.size());

  if (auto const ex = f->extShared()) {
    ex->m_hasExtendedSharedData = true;
    ex->m_arFuncPtr = nullptr;
    ex->m_nativeFuncPtr = nullptr;
    ex->m_line2 = line2;
    ex->m_past = past;
    ex->m_returnByValue = false;
    ex->m_isMemoizeWrapper = false;
    ex->m_isMemoizeWrapperLSB = false;
    ex->m_actualNumClsRefSlots = m_numClsRefSlots;
  }

  std::vector<Func::ParamInfo> fParams;
  for (unsigned i = 0; i < params.size(); ++i) {
    Func::ParamInfo pi = params[i];
    if (pi.isVariadic()) {
      pi.builtinType = RuntimeOption::EvalHackArrDVArrs
        ? KindOfVec : KindOfArray;
    }
    f->appendParam(params[i].byRef, pi, fParams);
  }

  auto const originalFullName =
    (!originalFilename ||
     !RuntimeOption::RepoAuthoritative ||
     FileUtil::isAbsolutePath(originalFilename->slice())) ?
    originalFilename :
    makeStaticString(RuntimeOption::SourceRoot +
                     originalFilename->toCppString());

  f->shared()->m_localNames.create(m_localNames);
  f->shared()->m_numLocals = m_numLocals;
  f->shared()->m_numIterators = m_numIterators;
  f->m_maxStackCells = maxStackCells;
  f->shared()->m_staticVars = staticVars;
  f->shared()->m_ehtab = ehtab;
  f->shared()->m_fpitab = fpitab;
  f->shared()->m_isClosureBody = isClosureBody;
  f->shared()->m_isAsync = isAsync;
  f->shared()->m_isGenerator = isGenerator;
  f->shared()->m_isPairGenerator = isPairGenerator;
  f->shared()->m_userAttributes = userAttributes;
  f->shared()->m_retTypeConstraint = retTypeConstraint;
  f->shared()->m_retUserType = retUserType;
  f->shared()->m_originalFilename = originalFullName;
  f->shared()->m_isGenerated = isGenerated;
  f->shared()->m_repoReturnType = repoReturnType;
  f->shared()->m_repoAwaitedReturnType = repoAwaitedReturnType;
  f->shared()->m_isMemoizeWrapper = isMemoizeWrapper;
  f->shared()->m_isMemoizeWrapperLSB = isMemoizeWrapperLSB;
  f->shared()->m_numClsRefSlots = m_numClsRefSlots;

  if (isNative) {
    auto const ex = f->extShared();

    ex->m_hniReturnType = hniReturnType;

    auto const info = getNativeInfo();

    Attr dummy = AttrNone;
    auto nativeAttributes = parseNativeAttributes(dummy);
    Native::getFunctionPointers(
      info,
      nativeAttributes,
      ex->m_arFuncPtr,
      ex->m_nativeFuncPtr
    );
    ex->m_takesNumArgs = !!(nativeAttributes & Native::AttrTakesNumArgs);

    if (ex->m_nativeFuncPtr) {
      if (info.sig.ret == Native::NativeSig::Type::MixedTV) {
        ex->m_returnByValue = true;
      }
      int extra =
        (nativeAttributes & Native::AttrTakesNumArgs ? 1 : 0) +
        (isMethod() ? 1 : 0);
      assertx(info.sig.args.size() == params.size() + extra);
      for (auto i = params.size(); i--; ) {
        switch (info.sig.args[extra + i]) {
          case Native::NativeSig::Type::ObjectArg:
          case Native::NativeSig::Type::StringArg:
          case Native::NativeSig::Type::ArrayArg:
          case Native::NativeSig::Type::ResourceArg:
          case Native::NativeSig::Type::OutputArg:
          case Native::NativeSig::Type::MixedTV:
            fParams[i].nativeArg = true;
            break;
          default:
            break;
        }
      }
    }
  }

  f->finishedEmittingParams(fParams);
  return f;
}
Esempio n. 3
0
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const {
  bool isGenerated = isdigit(name->data()[0]) ||
    ParserBase::IsClosureName(name->toCppString());

  Attr attrs = this->attrs;
  if (preClass && preClass->attrs() & AttrInterface) {
    attrs |= AttrAbstract;
  }
  if (attrs & AttrPersistent &&
      ((RuntimeOption::EvalJitEnableRenameFunction && !isGenerated) ||
       (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) ||
       attrs & AttrInterceptable)) {
    if (attrs & AttrBuiltin) {
      SystemLib::s_anyNonPersistentBuiltins = true;
    }
    attrs = Attr(attrs & ~AttrPersistent);
  }
  if (!RuntimeOption::RepoAuthoritative) {
    // In non-RepoAuthoritative mode, any function could get a VarEnv because
    // of evalPHPDebugger.
    attrs |= AttrMayUseVV;
  } else if (RuntimeOption::EvalJitEnableRenameFunction &&
      !name->empty() &&
      !Func::isSpecial(name) &&
      !isClosureBody) {
    // intercepted functions need to pass all args through
    // to the interceptee
    attrs |= AttrMayUseVV;
  }
  if (isVariadic()) { attrs |= AttrVariadicParam; }

  if (!containsCalls) { attrs |= AttrPhpLeafFn; }

  assert(!m_pce == !preClass);
  auto f = m_ue.newFunc(this, unit, name, attrs, params.size());

  f->m_isPreFunc = !!preClass;

  bool const needsExtendedSharedData =
    m_info ||
    m_builtinFuncPtr ||
    m_nativeFuncPtr ||
    (attrs & AttrNative) ||
    line2 - line1 >= Func::kSmallDeltaLimit ||
    past - base >= Func::kSmallDeltaLimit;

  f->m_shared.reset(
    needsExtendedSharedData
      ? new Func::ExtendedSharedData(preClass, base, past, line1, line2,
                                     top, docComment)
      : new Func::SharedData(preClass, base, past,
                             line1, line2, top, docComment)
  );

  f->init(params.size());

  if (auto const ex = f->extShared()) {
    ex->m_hasExtendedSharedData = true;
    ex->m_builtinFuncPtr = m_builtinFuncPtr;
    ex->m_nativeFuncPtr = m_nativeFuncPtr;
    ex->m_info = m_info;
    ex->m_line2 = line2;
    ex->m_past = past;
  }

  std::vector<Func::ParamInfo> fParams;
  bool usesDoubles = false, variadic = false;
  for (unsigned i = 0; i < params.size(); ++i) {
    Func::ParamInfo pi = params[i];
    if (pi.builtinType == KindOfDouble) usesDoubles = true;
    if (pi.isVariadic()) variadic = true;
    f->appendParam(params[i].byRef, pi, fParams);
  }

  f->shared()->m_returnType = returnType;
  f->shared()->m_localNames.create(m_localNames);
  f->shared()->m_numLocals = m_numLocals;
  f->shared()->m_numIterators = m_numIterators;
  f->m_maxStackCells = maxStackCells;
  f->shared()->m_staticVars = staticVars;
  f->shared()->m_ehtab = toFixed(ehtab);
  f->shared()->m_fpitab = fpitab;
  f->shared()->m_isClosureBody = isClosureBody;
  f->shared()->m_isAsync = isAsync;
  f->shared()->m_isGenerator = isGenerator;
  f->shared()->m_isPairGenerator = isPairGenerator;
  f->shared()->m_userAttributes = userAttributes;
  f->shared()->m_retTypeConstraint = retTypeConstraint;
  f->shared()->m_retUserType = retUserType;
  f->shared()->m_originalFilename = originalFilename;
  f->shared()->m_isGenerated = isGenerated;

  f->finishedEmittingParams(fParams);

  if (attrs & AttrNative) {
    auto const ex = f->extShared();

    auto const& info = Native::GetBuiltinFunction(
      name,
      m_pce ? m_pce->name() : nullptr,
      f->isStatic()
    );

    auto const nif = info.ptr;
    if (nif) {
      Attr dummy = AttrNone;
      int nativeAttrs = parseNativeAttributes(dummy);
      if (nativeAttrs & Native::AttrZendCompat) {
        ex->m_nativeFuncPtr = nif;
        ex->m_builtinFuncPtr = zend_wrap_func;
      } else {
        if (parseNativeAttributes(dummy) & Native::AttrActRec) {
          ex->m_builtinFuncPtr = nif;
          ex->m_nativeFuncPtr = nullptr;
        } else {
          ex->m_nativeFuncPtr = nif;
          ex->m_builtinFuncPtr =
            Native::getWrapper(m_pce, usesDoubles, variadic);
        }
      }
    } else {
      ex->m_builtinFuncPtr = Native::unimplementedWrapper;
    }
  }

  return f;
}