void RuntimeOption::Load()

in hphp/runtime/base/runtime-option.cpp [1530:2973]


void RuntimeOption::Load(
  IniSetting::Map& ini, Hdf& config,
  const std::vector<std::string>& iniClis /* = std::vector<std::string>() */,
  const std::vector<std::string>& hdfClis /* = std::vector<std::string>() */,
  std::vector<std::string>* messages /* = nullptr */,
  std::string cmd /* = "" */) {

  // Intialize the memory manager here because various settings and
  // initializations that we do here need it
  tl_heap.getCheck();

  // Get the ini (-d) and hdf (-v) strings, which may override some
  // of options that were set from config files. We also do these
  // now so we can override Tier.*.[machine | tier | cpu] on the
  // command line, along with any fields within a Tier (e.g.,
  // CoreFileSize)
  for (auto& istr : iniClis) {
    Config::ParseIniString(istr, ini);
  }
  for (auto& hstr : hdfClis) {
    Config::ParseHdfString(hstr, config);
  }

  // See if there are any Tier-based overrides
  auto m = getTierOverwrites(ini, config);
  if (messages) *messages = std::move(m);

  // RelativeConfigs can be set by commandline flags and tier overwrites, they
  // may also contain tier overwrites. They are, however, only included once, so
  // relative configs may not specify other relative configs which must to be
  // loaded. If RelativeConfigs is modified while loading configs an error is
  // raised, but we defer doing so until the logger is initialized below. If a
  // relative config cannot be found it is silently skipped (this is to allow
  // configs to be conditionally applied to scripts based on their location). By
  // reading the "hhvm.relative_configs" ini setting at runtime it is possible
  // to determine which configs were actually loaded.
  std::string relConfigsError;
  Config::Bind(s_RelativeConfigs, ini, config, "RelativeConfigs");
  if (!cmd.empty() && !s_RelativeConfigs.empty()) {
    String strcmd(cmd, CopyString);
    Process::InitProcessStatics();
    auto const currentDir = Process::CurrentWorkingDirectory.data();
    std::vector<std::string> newConfigs;
    auto const original = s_RelativeConfigs;
    for (auto& str : original) {
      if (str.empty()) continue;

      std::string fullpath;
      auto const found = FileUtil::runRelative(
        str, strcmd, currentDir,
        [&] (const String& f) {
          if (access(f.data(), R_OK) == 0) {
            fullpath = f.toCppString();
            FTRACE_MOD(Trace::facts, 3, "Parsing {}\n", fullpath);
            Config::ParseConfigFile(fullpath, ini, config);
            return true;
          }
          return false;
        }
      );
      if (found) newConfigs.emplace_back(std::move(fullpath));
    }
    if (!newConfigs.empty()) {
      auto m2 = getTierOverwrites(ini, config);
      if (messages) *messages = std::move(m2);
      if (s_RelativeConfigs != original) {
        relConfigsError = folly::sformat(
          "RelativeConfigs node was modified while loading configs from [{}] "
          "to [{}]",
          folly::join(", ", original),
          folly::join(", ", s_RelativeConfigs)
        );
      }
    }
    s_RelativeConfigs.swap(newConfigs);
  } else {
    s_RelativeConfigs.clear();
  }

  // Then get the ini and hdf cli strings again, in case the tier overwrites
  // overrode any non-tier based command line option we set. The tier-based
  // command line overwrites will already have been set in the call above.
  // This extra call is for the other command line options that may have been
  // overridden by a tier, but shouldn't have been.
  for (auto& istr : iniClis) {
    Config::ParseIniString(istr, ini);
  }
  for (auto& hstr : hdfClis) {
    Config::ParseHdfString(hstr, config);
  }

  Config::Bind(PidFile, ini, config, "PidFile", "www.pid");
  Config::Bind(DeploymentId, ini, config, "DeploymentId");

  {
    static std::string deploymentIdOverride;
    Config::Bind(deploymentIdOverride, ini, config, "DeploymentIdOverride");
    if (!deploymentIdOverride.empty()) {
      RuntimeOption::DeploymentId = deploymentIdOverride;
    }
  }

  {
    // Config ID
    Config::Bind(ConfigId, ini, config, "ConfigId", 0);
    auto configIdCounter = ServiceData::createCounter("vm.config.id");
    configIdCounter->setValue(ConfigId);
  }

  {
    // Logging
    auto setLogLevel = [](const std::string& value) {
      // ini parsing treats "None" as ""
      if (value == "None" || value == "") {
        Logger::LogLevel = Logger::LogNone;
      } else if (value == "Error") {
        Logger::LogLevel = Logger::LogError;
      } else if (value == "Warning") {
        Logger::LogLevel = Logger::LogWarning;
      } else if (value == "Info") {
        Logger::LogLevel = Logger::LogInfo;
      } else if (value == "Verbose") {
        Logger::LogLevel = Logger::LogVerbose;
      } else {
        return false;
      }
      return true;
    };
    auto str = Config::GetString(ini, config, "Log.Level");
    if (!str.empty()) {
      setLogLevel(str);
    }
    IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                     "hhvm.log.level", IniSetting::SetAndGet<std::string>(
      setLogLevel,
      []() {
        switch (Logger::LogLevel) {
          case Logger::LogNone:
            return "None";
          case Logger::LogError:
            return "Error";
          case Logger::LogWarning:
            return "Warning";
          case Logger::LogInfo:
            return "Info";
          case Logger::LogVerbose:
            return "Verbose";
        }
        return "";
      }
    ));

    Config::Bind(Logger::UseLogFile, ini, config, "Log.UseLogFile", true);
    Config::Bind(LogFile, ini, config, "Log.File");
    Config::Bind(LogFileSymLink, ini, config, "Log.SymLink");
    Config::Bind(LogFilePeriodMultiplier, ini,
                 config, "Log.PeriodMultiplier", 0);
    if (Logger::UseLogFile && RuntimeOption::ServerExecutionMode()) {
      RuntimeOption::ErrorLogs[Logger::DEFAULT] =
        ErrorLogFileData(LogFile, LogFileSymLink, LogFilePeriodMultiplier);
    }
    if (Config::GetBool(ini, config, "Log.AlwaysPrintStackTraces")) {
      Logger::SetTheLogger(Logger::DEFAULT, new ExtendedLogger());
      ExtendedLogger::EnabledByDefault = true;
    }

    Config::Bind(Logger::LogHeader, ini, config, "Log.Header");
    Config::Bind(Logger::LogNativeStackTrace, ini, config,
                 "Log.NativeStackTrace", true);
    Config::Bind(Logger::UseSyslog, ini, config, "Log.UseSyslog", false);
    Config::Bind(Logger::UseRequestLog, ini, config, "Log.UseRequestLog",
                 false);
    Config::Bind(Logger::AlwaysEscapeLog, ini, config, "Log.AlwaysEscapeLog",
                 true);
    Config::Bind(Logger::UseCronolog, ini, config, "Log.UseCronolog", false);
    Config::Bind(Logger::MaxMessagesPerRequest, ini,
                 config, "Log.MaxMessagesPerRequest", -1);
    Config::Bind(LogFileFlusher::DropCacheChunkSize, ini,
                 config, "Log.DropCacheChunkSize", 1 << 20);
    Config::Bind(RuntimeOption::LogHeaderMangle, ini, config,
                 "Log.HeaderMangle", 0);
    Config::Bind(AlwaysLogUnhandledExceptions, ini,
                 config, "Log.AlwaysLogUnhandledExceptions",
                 true);
    Config::Bind(NoSilencer, ini, config, "Log.NoSilencer");
    Config::Bind(RuntimeErrorReportingLevel, ini,
                 config, "Log.RuntimeErrorReportingLevel",
                 static_cast<int>(ErrorMode::HPHP_ALL));
    Config::Bind(ForceErrorReportingLevel, ini,
                 config, "Log.ForceErrorReportingLevel", 0);
    Config::Bind(AccessLogDefaultFormat, ini, config,
                 "Log.AccessLogDefaultFormat", "%h %l %u %t \"%r\" %>s %b");

    auto parseLogs = [] (const Hdf &config, const IniSetting::Map& ini,
                         const std::string &name,
                         std::map<std::string, AccessLogFileData> &logs) {
      auto parse_logs_callback = [&] (const IniSetting::Map &ini_pl,
                                      const Hdf &hdf_pl,
                                      const std::string &ini_pl_key) {
        string logName = hdf_pl.exists() && !hdf_pl.isEmpty()
                       ? hdf_pl.getName()
                       : ini_pl_key;
        string fname = Config::GetString(ini_pl, hdf_pl, "File", "", false);
        if (!fname.empty()) {
          string symlink = Config::GetString(ini_pl, hdf_pl, "SymLink", "",
                                             false);
          string format = Config::GetString(ini_pl, hdf_pl, "Format",
                                            AccessLogDefaultFormat, false);
          auto periodMultiplier = Config::GetUInt16(ini_pl, hdf_pl,
                                                    "PeriodMultiplier",
                                                    0, false);
          logs[logName] = AccessLogFileData(fname, symlink,
                                            format, periodMultiplier);


        }
      };
      Config::Iterate(parse_logs_callback, ini, config, name);
    };

    parseLogs(config, ini, "Log.Access", AccessLogs);
    RPCLogs = AccessLogs;
    parseLogs(config, ini, "Log.RPC", RPCLogs);

    Config::Bind(AdminLogFormat, ini, config, "Log.AdminLog.Format",
                 "%h %t %s %U");
    Config::Bind(AdminLogFile, ini, config, "Log.AdminLog.File");
    Config::Bind(AdminLogSymLink, ini, config, "Log.AdminLog.SymLink");
  }
  {
    // Error Handling

    Config::Bind(ErrorUpgradeLevel, ini, config, "ErrorHandling.UpgradeLevel",
                 0);
    Config::Bind(MaxSerializedStringSize, ini,
                 config, "ErrorHandling.MaxSerializedStringSize",
                 64 * 1024 * 1024);
    Config::Bind(CallUserHandlerOnFatals, ini,
                 config, "ErrorHandling.CallUserHandlerOnFatals", false);
    Config::Bind(ThrowExceptionOnBadMethodCall, ini,
                 config, "ErrorHandling.ThrowExceptionOnBadMethodCall", true);
    Config::Bind(LogNativeStackOnOOM, ini,
                 config, "ErrorHandling.LogNativeStackOnOOM", false);
    Config::Bind(NoticeFrequency, ini, config, "ErrorHandling.NoticeFrequency",
                 1);
    Config::Bind(WarningFrequency, ini, config,
                 "ErrorHandling.WarningFrequency", 1);
  }

  // If we generated errors while loading RelativeConfigs report those now that
  // error reporting is initialized
  if (!relConfigsError.empty()) Logger::Error(relConfigsError);

  {
    if (Config::GetInt64(ini, config, "ResourceLimit.CoreFileSizeOverride")) {
      setResourceLimit(RLIMIT_CORE, ini,  config,
                       "ResourceLimit.CoreFileSizeOverride");
    } else {
      setResourceLimit(RLIMIT_CORE, ini, config, "ResourceLimit.CoreFileSize");
    }
    setResourceLimit(RLIMIT_NOFILE, ini, config, "ResourceLimit.MaxSocket");
    setResourceLimit(RLIMIT_DATA, ini, config, "ResourceLimit.RSS");
    // These don't have RuntimeOption::xxx bindings, but we still want to be
    // able to use ini_xxx functionality on them; so directly bind to a local
    // static via Config::Bind.
    static int64_t s_core_file_size_override, s_core_file_size, s_rss = 0;
    static int32_t s_max_socket = 0;
    Config::Bind(s_core_file_size_override, ini, config,
                 "ResourceLimit.CoreFileSizeOverride", 0);
    Config::Bind(s_core_file_size, ini, config, "ResourceLimit.CoreFileSize",
                 0);
    Config::Bind(s_max_socket, ini, config, "ResourceLimit.MaxSocket", 0);
    Config::Bind(s_rss, ini, config, "ResourceLimit.RSS", 0);

    Config::Bind(SocketDefaultTimeout, ini, config,
                 "ResourceLimit.SocketDefaultTimeout", 60);
    Config::Bind(MaxSQLRowCount, ini, config, "ResourceLimit.MaxSQLRowCount",
                 0);
    Config::Bind(SerializationSizeLimit, ini, config,
                 "ResourceLimit.SerializationSizeLimit", StringData::MaxSize);
    Config::Bind(HeapSizeMB, ini, config, "ResourceLimit.HeapSizeMB",
                 HeapSizeMB);
    Config::Bind(HeapResetCountBase, ini, config,
                 "ResourceLimit.HeapResetCountBase", HeapResetCountBase);
    Config::Bind(HeapResetCountMultiple, ini, config,
                 "ResourceLimit.HeapResetCountMultiple",
                 HeapResetCountMultiple);
    Config::Bind(HeapLowWaterMark , ini, config,
                 "ResourceLimit.HeapLowWaterMark", HeapLowWaterMark);
    Config::Bind(HeapHighWaterMark , ini, config,
                 "ResourceLimit.HeapHighWaterMark",HeapHighWaterMark);
  }
  {
    // watchman
    Config::Bind(WatchmanRootSocket, ini, config, "watchman.socket.root", "");
    Config::Bind(WatchmanDefaultSocket, ini, config,
                 "watchman.socket.default", "");
  }
  {
    // PHPisms
    Config::Bind(DisableCallUserFunc, ini, config,
                 "Hack.Lang.Phpism.DisableCallUserFunc",
                 DisableCallUserFunc);
    Config::Bind(DisableCallUserFuncArray, ini, config,
                 "Hack.Lang.Phpism.DisableCallUserFuncArray",
                 DisableCallUserFuncArray);
    Config::Bind(DisableConstant, ini, config,
                 "Hack.Lang.Phpism.DisableConstant",
                 DisableConstant);
  }
  {
    // Repo
    auto repoModeToStr = [](RepoMode mode) {
      switch (mode) {
        case RepoMode::Closed:
          return "--";
        case RepoMode::ReadOnly:
          return "r-";
        case RepoMode::ReadWrite:
          return "rw";
      }

      always_assert(false);
      return "";
    };

    auto parseRepoMode = [&](const std::string& repoModeStr, const char* type, RepoMode defaultMode) {
      if (repoModeStr.empty()) {
        return defaultMode;
      }
      if (repoModeStr == "--") {
        return RepoMode::Closed;
      }
      if (repoModeStr == "r-") {
        return RepoMode::ReadOnly;
      }
      if (repoModeStr == "rw") {
        return RepoMode::ReadWrite;
      }

      Logger::Error("Bad config setting: Repo.%s.Mode=%s",
                    type, repoModeStr.c_str());
      return RepoMode::ReadWrite;
    };

    // Local Repo
    static std::string repoLocalMode;
    Config::Bind(repoLocalMode, ini, config, "Repo.Local.Mode", repoModeToStr(RepoLocalMode));
    RepoLocalMode = parseRepoMode(repoLocalMode, "Local", RepoMode::ReadOnly);

    // Repo.Path
    Config::Bind(RepoPath, ini, config, "Repo.Path", RepoPath);

    // Repo.Local.Path
    Config::Bind(RepoLocalPath, ini, config, "Repo.Local.Path");
    if (RepoLocalPath.empty()) {
      const char* HHVM_REPO_LOCAL_PATH = getenv("HHVM_REPO_LOCAL_PATH");
      if (HHVM_REPO_LOCAL_PATH != nullptr) {
        RepoLocalPath = HHVM_REPO_LOCAL_PATH;
      }
    }

    // Central Repo
    static std::string repoCentralMode;
    Config::Bind(repoCentralMode, ini, config, "Repo.Central.Mode", repoModeToStr(RepoCentralMode));
    RepoCentralMode = parseRepoMode(repoCentralMode, "Central", RepoMode::ReadWrite);

    // Repo.Central.Path
    Config::Bind(RepoCentralPath, ini, config, "Repo.Central.Path");
    Config::Bind(RepoCentralFileMode, ini, config, "Repo.Central.FileMode");
    Config::Bind(RepoCentralFileUser, ini, config, "Repo.Central.FileUser");
    Config::Bind(RepoCentralFileGroup, ini, config, "Repo.Central.FileGroup");

    Config::Bind(RepoAllowFallbackPath, ini, config, "Repo.AllowFallbackPath",
                 RepoAllowFallbackPath);

    replacePlaceholders(RepoLocalPath);
    replacePlaceholders(RepoCentralPath);
    replacePlaceholders(RepoPath);

    Config::Bind(RepoJournal, ini, config, "Repo.Journal", RepoJournal);
    Config::Bind(RepoCommit, ini, config, "Repo.Commit",
                 RepoCommit);
    Config::Bind(RepoDebugInfo, ini, config, "Repo.DebugInfo", RepoDebugInfo);
    Config::Bind(RepoLitstrLazyLoad, ini, config, "Repo.LitstrLazyLoad",
                 RepoLitstrLazyLoad);
    Config::Bind(RepoAuthoritative, ini, config, "Repo.Authoritative",
                 RepoAuthoritative);
    Config::Bind(RepoLocalReadaheadRate, ini, config,
                 "Repo.LocalReadaheadRate", 0);
    Config::Bind(RepoLocalReadaheadConcurrent, ini, config,
                 "Repo.LocalReadaheadConcurrent", false);
    Config::Bind(RepoBusyTimeoutMS, ini, config,
                 "Repo.BusyTimeoutMS", RepoBusyTimeoutMS);

    if (RepoPath.empty()) {
      if (!RepoLocalPath.empty()) {
        RepoPath = RepoLocalPath;
      } else if (!RepoCentralPath.empty()) {
        RepoPath = RepoCentralPath;
      } else if (auto const env = getenv("HHVM_REPO_CENTRAL_PATH")) {
        RepoPath = env;
        replacePlaceholders(RepoPath);
      } else {
        always_assert_flog(
          !RepoAuthoritative,
          "Either Repo.Path, Repo.LocalPath, or Repo.CentralPath "
          "must be set in RepoAuthoritative mode"
        );
      }
    }
  }

  if (use_jemalloc) {
    // HHProf
    Config::Bind(HHProfEnabled, ini, config, "HHProf.Enabled", false);
    Config::Bind(HHProfActive, ini, config, "HHProf.Active", false);
    Config::Bind(HHProfAccum, ini, config, "HHProf.Accum", false);
    Config::Bind(HHProfRequest, ini, config, "HHProf.Request", false);
  }
  {
    // Eval
    Config::Bind(EnableHipHopSyntax, ini, config, "Eval.EnableHipHopSyntax",
                 EnableHipHopSyntax);
    Config::Bind(EnableXHP, ini, config, "Eval.EnableXHP", EnableXHP);
    Config::Bind(TimeoutsUseWallTime, ini, config, "Eval.TimeoutsUseWallTime",
                 true);
    Config::Bind(CheckFlushOnUserClose, ini, config,
                 "Eval.CheckFlushOnUserClose", true);
    Config::Bind(EvalInitialNamedEntityTableSize, ini, config,
                 "Eval.InitialNamedEntityTableSize",
                 EvalInitialNamedEntityTableSize);
    Config::Bind(EvalInitialStaticStringTableSize, ini, config,
                 "Eval.InitialStaticStringTableSize",
                 EvalInitialStaticStringTableSize);

    static std::string jitSerdesMode;
    Config::Bind(jitSerdesMode, ini, config, "Eval.JitSerdesMode", "Off");

    EvalJitSerdesMode = [&] {
      #define X(x) if (jitSerdesMode == #x) return JitSerdesMode::x
      X(Serialize);
      X(SerializeAndExit);
      X(Deserialize);
      X(DeserializeOrFail);
      X(DeserializeOrGenerate);
      X(DeserializeAndDelete);
      X(DeserializeAndExit);
      #undef X
      return JitSerdesMode::Off;
    }();
    Config::Bind(EvalJitSerdesFile, ini, config,
                 "Eval.JitSerdesFile", EvalJitSerdesFile);
    replacePlaceholders(EvalJitSerdesFile);

    // DumpPreciseProfileData defaults to true only when we can possibly write
    // profile data to disk.  It can be set to false to avoid the performance
    // penalty of only running the interpreter during retranslateAll.  We will
    // assume that DumpPreciseProfileData implies (JitSerdesMode::Serialize ||
    // JitSerdesMode::SerializeAndExit), to avoid checking too many flags in a
    // few places.  The config file should never need to explicitly set
    // DumpPreciseProfileData to true.
    auto const couldDump = !EvalJitSerdesFile.empty() &&
      (isJitSerializing() ||
       (EvalJitSerdesMode == JitSerdesMode::DeserializeOrGenerate));
    Config::Bind(DumpPreciseProfData, ini, config,
                 "Eval.DumpPreciseProfData", couldDump);
    Config::Bind(ProfDataTTLHours, ini, config,
                 "Eval.ProfDataTTLHours", ProfDataTTLHours);
    Config::Bind(ProfDataTag, ini, config, "Eval.ProfDataTag", ProfDataTag);

    Config::Bind(CheckSymLink, ini, config, "Eval.CheckSymLink", true);
    Config::Bind(TrustAutoloaderPath, ini, config,
                 "Eval.TrustAutoloaderPath", false);

#define F(type, name, defaultVal) \
    Config::Bind(Eval ## name, ini, config, "Eval."#name, defaultVal);
    EVALFLAGS()
#undef F

    if (EvalJitSerdesModeForceOff) EvalJitSerdesMode = JitSerdesMode::Off;
    if (!EvalEnableReusableTC) EvalReusableTCPadding = 0;
    if (numa_num_nodes <= 1) {
      EvalEnableNuma = false;
    }

    Config::Bind(ServerForkEnabled, ini, config,
                 "Server.Forking.Enabled", ServerForkEnabled);
    Config::Bind(ServerForkLogging, ini, config,
                 "Server.Forking.LogForkAttempts", ServerForkLogging);
    if (!ServerForkEnabled && ServerExecutionMode()) {
      // Only use hugetlb pages when we don't fork().
      low_2m_pages(EvalMaxLowMemHugePages);
      high_2m_pages(EvalMaxHighArenaHugePages);
    }
#if USE_JEMALLOC_EXTENT_HOOKS
    g_useTHPUponHugeTLBFailure =
      Config::GetBool(ini, config, "Eval.UseTHPUponHugeTLBFailure",
                      g_useTHPUponHugeTLBFailure);
#endif
    s_enable_static_arena =
      Config::GetBool(ini, config, "Eval.UseTLStaticArena", true);

    replacePlaceholders(EvalEmbeddedDataExtractPath);
    replacePlaceholders(EvalEmbeddedDataFallbackPath);

    if (!jit::mcgen::retranslateAllEnabled()) {
      EvalJitWorkerThreads = 0;
      if (EvalJitSerdesMode != JitSerdesMode::Off) {
        if (ServerMode) {
          Logger::Warning("Eval.JitSerdesMode reset from " + jitSerdesMode +
                          " to off, becasue JitRetranslateAll isn't enabled.");
        }
        EvalJitSerdesMode = JitSerdesMode::Off;
      }
      EvalJitSerdesFile.clear();
      DumpPreciseProfData = false;
    }
    EvalJitPGOUseAddrCountedCheck &= addr_encodes_persistency;
    HardwareCounter::Init(EvalProfileHWEnable,
                          url_decode(EvalProfileHWEvents.data(),
                                     EvalProfileHWEvents.size()).toCppString(),
                          false,
                          EvalProfileHWExcludeKernel,
                          EvalProfileHWFastReads,
                          EvalProfileHWExportInterval);

    Config::Bind(EnableIntrinsicsExtension, ini,
                 config, "Eval.EnableIntrinsicsExtension",
                 EnableIntrinsicsExtension);
    Config::Bind(RecordCodeCoverage, ini, config, "Eval.RecordCodeCoverage");
    if (EvalJit && RecordCodeCoverage) {
      throw std::runtime_error("Code coverage is not supported with "
        "Eval.Jit=true");
    }
    Config::Bind(DisableSmallAllocator, ini, config,
                 "Eval.DisableSmallAllocator", DisableSmallAllocator);
    SetArenaSlabAllocBypass(DisableSmallAllocator);
    EvalSlabAllocAlign = folly::nextPowTwo(EvalSlabAllocAlign);
    EvalSlabAllocAlign = std::min(EvalSlabAllocAlign,
                                  decltype(EvalSlabAllocAlign){4096});

    if (RecordCodeCoverage) CheckSymLink = true;
    Config::Bind(CodeCoverageOutputFile, ini, config,
                 "Eval.CodeCoverageOutputFile");
    // NB: after we know the value of RepoAuthoritative.
    Config::Bind(EnableArgsInBacktraces, ini, config,
                 "Eval.EnableArgsInBacktraces", !RepoAuthoritative);
    Config::Bind(EvalAuthoritativeMode, ini, config, "Eval.AuthoritativeMode",
                 false);

    Config::Bind(CheckCLIClientCommands, ini, config, "Eval.CheckCLIClientCommands", 1);
    if (RepoAuthoritative) {
      EvalAuthoritativeMode = true;
    }
    {
      // Debugger (part of Eval)
      Config::Bind(EnableHphpdDebugger, ini, config,
                   "Eval.Debugger.EnableDebugger");
      Config::Bind(EnableVSDebugger, ini, config,
                   "Eval.Debugger.VSDebugEnable", EnableVSDebugger);
      Config::Bind(EnableDebuggerColor, ini, config,
                   "Eval.Debugger.EnableDebuggerColor", true);
      Config::Bind(EnableDebuggerPrompt, ini, config,
                   "Eval.Debugger.EnableDebuggerPrompt", true);
      Config::Bind(EnableDebuggerServer, ini, config,
                   "Eval.Debugger.EnableDebuggerServer");
      Config::Bind(EnableDebuggerUsageLog, ini, config,
                   "Eval.Debugger.EnableDebuggerUsageLog");
      Config::Bind(DebuggerServerIP, ini, config, "Eval.Debugger.IP");
      Config::Bind(DebuggerServerPort, ini, config, "Eval.Debugger.Port", 8089);
      Config::Bind(DebuggerDisableIPv6, ini, config,
                   "Eval.Debugger.DisableIPv6", false);
      Config::Bind(DebuggerDefaultSandboxPath, ini, config,
                   "Eval.Debugger.DefaultSandboxPath");
      Config::Bind(DebuggerStartupDocument, ini, config,
                   "Eval.Debugger.StartupDocument");
      Config::Bind(DebuggerSignalTimeout, ini, config,
                   "Eval.Debugger.SignalTimeout", 1);
      Config::Bind(DebuggerAuthTokenScriptBin, ini, config,
                   "Eval.Debugger.Auth.TokenScriptBin");
      Config::Bind(DebuggerSessionAuthScriptBin, ini, config,
                   "Eval.Debugger.Auth.SessionAuthScriptBin");
    }
  }
  {
    // CodeCache
    using jit::CodeCache;
    Config::Bind(CodeCache::ASize, ini, config, "Eval.JitASize", 60 << 20);
    Config::Bind(CodeCache::AColdSize, ini, config, "Eval.JitAColdSize",
                 24 << 20);
    Config::Bind(CodeCache::AFrozenSize, ini, config, "Eval.JitAFrozenSize",
                 40 << 20);
    Config::Bind(CodeCache::ABytecodeSize, ini, config,
                 "Eval.JitABytecodeSize", 0);
    Config::Bind(CodeCache::GlobalDataSize, ini, config,
                 "Eval.JitGlobalDataSize", CodeCache::ASize >> 2);

    Config::Bind(CodeCache::MapTCHuge, ini, config, "Eval.MapTCHuge",
                 hugePagesSoundNice());

    Config::Bind(CodeCache::TCNumHugeHotMB, ini, config,
                 "Eval.TCNumHugeHotMB", 64);
    Config::Bind(CodeCache::TCNumHugeMainMB, ini, config,
                 "Eval.TCNumHugeMainMB", 16);
    Config::Bind(CodeCache::TCNumHugeColdMB, ini, config,
                 "Eval.TCNumHugeColdMB", 4);

    Config::Bind(CodeCache::AutoTCShift, ini, config, "Eval.JitAutoTCShift", 1);
  }
  {
    // Hack Language
    Config::Bind(CheckIntOverflow, ini, config,
                 "Hack.Lang.CheckIntOverflow", 0);
    Config::Bind(StrictArrayFillKeys, ini, config,
                 "Hack.Lang.StrictArrayFillKeys", HackStrictOption::ON);

    Config::Bind(LookForTypechecker, ini, config,
                 "Hack.Lang.LookForTypechecker", false);

    // If you turn off LookForTypechecker, you probably want to turn this off
    // too -- basically, make the two look like the same option to external
    // users, unless you really explicitly want to set them differently for
    // some reason.
    Config::Bind(AutoTypecheck, ini, config, "Hack.Lang.AutoTypecheck",
                 LookForTypechecker);
    Config::Bind(EnableClassLevelWhereClauses, ini, config,
                 "Hack.Lang.EnableClassLevelWhereClauses",
                 false);
  }
  {
    // Options for PHP7 features which break BC. (Features which do not break
    // BC don't need options here and can just always be turned on.)
    //
    // NB that the "PHP7.all" option is intended to be only a master switch;
    // all runtime behavior gating should be based on sub-options (that's why
    // it's a file static not a static member of RuntimeOption). Also don't
    // forget to update mangleUnitPHP7Options if needed.
    //
    // TODO: we may eventually want to make an option which specifies
    // directories or filenames to exclude from PHP7 behavior, and so checking
    // these may want to be per-file. We originally planned to do this from the
    // get-go, but threading that through turns out to be kind of annoying and
    // of questionable value, so just doing this for now.
    Config::Bind(s_PHP7_master, ini, config, "PHP7.all", s_PHP7_default);
    Config::Bind(PHP7_EngineExceptions, ini, config, "PHP7.EngineExceptions",
                 s_PHP7_master);
    Config::Bind(PHP7_NoHexNumerics, ini, config, "PHP7.NoHexNumerics",
                 s_PHP7_master);
    Config::Bind(PHP7_Builtins, ini, config, "PHP7.Builtins", s_PHP7_master);
    Config::Bind(PHP7_Substr, ini, config, "PHP7.Substr",
                 s_PHP7_master);
    Config::Bind(PHP7_DisallowUnsafeCurlUploads, ini, config,
                 "PHP7.DisallowUnsafeCurlUploads", s_PHP7_master);
  }
  {
    // Server
    Config::Bind(Host, ini, config, "Server.Host");
    Config::Bind(DefaultServerNameSuffix, ini, config,
                 "Server.DefaultServerNameSuffix");
    Config::Bind(AlwaysDecodePostDataDefault, ini, config,
                 "Server.AlwaysDecodePostDataDefault",
                 AlwaysDecodePostDataDefault);
    Config::Bind(ServerType, ini, config, "Server.Type", ServerType);
    Config::Bind(ServerIP, ini, config, "Server.IP");
    Config::Bind(ServerFileSocket, ini, config, "Server.FileSocket");

#ifdef FACEBOOK
    //Do not cause slowness on startup -- except for Facebook
    if (GetServerPrimaryIPv4().empty() && GetServerPrimaryIPv6().empty()) {
      throw std::runtime_error("Unable to resolve the server's "
          "IPv4 or IPv6 address");
    }
#endif

    Config::Bind(ServerPort, ini, config, "Server.Port", 80);
    Config::Bind(ServerBacklog, ini, config, "Server.Backlog", 128);
    Config::Bind(ServerConnectionLimit, ini, config,
                 "Server.ConnectionLimit", 0);
    Config::Bind(ServerThreadCount, ini, config, "Server.ThreadCount",
                 Process::GetCPUCount() * 2);
    Config::Bind(ServerQueueCount, ini, config, "Server.QueueCount",
                 ServerThreadCount);
    Config::Bind(ServerIOThreadCount, ini, config,
                 "Server.IOThreadCount", 1);
    Config::Bind(ServerLegacyBehavior, ini, config, "Server.LegacyBehavior",
                 ServerLegacyBehavior);
    Config::Bind(ServerHugeThreadCount, ini, config,
                 "Server.HugeThreadCount", 0);
    Config::Bind(ServerHugeStackKb, ini, config, "Server.HugeStackSizeKb", 384);
    ServerSchedPolicy =
      Config::GetInt32(ini, config, "Server.SchedPolicy", ServerSchedPolicy);
    ServerSchedPriority =
      Config::GetInt32(ini, config, "Server.SchedPriority", ServerSchedPriority);
    Config::Bind(ServerLoopSampleRate, ini, config,
                 "Server.LoopSampleRate", 0);
    Config::Bind(ServerWarmupThrottleRequestCount, ini, config,
                 "Server.WarmupThrottleRequestCount",
                 ServerWarmupThrottleRequestCount);
    Config::Bind(ServerWarmupThrottleThreadCount, ini, config,
                 "Server.WarmupThrottleThreadCount",
                 Process::GetCPUCount());
    Config::Bind(ServerThreadDropCacheTimeoutSeconds, ini, config,
                 "Server.ThreadDropCacheTimeoutSeconds", 0);
    if (Config::GetBool(ini, config, "Server.ThreadJobLIFO")) {
      ServerThreadJobLIFOSwitchThreshold = 0;
    }
    Config::Bind(ServerThreadJobLIFOSwitchThreshold, ini, config,
                 "Server.ThreadJobLIFOSwitchThreshold",
                 ServerThreadJobLIFOSwitchThreshold);
    Config::Bind(ServerThreadJobMaxQueuingMilliSeconds, ini, config,
                 "Server.ThreadJobMaxQueuingMilliSeconds", -1);
    Config::Bind(ServerThreadDropStack, ini, config, "Server.ThreadDropStack");
    Config::Bind(ServerHttpSafeMode, ini, config, "Server.HttpSafeMode");
    Config::Bind(ServerStatCache, ini, config, "Server.StatCache", false);
    Config::Bind(ServerFixPathInfo, ini, config, "Server.FixPathInfo", false);
    Config::Bind(ServerAddVaryEncoding, ini, config, "Server.AddVaryEncoding",
                 ServerAddVaryEncoding);
    Config::Bind(ServerLogSettingsOnStartup, ini, config,
                 "Server.LogSettingsOnStartup", false);
    Config::Bind(ServerLogReorderProps, ini, config,
                 "Server.LogReorderProps", false);
    Config::Bind(ServerWarmupConcurrently, ini, config,
                 "Server.WarmupConcurrently", false);
    Config::Bind(ServerDedupeWarmupRequests, ini, config,
                 "Server.DedupeWarmupRequests", false);
    Config::Bind(ServerWarmupThreadCount, ini, config,
                 "Server.WarmupThreadCount", ServerWarmupThreadCount);
    Config::Bind(ServerExtendedWarmupThreadCount, ini, config,
                 "Server.ExtendedWarmup.ThreadCount",
                 ServerExtendedWarmupThreadCount);
    Config::Bind(ServerExtendedWarmupDelaySeconds, ini, config,
                 "Server.ExtendedWarmup.DelaySeconds",
                 ServerExtendedWarmupDelaySeconds);
    Config::Bind(ServerExtendedWarmupRepeat, ini, config,
                 "Server.ExtendedWarmup.Repeat", ServerExtendedWarmupRepeat);
    Config::Bind(ServerWarmupRequests, ini, config, "Server.WarmupRequests");
    Config::Bind(ServerExtendedWarmupRequests, ini, config,
                 "Server.ExtendedWarmup.Requests");
    Config::Bind(ServerCleanupRequest, ini, config, "Server.CleanupRequest");
    Config::Bind(ServerInternalWarmupThreads, ini, config,
                 "Server.InternalWarmupThreads", 0);  // 0 = skip
    Config::Bind(ServerHighPriorityEndPoints, ini, config,
                 "Server.HighPriorityEndPoints");
    Config::Bind(ServerExitOnBindFail, ini, config, "Server.ExitOnBindFail",
                 false);

    Config::Bind(RequestTimeoutSeconds, ini, config,
                 "Server.RequestTimeoutSeconds", 0);
    Config::Bind(MaxRequestAgeFactor, ini, config, "Server.MaxRequestAgeFactor",
                 0);
    Config::Bind(PspTimeoutSeconds, ini, config, "Server.PspTimeoutSeconds", 0);
    Config::Bind(PspCpuTimeoutSeconds, ini, config,
                 "Server.PspCpuTimeoutSeconds", 0);
    Config::Bind(RequestMemoryMaxBytes, ini, config,
                 "Server.RequestMemoryMaxBytes", (16LL << 30)); // 16GiB
    RequestInfo::setOOMKillThreshold(
      Config::GetUInt64(ini, config, "Server.RequestMemoryOOMKillBytes",
                        128ULL << 20));
    Config::Bind(RequestHugeMaxBytes, ini, config,
                 "Server.RequestHugeMaxBytes", (24LL << 20));
    Config::Bind(ServerGracefulShutdownWait, ini,
                 config, "Server.GracefulShutdownWait", 0);
    Config::Bind(ServerHarshShutdown, ini, config, "Server.HarshShutdown",
                 true);
    Config::Bind(ServerKillOnTimeout, ini, config, "Server.KillOnTimeout",
                 true);
    Config::Bind(ServerEvilShutdown, ini, config, "Server.EvilShutdown", true);
    Config::Bind(ServerPreShutdownWait, ini, config,
                 "Server.PreShutdownWait", 0);
    Config::Bind(ServerShutdownListenWait, ini, config,
                 "Server.ShutdownListenWait", 0);
    Config::Bind(ServerShutdownEOMWait, ini, config,
                 "Server.ShutdownEOMWait", 0);
    Config::Bind(ServerPrepareToStopTimeout, ini, config,
                 "Server.PrepareToStopTimeout", 240);
    Config::Bind(ServerPartialPostStatusCode, ini, config,
                 "Server.PartialPostStatusCode", -1);
    Config::Bind(StopOldServer, ini, config, "Server.StopOld", false);
    Config::Bind(OldServerWait, ini, config, "Server.StopOldWait", 30);
    Config::Bind(ServerRSSNeededMb, ini, config, "Server.RSSNeededMb", 4096);
    Config::Bind(ServerCriticalFreeMb, ini, config,
                 "Server.CriticalFreeMb", 512);
    Config::Bind(CacheFreeFactor, ini, config, "Server.CacheFreeFactor", 50);
    if (CacheFreeFactor > 100) CacheFreeFactor = 100;
    if (CacheFreeFactor < 0) CacheFreeFactor = 0;

    Config::Bind(ServerNextProtocols, ini, config, "Server.SSLNextProtocols");
    Config::Bind(ServerEnableH2C, ini, config, "Server.EnableH2C");
    extern bool g_brotliUseLocalArena;
    Config::Bind(g_brotliUseLocalArena, ini, config,
                 "Server.BrotliUseLocalArena", g_brotliUseLocalArena);
    Config::Bind(BrotliCompressionEnabled, ini, config,
                 "Server.BrotliCompressionEnabled", -1);
    Config::Bind(BrotliChunkedCompressionEnabled, ini, config,
                 "Server.BrotliChunkedCompressionEnabled", -1);
    Config::Bind(BrotliCompressionLgWindowSize, ini, config,
                 "Server.BrotliCompressionLgWindowSize", 20);
    Config::Bind(BrotliCompressionMode, ini, config,
                 "Server.BrotliCompressionMode", 0);
    Config::Bind(BrotliCompressionQuality, ini, config,
                 "Server.BrotliCompressionQuality", 6);
    Config::Bind(ZstdCompressionEnabled, ini, config,
                 "Server.ZstdCompressionEnabled", -1);
    Config::Bind(ZstdCompressor::s_useLocalArena, ini, config,
                 "Server.ZstdUseLocalArena", ZstdCompressor::s_useLocalArena);
    Config::Bind(ZstdCompressionLevel, ini, config,
                 "Server.ZstdCompressionLevel", 3);
    Config::Bind(ZstdChecksumRate, ini, config,
                "Server.ZstdChecksumRate", 0);
    Config::Bind(GzipCompressionLevel, ini, config,
                 "Server.GzipCompressionLevel", 3);
    Config::Bind(GzipMaxCompressionLevel, ini, config,
                 "Server.GzipMaxCompressionLevel", 9);
    Config::Bind(GzipCompressor::s_useLocalArena, ini, config,
                 "Server.GzipUseLocalArena", GzipCompressor::s_useLocalArena);
    Config::Bind(EnableKeepAlive, ini, config, "Server.EnableKeepAlive", true);
    Config::Bind(ExposeHPHP, ini, config, "Server.ExposeHPHP", true);
    Config::Bind(ExposeXFBServer, ini, config, "Server.ExposeXFBServer", false);
    Config::Bind(ExposeXFBDebug, ini, config, "Server.ExposeXFBDebug", false);
    Config::Bind(XFBDebugSSLKey, ini, config, "Server.XFBDebugSSLKey", "");
    Config::Bind(ConnectionTimeoutSeconds, ini, config,
                 "Server.ConnectionTimeoutSeconds", -1);
    Config::Bind(EnableOutputBuffering, ini, config,
                 "Server.EnableOutputBuffering");
    Config::Bind(OutputHandler, ini, config, "Server.OutputHandler");
    Config::Bind(ImplicitFlush, ini, config, "Server.ImplicitFlush");
    Config::Bind(EnableEarlyFlush, ini, config, "Server.EnableEarlyFlush",
                 true);
    Config::Bind(ForceChunkedEncoding, ini, config,
                 "Server.ForceChunkedEncoding");
    Config::Bind(MaxPostSize, ini, config, "Server.MaxPostSize", 100);
    MaxPostSize <<= 20;
    Config::Bind(AlwaysPopulateRawPostData, ini, config,
                 "Server.AlwaysPopulateRawPostData", false);
    Config::Bind(TakeoverFilename, ini, config, "Server.TakeoverFilename");
    Config::Bind(ExpiresActive, ini, config, "Server.ExpiresActive", true);
    Config::Bind(ExpiresDefault, ini, config, "Server.ExpiresDefault", 2592000);
    if (ExpiresDefault < 0) ExpiresDefault = 2592000;
    Config::Bind(DefaultCharsetName, ini, config, "Server.DefaultCharsetName",
                 "");
    Config::Bind(RequestBodyReadLimit, ini, config,
                 "Server.RequestBodyReadLimit", -1);
    Config::Bind(EnableSSL, ini, config, "Server.EnableSSL");
    Config::Bind(SSLPort, ini, config, "Server.SSLPort", 443);
    Config::Bind(SSLCertificateFile, ini, config, "Server.SSLCertificateFile");
    Config::Bind(SSLCertificateKeyFile, ini, config,
                 "Server.SSLCertificateKeyFile");
    Config::Bind(SSLCertificateDir, ini, config, "Server.SSLCertificateDir");
    Config::Bind(SSLTicketSeedFile, ini, config, "Server.SSLTicketSeedFile");
    Config::Bind(TLSDisableTLS1_2, ini, config, "Server.TLSDisableTLS1_2",
                 false);
    Config::Bind(TLSClientCipherSpec, ini, config,
                 "Server.TLSClientCipherSpec");
    Config::Bind(EnableSSLWithPlainText, ini, config,
                 "Server.EnableSSLWithPlainText");
    Config::Bind(SSLClientAuthLevel, ini, config,
                 "Server.SSLClientAuthLevel", 0);
    if (SSLClientAuthLevel < 0) SSLClientAuthLevel = 0;
    if (SSLClientAuthLevel > 2) SSLClientAuthLevel = 2;
    Config::Bind(SSLClientCAFile, ini, config, "Server.SSLClientCAFile", "");
    if (!SSLClientAuthLevel) {
      SSLClientCAFile = "";
    } else if (SSLClientCAFile.empty()) {
      throw std::runtime_error(
          "SSLClientCAFile is required to enable client auth");
    }

    Config::Bind(ClientAuthAclIdentity, ini, config,
                 "Server.ClientAuthAclIdentity", "");
    Config::Bind(ClientAuthAclAction, ini, config,
                 "Server.ClientAuthAclAction", "");
    Config::Bind(ClientAuthFailClose, ini, config,
                 "Server.ClientAuthFailClose", false);

    Config::Bind(ClientAuthLogSampleBase, ini, config,
                 "Server.ClientAuthLogSampleBase", 100);
    if (ClientAuthLogSampleBase < 1) {
      ClientAuthLogSampleBase = 1;
    }

    Config::Bind(SSLClientAuthLoggingSampleRatio, ini, config,
                 "Server.SSLClientAuthLoggingSampleRatio", 0);
    if (SSLClientAuthLoggingSampleRatio < 0) {
      SSLClientAuthLoggingSampleRatio = 0;
    }
    if (SSLClientAuthLoggingSampleRatio > ClientAuthLogSampleBase) {
      SSLClientAuthLoggingSampleRatio = ClientAuthLogSampleBase;
    }

    Config::Bind(ClientAuthSuccessLogSampleRatio, ini, config,
                 "Server.ClientAuthSuccessLogSampleRatio", 0);
    if (ClientAuthSuccessLogSampleRatio <
          SSLClientAuthLoggingSampleRatio) {
      ClientAuthSuccessLogSampleRatio = SSLClientAuthLoggingSampleRatio;
    }
    if (ClientAuthSuccessLogSampleRatio > ClientAuthLogSampleBase) {
      ClientAuthSuccessLogSampleRatio = ClientAuthLogSampleBase;
    }

    Config::Bind(ClientAuthFailureLogSampleRatio, ini, config,
                 "Server.ClientAuthFailureLogSampleRatio", 0);
    if (ClientAuthFailureLogSampleRatio <
          SSLClientAuthLoggingSampleRatio) {
      ClientAuthFailureLogSampleRatio = SSLClientAuthLoggingSampleRatio;
    }
    if (ClientAuthFailureLogSampleRatio > ClientAuthLogSampleBase) {
      ClientAuthFailureLogSampleRatio = ClientAuthLogSampleBase;
    }

    // SourceRoot has been default to: Process::GetCurrentDirectory() + '/'
    auto defSourceRoot = SourceRoot;
    Config::Bind(SourceRoot, ini, config, "Server.SourceRoot", SourceRoot);
    SourceRoot = FileUtil::normalizeDir(SourceRoot);
    if (SourceRoot.empty()) {
      SourceRoot = defSourceRoot;
    }
    FileCache::SourceRoot = SourceRoot;

    Config::Bind(IncludeSearchPaths, ini, config, "Server.IncludeSearchPaths");
    for (unsigned int i = 0; i < IncludeSearchPaths.size(); i++) {
      IncludeSearchPaths[i] = FileUtil::normalizeDir(IncludeSearchPaths[i]);
    }
    IncludeSearchPaths.insert(IncludeSearchPaths.begin(), ".");

    Config::Bind(AutoloadEnabled, ini, config, "Autoload.Enabled", false);
    Config::Bind(AutoloadDBPath, ini, config, "Autoload.DB.Path");
    Config::Bind(AutoloadDBPerms, ini, config, "Autoload.DB.Perms", "0644");
    Config::Bind(AutoloadDBGroup, ini, config, "Autoload.DB.Group");
    Config::Bind(AutoloadLogging, ini, config, "Autoload.Logging",
      "hphp.runtime.ext.facts:=CRITICAL:slog;slog=hhvm");
    Config::Bind(AutoloadExcludedRepos, ini, config, "Autoload.ExcludedRepos");
    Config::Bind(AutoloadLoggingAllowPropagation, ini, config,
                 "Autoload.AllowLoggingPropagation", false);
    Config::Bind(AutoloadRethrowExceptions, ini, config,
                 "Autoload.RethrowExceptions", true);

    Config::Bind(FileCache, ini, config, "Server.FileCache");
    Config::Bind(DefaultDocument, ini, config, "Server.DefaultDocument",
                 "index.php");
    Config::Bind(GlobalDocument, ini, config, "Server.GlobalDocument");
    Config::Bind(ErrorDocument404, ini, config, "Server.ErrorDocument404");
    normalizePath(ErrorDocument404);
    Config::Bind(ForbiddenAs404, ini, config, "Server.ForbiddenAs404");
    Config::Bind(ErrorDocument500, ini, config, "Server.ErrorDocument500");
    normalizePath(ErrorDocument500);
    Config::Bind(FatalErrorMessage, ini, config, "Server.FatalErrorMessage");
    FontPath = FileUtil::normalizeDir(
      Config::GetString(ini, config, "Server.FontPath"));
    Config::Bind(EnableStaticContentFromDisk, ini, config,
                 "Server.EnableStaticContentFromDisk", true);
    Config::Bind(EnableOnDemandUncompress, ini, config,
                 "Server.EnableOnDemandUncompress", true);
    Config::Bind(EnableStaticContentMMap, ini, config,
                 "Server.EnableStaticContentMMap", true);
    if (EnableStaticContentMMap) {
      EnableOnDemandUncompress = true;
    }
    Config::Bind(Utf8izeReplace, ini, config, "Server.Utf8izeReplace", true);

    Config::Bind(RequestInitFunction, ini, config,
                 "Server.RequestInitFunction");
    Config::Bind(RequestInitDocument, ini, config,
                 "Server.RequestInitDocument");
    Config::Bind(SafeFileAccess, ini, config, "Server.SafeFileAccess");
    Config::Bind(AllowedDirectories, ini, config, "Server.AllowedDirectories");
    Config::Bind(WhitelistExec, ini, config, "Server.WhitelistExec");
    Config::Bind(WhitelistExecWarningOnly, ini, config,
                 "Server.WhitelistExecWarningOnly");
    Config::Bind(AllowedExecCmds, ini, config, "Server.AllowedExecCmds");
    Config::Bind(UnserializationWhitelistCheck, ini, config,
                 "Server.UnserializationWhitelistCheck", false);
    Config::Bind(UnserializationWhitelistCheckWarningOnly, ini, config,
                 "Server.UnserializationWhitelistCheckWarningOnly", true);
    Config::Bind(UnserializationBigMapThreshold, ini, config,
                 "Server.UnserializationBigMapThreshold", 1 << 16);
    Config::Bind(AllowedFiles, ini, config, "Server.AllowedFiles");
    Config::Bind(ForbiddenFileExtensions, ini, config,
                 "Server.ForbiddenFileExtensions");
    Config::Bind(LockCodeMemory, ini, config, "Server.LockCodeMemory", false);
    Config::Bind(MaxArrayChain, ini, config, "Server.MaxArrayChain", INT_MAX);
    if (MaxArrayChain != INT_MAX) {
      // VanillaDict needs a higher threshold to avoid false-positives.
      // (and we always use VanillaDict)
      MaxArrayChain *= 2;
    }

    Config::Bind(WarnOnCollectionToArray, ini, config,
                 "Server.WarnOnCollectionToArray", false);
    Config::Bind(UseDirectCopy, ini, config, "Server.UseDirectCopy", false);
    Config::Bind(AlwaysUseRelativePath, ini, config,
                 "Server.AlwaysUseRelativePath", false);
    {
      // Server Upload
      Config::Bind(UploadMaxFileSize, ini, config,
                   "Server.Upload.UploadMaxFileSize", 100);
      UploadMaxFileSize <<= 20;
      Config::Bind(UploadTmpDir, ini, config, "Server.Upload.UploadTmpDir",
                   "/tmp");
      Config::Bind(EnableFileUploads, ini, config,
                   "Server.Upload.EnableFileUploads", true);
      Config::Bind(MaxFileUploads, ini, config, "Server.Upload.MaxFileUploads",
                   20);
      Config::Bind(EnableUploadProgress, ini, config,
                   "Server.Upload.EnableUploadProgress");
      Config::Bind(Rfc1867Freq, ini, config, "Server.Upload.Rfc1867Freq",
                   256 * 1024);
      if (Rfc1867Freq < 0) Rfc1867Freq = 256 * 1024;
      Config::Bind(Rfc1867Prefix, ini, config, "Server.Upload.Rfc1867Prefix",
                   "vupload_");
      Config::Bind(Rfc1867Name, ini, config, "Server.Upload.Rfc1867Name",
                   "video_ptoken");
    }
    Config::Bind(ImageMemoryMaxBytes, ini, config,
                 "Server.ImageMemoryMaxBytes", 0);
    if (ImageMemoryMaxBytes == 0) {
      ImageMemoryMaxBytes = UploadMaxFileSize * 2;
    }
    Config::Bind(LightProcessFilePrefix, ini, config,
                 "Server.LightProcessFilePrefix", "./lightprocess");
    Config::Bind(LightProcessCount, ini, config,
                 "Server.LightProcessCount", 0);
    Config::Bind(LightProcess::g_strictUser, ini, config,
                 "Server.LightProcessStrictUser", false);
    Config::Bind(ForceServerNameToHeader, ini, config,
                 "Server.ForceServerNameToHeader");
    Config::Bind(PathDebug, ini, config, "Server.PathDebug", false);
    Config::Bind(ServerUser, ini, config, "Server.User", "");
    Config::Bind(AllowRunAsRoot, ini, config, "Server.AllowRunAsRoot", false);
  }

  VirtualHost::SortAllowedDirectories(AllowedDirectories);
  {
    auto vh_callback = [] (const IniSettingMap &ini_vh, const Hdf &hdf_vh,
                           const std::string &ini_vh_key) {
      if (VirtualHost::IsDefault(ini_vh, hdf_vh, ini_vh_key)) {
        VirtualHost::GetDefault().init(ini_vh, hdf_vh, ini_vh_key);
        VirtualHost::GetDefault().addAllowedDirectories(AllowedDirectories);
      } else {
        auto host = std::make_shared<VirtualHost>(ini_vh, hdf_vh, ini_vh_key);
        host->addAllowedDirectories(AllowedDirectories);
        VirtualHosts.push_back(host);
      }
    };
    // Virtual Hosts have to be iterated in order. Because only the first
    // one that matches in the VirtualHosts vector gets applied and used.
    // Hdf's and ini (via Variant arrays) internal storage handles ordering
    // naturally (as specified top to bottom in the file and left to right on
    // the command line.
    Config::Iterate(vh_callback, ini, config, "VirtualHost");
    LowestMaxPostSize = VirtualHost::GetLowestMaxPostSize();
  }
  {
    // IpBlocks
    IpBlocks = std::make_shared<IpBlockMap>(ini, config);
  }
  {
    ReadSatelliteInfo(ini, config, SatelliteServerInfos,
                      XboxPassword, XboxPasswords);
  }
  {
    // Xbox
    Config::Bind(XboxServerThreadCount, ini, config,
                 "Xbox.ServerInfo.ThreadCount", 10);
    Config::Bind(XboxServerMaxQueueLength, ini, config,
                 "Xbox.ServerInfo.MaxQueueLength", INT_MAX);
    if (XboxServerMaxQueueLength < 0) XboxServerMaxQueueLength = INT_MAX;
    Config::Bind(XboxServerInfoMaxRequest, ini, config,
                 "Xbox.ServerInfo.MaxRequest", 500);
    Config::Bind(XboxServerInfoDuration, ini, config,
                 "Xbox.ServerInfo.MaxDuration", 120);
    Config::Bind(XboxServerInfoReqInitFunc, ini, config,
                 "Xbox.ServerInfo.RequestInitFunction", "");
    Config::Bind(XboxServerInfoReqInitDoc, ini, config,
                 "Xbox.ServerInfo.RequestInitDocument", "");
    Config::Bind(XboxServerInfoAlwaysReset, ini, config,
                 "Xbox.ServerInfo.AlwaysReset", false);
    Config::Bind(XboxServerLogInfo, ini, config, "Xbox.ServerInfo.LogInfo",
                 false);
    Config::Bind(XboxProcessMessageFunc, ini, config, "Xbox.ProcessMessageFunc",
                 "xbox_process_message");
  }
  {
    // Pagelet Server
    Config::Bind(PageletServerThreadCount, ini, config,
                 "PageletServer.ThreadCount", 0);
    Config::Bind(PageletServerHugeThreadCount, ini, config,
                 "PageletServer.HugeThreadCount", 0);
    Config::Bind(PageletServerThreadDropStack, ini, config,
                 "PageletServer.ThreadDropStack");
    Config::Bind(PageletServerThreadDropCacheTimeoutSeconds, ini, config,
                 "PageletServer.ThreadDropCacheTimeoutSeconds", 0);
    Config::Bind(PageletServerQueueLimit, ini, config,
                 "PageletServer.QueueLimit", 0);
  }
  {
    // Static File

    hphp_string_imap<std::string> staticFileDefault;
    staticFileDefault["css"] = "text/css";
    staticFileDefault["gif"] = "image/gif";
    staticFileDefault["html"] = "text/html";
    staticFileDefault["jpeg"] = "image/jpeg";
    staticFileDefault["jpg"] = "image/jpeg";
    staticFileDefault["mp3"] = "audio/mpeg";
    staticFileDefault["png"] = "image/png";
    staticFileDefault["tif"] = "image/tiff";
    staticFileDefault["tiff"] = "image/tiff";
    staticFileDefault["txt"] = "text/plain";
    staticFileDefault["zip"] = "application/zip";

    Config::Bind(StaticFileExtensions, ini, config, "StaticFile.Extensions",
                 staticFileDefault);

    auto matches_callback = [](const IniSettingMap& ini_m, const Hdf& hdf_m,
                               const std::string& /*ini_m_key*/) {
      FilesMatches.push_back(std::make_shared<FilesMatch>(ini_m, hdf_m));
    };
    Config::Iterate(matches_callback, ini, config, "StaticFile.FilesMatch");
  }
  {
    // PhpFile
    Config::Bind(PhpFileExtensions, ini, config, "PhpFile.Extensions");
  }
  {
    // Admin Server
    Config::Bind(AdminServerIP, ini, config, "AdminServer.IP", ServerIP);
    Config::Bind(AdminServerPort, ini, config, "AdminServer.Port", 0);
    Config::Bind(AdminThreadCount, ini, config, "AdminServer.ThreadCount", 1);
    Config::Bind(AdminServerEnableSSLWithPlainText, ini, config,
                 "AdminServer.EnableSSLWithPlainText", false);
    Config::Bind(AdminServerStatsNeedPassword, ini, config,
                 "AdminServer.StatsNeedPassword", AdminServerStatsNeedPassword);
    AdminPassword = Config::GetString(ini, config, "AdminServer.Password");
    AdminPasswords = Config::GetSet(ini, config, "AdminServer.Passwords");
    HashedAdminPasswords =
      Config::GetSet(ini, config, "AdminServer.HashedPasswords");
    Config::Bind(AdminDumpPath, ini, config,
                 "AdminServer.DumpPath", "/tmp/hhvm_admin_dump");
  }
  {
    // Proxy
    Config::Bind(ProxyOriginRaw, ini, config, "Proxy.Origin");
    Config::Bind(ProxyPercentageRaw, ini, config, "Proxy.Percentage", 0);
    Config::Bind(ProxyRetry, ini, config, "Proxy.Retry", 3);
    Config::Bind(UseServeURLs, ini, config, "Proxy.ServeURLs");
    Config::Bind(ServeURLs, ini, config, "Proxy.ServeURLs");
    Config::Bind(UseProxyURLs, ini, config, "Proxy.ProxyURLs");
    Config::Bind(ProxyURLs, ini, config, "Proxy.ProxyURLs");
    Config::Bind(ProxyPatterns, ini, config, "Proxy.ProxyPatterns");
  }
  {
    // Http
    Config::Bind(HttpDefaultTimeout, ini, config, "Http.DefaultTimeout", 30);
    Config::Bind(HttpSlowQueryThreshold, ini, config, "Http.SlowQueryThreshold",
                 5000);
  }
  {
    // Debug

    Config::Bind(NativeStackTrace, ini, config, "Debug.NativeStackTrace");
    StackTrace::Enabled = NativeStackTrace;
    Config::Bind(ServerErrorMessage, ini, config, "Debug.ServerErrorMessage");
    Config::Bind(RecordInput, ini, config, "Debug.RecordInput");
    Config::Bind(ClearInputOnSuccess, ini, config, "Debug.ClearInputOnSuccess",
                 true);
    Config::Bind(ProfilerOutputDir, ini, config, "Debug.ProfilerOutputDir",
                 "/tmp");
    Config::Bind(CoreDumpEmail, ini, config, "Debug.CoreDumpEmail");
    Config::Bind(CoreDumpReport, ini, config, "Debug.CoreDumpReport", true);
    if (CoreDumpReport) {
      install_crash_reporter();
    }
    // Binding default dependenant on whether we are using an OSS build or
    // not, and that is set at initialization time of CoreDumpReportDirectory.
    Config::Bind(CoreDumpReportDirectory, ini, config,
                 "Debug.CoreDumpReportDirectory", CoreDumpReportDirectory);
    std::ostringstream stack_trace_stream;
    stack_trace_stream << CoreDumpReportDirectory << "/stacktrace."
                       << (int64_t)getpid() << ".log";
    StackTraceFilename = stack_trace_stream.str();

    Config::Bind(StackTraceTimeout, ini, config, "Debug.StackTraceTimeout", 0);
    Config::Bind(RemoteTraceOutputDir, ini, config,
                 "Debug.RemoteTraceOutputDir", "/tmp");
    Config::Bind(TraceFunctions, ini, config,
                 "Debug.TraceFunctions", TraceFunctions);
  }
  {
    // Stats
    Config::Bind(EnableStats, ini, config, "Stats.Enable",
                 false); // main switch
    Config::Bind(EnableAPCStats, ini, config, "Stats.APC", false);
    Config::Bind(EnableWebStats, ini, config, "Stats.Web");
    Config::Bind(EnableMemoryStats, ini, config, "Stats.Memory");
    Config::Bind(EnableSQLStats, ini, config, "Stats.SQL");
    Config::Bind(EnableSQLTableStats, ini, config, "Stats.SQLTable");
    Config::Bind(EnableNetworkIOStatus, ini, config, "Stats.NetworkIO");
    Config::Bind(StatsXSL, ini, config, "Stats.XSL");
    Config::Bind(StatsXSLProxy, ini, config, "Stats.XSLProxy");
    Config::Bind(StatsSlotDuration, ini, config, "Stats.SlotDuration", 10 * 60);
    Config::Bind(StatsMaxSlot, ini, config, "Stats.MaxSlot",
                 12 * 6); // 12 hours
    StatsSlotDuration = std::max(1u, StatsSlotDuration);
    StatsMaxSlot = std::max(2u, StatsMaxSlot);
    Config::Bind(EnableHotProfiler, ini, config, "Stats.EnableHotProfiler",
                 true);
    Config::Bind(ProfilerTraceBuffer, ini, config, "Stats.ProfilerTraceBuffer",
                 2000000);
    Config::Bind(ProfilerTraceExpansion, ini, config,
                 "Stats.ProfilerTraceExpansion", 1.2);
    Config::Bind(ProfilerMaxTraceBuffer, ini, config,
                 "Stats.ProfilerMaxTraceBuffer", 0);
    Config::Bind(TrackPerUnitMemory, ini, config,
                 "Stats.TrackPerUnitMemory", false);
  }
  {
    Config::Bind(ServerVariables, ini, config, "ServerVariables");
    Config::Bind(EnvVariables, ini, config, "EnvVariables");
  }
  {
    // Sandbox
    Config::Bind(SandboxMode, ini, config, "Sandbox.SandboxMode");
    Config::Bind(SandboxPattern, ini, config, "Sandbox.Pattern");
    SandboxPattern = format_pattern(SandboxPattern, true);
    Config::Bind(SandboxHome, ini, config, "Sandbox.Home");
    Config::Bind(SandboxFallback, ini, config, "Sandbox.Fallback");
    Config::Bind(SandboxConfFile, ini, config, "Sandbox.ConfFile");
    Config::Bind(SandboxFromCommonRoot, ini, config, "Sandbox.FromCommonRoot");
    Config::Bind(SandboxDirectoriesRoot, ini, config,
                 "Sandbox.DirectoriesRoot");
    Config::Bind(SandboxLogsRoot, ini, config, "Sandbox.LogsRoot");
    Config::Bind(SandboxServerVariables, ini, config,
                 "Sandbox.ServerVariables");
    Config::Bind(SandboxDefaultUserFile, ini, config,
                 "Sandbox.DefaultUserFile");
    Config::Bind(SandboxHostAlias, ini, config, "Sandbox.HostAlias");
  }
  {
    // Mail
    Config::Bind(SendmailPath, ini, config, "Mail.SendmailPath",
                 "/usr/lib/sendmail -t -i");
    Config::Bind(MailForceExtraParameters, ini, config,
                 "Mail.ForceExtraParameters");
  }
  {
    // Preg
    Config::Bind(PregBacktraceLimit, ini, config, "Preg.BacktraceLimit",
                 1000000);
    Config::Bind(PregRecursionLimit, ini, config, "Preg.RecursionLimit",
                 100000);
    Config::Bind(EnablePregErrorLog, ini, config, "Preg.ErrorLog", true);
  }
  {
    // SimpleXML
    Config::Bind(SimpleXMLEmptyNamespaceMatchesAll, ini, config,
                 "SimpleXML.EmptyNamespaceMatchesAll", false);
  }
#ifdef FACEBOOK
  {
    // Fb303Server
    Config::Bind(EnableFb303Server, ini, config, "Fb303Server.Enable",
                 EnableFb303Server);
    Config::Bind(Fb303ServerPort, ini, config, "Fb303Server.Port", 0);
    Config::Bind(Fb303ServerIP, ini, config, "Fb303Server.IP");
    Config::Bind(Fb303ServerThreadStackSizeMb, ini, config,
                 "Fb303Server.ThreadStackSizeMb", 8);
    Config::Bind(Fb303ServerWorkerThreads, ini, config,
                 "Fb303Server.WorkerThreads", 1);
    Config::Bind(Fb303ServerPoolThreads, ini, config, "Fb303Server.PoolThreads",
                 1);
  }
#endif

  {
    // Xenon
    Config::Bind(XenonPeriodSeconds, ini, config, "Xenon.Period", 0.0);
    Config::Bind(XenonRequestFreq, ini, config, "Xenon.RequestFreq", 1);
    Config::Bind(XenonForceAlwaysOn, ini, config, "Xenon.ForceAlwaysOn", false);
  }
  {
    // Strobelight
    Config::Bind(StrobelightEnabled, ini, config, "Strobelight.Enabled", false);
  }
  {
    // Profiling
    Config::Bind(SetProfileNullThisObject, ini, config,
                 "SetProfile.NullThisObject", true);
  }
  {
    // Loadhint queue penalty
    Config::Bind(ApplySecondaryQueuePenalty, ini, config, "Server.ApplySecondaryQueuePenalty", false);
  }

  Config::Bind(TzdataSearchPaths, ini, config, "TzdataSearchPaths");

  Config::Bind(CustomSettings, ini, config, "CustomSettings");

  // Run initializers depedent on options, e.g., resizing atomic maps/vectors.
  refineStaticStringTableSize();
  InitFiniNode::ProcessPostRuntimeOptions();

  // **************************************************************************
  //                                  DANGER
  //
  // Do not bind any PHP_INI_ALL, PHP_INI_USER or PHP_INI_PERDIR settings here!
  // These settings are process-wide, while those need to be thread-local since
  // they are per-request. They should go into RequestInjectionData. Getting
  // this wrong will cause subtle breakage -- in particular, it probably will
  // not show up in CLI mode, since everything there tends to be single
  // theaded.
  // **************************************************************************
  // Language and Misc Configuration Options
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY, "expose_php",
                   &RuntimeOption::ExposeHPHP);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "auto_prepend_file", &RuntimeOption::AutoPrependFile);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "auto_append_file", &RuntimeOption::AutoAppendFile);

  // Data Handling
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "post_max_size",
                   IniSetting::SetAndGet<int64_t>(
                     nullptr,
                     []() {
                       return VirtualHost::GetMaxPostSize();
                     }
                   ),
                   &RuntimeOption::MaxPostSize);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "always_populate_raw_post_data",
                   &RuntimeOption::AlwaysPopulateRawPostData);

  // Paths and Directories
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "doc_root", &RuntimeOption::SourceRoot);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "sendmail_path", &RuntimeOption::SendmailPath);

  // FastCGI
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY,
                   "pid", &RuntimeOption::PidFile);

  // File Uploads
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "file_uploads", "true",
                   &RuntimeOption::EnableFileUploads);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "upload_tmp_dir", &RuntimeOption::UploadTmpDir);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "upload_max_filesize",
                   IniSetting::SetAndGet<std::string>(
                     [](const std::string& value) {
                       return ini_on_update(
                         value, RuntimeOption::UploadMaxFileSize);
                     },
                     []() {
                       return convert_long_to_bytes(
                         VirtualHost::GetUploadMaxFileSize());
                     }
                   ));
  // Filesystem and Streams Configuration Options
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "allow_url_fopen",
                   IniSetting::SetAndGet<std::string>(
                     [](const std::string& /*value*/) { return false; },
                     []() { return "1"; }));

  // HPHP specific
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
                   "hphp.compiler_id",
                   IniSetting::SetAndGet<std::string>(
                     [](const std::string& /*value*/) { return false; },
                     []() { return compilerId().begin(); }));
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
                   "hphp.compiler_timestamp",
                   IniSetting::SetAndGet<int64_t>(
                     [](const int64_t& /*value*/) { return false; },
                     []() { return compilerTimestamp(); }));
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
                   "hphp.compiler_version",
                   IniSetting::SetAndGet<std::string>(
                     [](const std::string& /*value*/) { return false; },
                     []() { return getHphpCompilerVersion(); }));
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_NONE,
                   "hphp.cli_server_api_version",
                   IniSetting::SetAndGet<uint64_t>(
                     [](const uint64_t /*value*/) { return false; },
                     []() { return cli_server_api_version(); }));
  IniSetting::Bind(
    IniSetting::CORE, IniSetting::PHP_INI_NONE, "hphp.build_id",
    IniSetting::SetAndGet<std::string>(
      [](const std::string& /*value*/) { return false; }, nullptr),
    &RuntimeOption::BuildId);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "notice_frequency",
                   &RuntimeOption::NoticeFrequency);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_SYSTEM,
                   "warning_frequency",
                   &RuntimeOption::WarningFrequency);
  IniSetting::Bind(IniSetting::CORE, IniSetting::PHP_INI_ONLY,
                   "hhvm.build_type",
                   IniSetting::SetAndGet<std::string>(
    [](const std::string&) {
      return false;
    },
    []() {
      return s_hhvm_build_type.c_str();
    }
  ));

  // Extensions
  Config::Bind(RuntimeOption::ExtensionDir, ini, config, "extension_dir",
               RuntimeOption::ExtensionDir, false);
  Config::Bind(RuntimeOption::DynamicExtensionPath, ini,
               config, "DynamicExtensionPath",
               RuntimeOption::DynamicExtensionPath);
  Config::Bind(RuntimeOption::Extensions, ini, config, "extensions");
  Config::Bind(RuntimeOption::DynamicExtensions, ini,
               config, "DynamicExtensions");

  ExtensionRegistry::moduleLoad(ini, config);
  initialize_apc();

  if (TraceFunctions.size()) Trace::ensureInit(getTraceOutputFile());

  if (RO::EvalJitEnableRenameFunction && RO::RepoAuthoritative) {
      throw std::runtime_error("Can't use Eval.JitEnableRenameFunction if "
                               " RepoAuthoritative is turned on");
  }

  // Bespoke array-likes

  auto const enable_logging = RO::EvalBespokeArrayLikeMode != 0;
  bespoke::setLoggingEnabled(enable_logging);
  specializeVanillaDestructors();

  // Coeffects
  CoeffectsConfig::init(RO::EvalCoeffectEnforcementLevels);

  // Initialize defaults for repo-specific parser configuration options.
  RepoOptions::setDefaults(config, ini);
}