<commit_before>#include "caf/config.hpp"
#include "caf/detail/get_mac_addresses.hpp"

#if defined(CAF_MACOS) || defined(CAF_BSD) || defined(CAF_IOS)

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <sstream>

#include <iostream>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  int mib[6];
  std::vector<iface_info> result;
  mib[0] = CTL_NET;
  mib[1] = AF_ROUTE;
  mib[2] = 0;
  mib[3] = AF_LINK;
  mib[4] = NET_RT_IFLIST;
  auto indices = if_nameindex();
  std::unique_ptr<char> buf;
  size_t buf_size = 0;
  for (auto i = indices; !(i->if_index == 0 && i->if_name == nullptr); ++i) {
    mib[5] = static_cast<int>(i->if_index);
    size_t len;
    if (sysctl(mib, 6, nullptr, &len, nullptr, 0) < 0) {
      perror("sysctl 1 error");
      exit(3);
    }
    if (buf_size < len) {
      buf.reset(new char[len]);
      buf_size = len;
    }
    if (sysctl(mib, 6, buf.get(), &len, nullptr, 0) < 0) {
      perror("sysctl 2 error");
      exit(5);
    }
    auto ifm = reinterpret_cast<if_msghdr*>(buf.get());
    auto sdl = reinterpret_cast<sockaddr_dl*>(ifm + 1);
    auto ptr = reinterpret_cast<unsigned char*>(LLADDR(sdl));
    auto uctoi = [](unsigned char c) -> unsigned {
      return static_cast<unsigned char>(c);
    };
    std::ostringstream oss;
    oss << std::hex;
    oss.fill('0');
    oss.width(2);
    oss << uctoi(*ptr++);
    for (auto j = 0; j < 5; ++j) {
      oss << ":";
      oss.width(2);
      oss << uctoi(*ptr++);
    }
    auto addr = oss.str();
    if (addr != "00:00:00:00:00:00") {
      result.emplace_back(i->if_name, std::move(addr));
    }
  }
  if_freenameindex(indices);
  return result;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_LINUX) || defined(CAF_ANDROID) || defined(CAF_CYGWIN)

#include <vector>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <cstring>
#include <unistd.h>
#include <iostream>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  // get a socket handle
  int sck = socket(AF_INET, SOCK_DGRAM, 0);
  if (sck < 0) {
    perror("socket");
    return {};
  }
  // query available interfaces
  char buf[1024] = {0};
  ifconf ifc;
  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  if (ioctl(sck, SIOCGIFCONF, &ifc) < 0) {
    perror("ioctl(SIOCGIFCONF)");
    return {};
  }
  std::vector<iface_info> result;
  auto ctoi = [](char c) -> unsigned {
    return static_cast<unsigned char>(c);
  };
  // iterate through interfaces
  auto ifr = ifc.ifc_req;
  auto num_ifaces = static_cast<size_t>(ifc.ifc_len) / sizeof(ifreq);
  for (size_t i = 0; i < num_ifaces; ++i) {
    auto item = &ifr[i];
    // get mac address
    if (ioctl(sck, SIOCGIFHWADDR, item) < 0) {
      perror("ioctl(SIOCGIFHWADDR)");
      return {};
    }
    std::ostringstream oss;
    oss << std::hex;
    oss.width(2);
    oss << ctoi(item->ifr_hwaddr.sa_data[0]);
    for (size_t j = 1; j < 6; ++j) {
      oss << ":";
      oss.width(2);
      oss << ctoi(item->ifr_hwaddr.sa_data[j]);
    }
    auto addr = oss.str();
    if (addr != "00:00:00:00:00:00") {
      result.push_back({item->ifr_name, std::move(addr)});
    }
  }
  return result;
}

} // namespace detail
} // namespace caf

#else

// windows

#include <ws2tcpip.h>
#include <winsock2.h>
#include <iphlpapi.h>

#include <memory>
#include <vector>
#include <string>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>

namespace {

constexpr size_t working_buffer_size = 15 * 1024; // 15kb by default
constexpr size_t max_iterations = 3;

struct c_free {
  template <class T>
  void operator()(T* ptr) const {
    free(ptr);
  }
};

} // namespace <anonymous>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  // result vector
  std::vector<iface_info> result;
  // flags to pass to GetAdaptersAddresses
  ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
  // default to unspecified address family (both)
  ULONG family = AF_UNSPEC;
  // buffer
  std::unique_ptr<IP_ADAPTER_ADDRESSES, c_free> addresses;
  // init buf size to default, adjusted by GetAdaptersAddresses if needed
  ULONG addresses_len = working_buffer_size;
  // stores result of latest system call
  DWORD res = 0;
  // break condition
  size_t iterations = 0;
  do {
    addresses.reset((IP_ADAPTER_ADDRESSES*)malloc(addresses_len));
    if (!addresses) {
      perror("Memory allocation failed for IP_ADAPTER_ADDRESSES struct");
      exit(1);
    }
    res = GetAdaptersAddresses(family, flags, nullptr, addresses.get(),
                               &addresses_len);
  } while ((res == ERROR_BUFFER_OVERFLOW) && (++iterations < max_iterations));
  if (res == NO_ERROR) {
    // read hardware addresses from the output we've received
    for (auto addr = addresses.get(); addr != nullptr; addr = addr->Next) {
      if (addr->PhysicalAddressLength > 0) {
        std::ostringstream oss;
        oss << std::hex;
        oss.width(2);
        oss << static_cast<int>(addr->PhysicalAddress[0]);
        for (DWORD i = 1; i < addr->PhysicalAddressLength; ++i) {
          oss << ":";
          oss.width(2);
          oss << static_cast<int>(addr->PhysicalAddress[i]);
        }
        auto hw_addr = oss.str();
        if (hw_addr != "00:00:00:00:00:00") {
          result.push_back({addr->AdapterName, std::move(hw_addr)});
        }
      }
    }
  } else {
    if (res == ERROR_NO_DATA) {
      perror("No addresses were found for the requested parameters");
    } else {
      perror("Call to GetAdaptersAddresses failed with error");
    }
  }
  return result;
}

} // namespace detail
} // namespace caf

#endif
<commit_msg>Fix ASAN alloc-dealloc-mismatch on FreeBSD<commit_after>#include "caf/config.hpp"
#include "caf/detail/get_mac_addresses.hpp"

#if defined(CAF_MACOS) || defined(CAF_BSD) || defined(CAF_IOS)

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <sstream>

#include <iostream>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  int mib[6];
  std::vector<iface_info> result;
  mib[0] = CTL_NET;
  mib[1] = AF_ROUTE;
  mib[2] = 0;
  mib[3] = AF_LINK;
  mib[4] = NET_RT_IFLIST;
  auto indices = if_nameindex();
  std::vector<char> buf;
  for (auto i = indices; !(i->if_index == 0 && i->if_name == nullptr); ++i) {
    mib[5] = static_cast<int>(i->if_index);
    size_t len;
    if (sysctl(mib, 6, nullptr, &len, nullptr, 0) < 0) {
      perror("sysctl 1 error");
      exit(3);
    }
    if (buf.size() < len)
      buf.resize(len);
    CAF_ASSERT(len > 0);
    if (sysctl(mib, 6, buf.data(), &len, nullptr, 0) < 0) {
      perror("sysctl 2 error");
      exit(5);
    }
    auto ifm = reinterpret_cast<if_msghdr*>(buf.data());
    auto sdl = reinterpret_cast<sockaddr_dl*>(ifm + 1);
    auto ptr = reinterpret_cast<unsigned char*>(LLADDR(sdl));
    auto uctoi = [](unsigned char c) -> unsigned {
      return static_cast<unsigned char>(c);
    };
    std::ostringstream oss;
    oss << std::hex;
    oss.fill('0');
    oss.width(2);
    oss << uctoi(*ptr++);
    for (auto j = 0; j < 5; ++j) {
      oss << ":";
      oss.width(2);
      oss << uctoi(*ptr++);
    }
    auto addr = oss.str();
    if (addr != "00:00:00:00:00:00") {
      result.emplace_back(i->if_name, std::move(addr));
    }
  }
  if_freenameindex(indices);
  return result;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_LINUX) || defined(CAF_ANDROID) || defined(CAF_CYGWIN)

#include <vector>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <cstring>
#include <unistd.h>
#include <iostream>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  // get a socket handle
  int sck = socket(AF_INET, SOCK_DGRAM, 0);
  if (sck < 0) {
    perror("socket");
    return {};
  }
  // query available interfaces
  char buf[1024] = {0};
  ifconf ifc;
  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  if (ioctl(sck, SIOCGIFCONF, &ifc) < 0) {
    perror("ioctl(SIOCGIFCONF)");
    return {};
  }
  std::vector<iface_info> result;
  auto ctoi = [](char c) -> unsigned {
    return static_cast<unsigned char>(c);
  };
  // iterate through interfaces
  auto ifr = ifc.ifc_req;
  auto num_ifaces = static_cast<size_t>(ifc.ifc_len) / sizeof(ifreq);
  for (size_t i = 0; i < num_ifaces; ++i) {
    auto item = &ifr[i];
    // get mac address
    if (ioctl(sck, SIOCGIFHWADDR, item) < 0) {
      perror("ioctl(SIOCGIFHWADDR)");
      return {};
    }
    std::ostringstream oss;
    oss << std::hex;
    oss.width(2);
    oss << ctoi(item->ifr_hwaddr.sa_data[0]);
    for (size_t j = 1; j < 6; ++j) {
      oss << ":";
      oss.width(2);
      oss << ctoi(item->ifr_hwaddr.sa_data[j]);
    }
    auto addr = oss.str();
    if (addr != "00:00:00:00:00:00") {
      result.push_back({item->ifr_name, std::move(addr)});
    }
  }
  return result;
}

} // namespace detail
} // namespace caf

#else

// windows

#include <ws2tcpip.h>
#include <winsock2.h>
#include <iphlpapi.h>

#include <memory>
#include <vector>
#include <string>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>

namespace {

constexpr size_t working_buffer_size = 15 * 1024; // 15kb by default
constexpr size_t max_iterations = 3;

struct c_free {
  template <class T>
  void operator()(T* ptr) const {
    free(ptr);
  }
};

} // namespace <anonymous>

namespace caf {
namespace detail {

std::vector<iface_info> get_mac_addresses() {
  // result vector
  std::vector<iface_info> result;
  // flags to pass to GetAdaptersAddresses
  ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
  // default to unspecified address family (both)
  ULONG family = AF_UNSPEC;
  // buffer
  std::unique_ptr<IP_ADAPTER_ADDRESSES, c_free> addresses;
  // init buf size to default, adjusted by GetAdaptersAddresses if needed
  ULONG addresses_len = working_buffer_size;
  // stores result of latest system call
  DWORD res = 0;
  // break condition
  size_t iterations = 0;
  do {
    addresses.reset((IP_ADAPTER_ADDRESSES*)malloc(addresses_len));
    if (!addresses) {
      perror("Memory allocation failed for IP_ADAPTER_ADDRESSES struct");
      exit(1);
    }
    res = GetAdaptersAddresses(family, flags, nullptr, addresses.get(),
                               &addresses_len);
  } while ((res == ERROR_BUFFER_OVERFLOW) && (++iterations < max_iterations));
  if (res == NO_ERROR) {
    // read hardware addresses from the output we've received
    for (auto addr = addresses.get(); addr != nullptr; addr = addr->Next) {
      if (addr->PhysicalAddressLength > 0) {
        std::ostringstream oss;
        oss << std::hex;
        oss.width(2);
        oss << static_cast<int>(addr->PhysicalAddress[0]);
        for (DWORD i = 1; i < addr->PhysicalAddressLength; ++i) {
          oss << ":";
          oss.width(2);
          oss << static_cast<int>(addr->PhysicalAddress[i]);
        }
        auto hw_addr = oss.str();
        if (hw_addr != "00:00:00:00:00:00") {
          result.push_back({addr->AdapterName, std::move(hw_addr)});
        }
      }
    }
  } else {
    if (res == ERROR_NO_DATA) {
      perror("No addresses were found for the requested parameters");
    } else {
      perror("Call to GetAdaptersAddresses failed with error");
    }
  }
  return result;
}

} // namespace detail
} // namespace caf

#endif
<|endoftext|>


<commit_before>#pragma once

#include "blackhole/factory.hpp"
#include "blackhole/sink/files/backend.hpp"
#include "blackhole/sink/files/config.hpp"
#include "blackhole/sink/files/flusher.hpp"
#include "blackhole/sink/files/rotation.hpp"
#include "blackhole/sink/files/writer.hpp"

namespace blackhole {

namespace sink {

template<class Backend = files::boost_backend_t, class Rotator = NoRotation, typename = void>
class files_t;

template<class Backend>
class files_t<Backend, NoRotation, void> {
    Backend m_backend;
    files::writer_t<Backend> m_writer;
    files::flusher_t<Backend> m_flusher;
public:
    typedef files::config_t<NoRotation> config_type;

    static const char* name() {
        return "files";
    }

    files_t(const config_type& config) :
        m_backend(config.path),
        m_writer(m_backend),
        m_flusher(config.autoflush, m_backend)
    {}

    void consume(const std::string& message) {
        m_writer.write(message);
        m_flusher.flush();
    }

    Backend& backend() {
        return m_backend;
    }
};

template<class Backend, class Rotator>
class files_t<
    Backend,
    Rotator,
    typename std::enable_if<
        !std::is_same<Rotator, NoRotation>::value
    >::type>
{
    Backend m_backend;
    files::writer_t<Backend> m_writer;
    files::flusher_t<Backend> m_flusher;
    Rotator m_rotator;
public:
    typedef files::config_t<Rotator> config_type;

    static const char* name() {
        return "files";
    }

    files_t(const config_type& config) :
        m_backend(config.path),
        m_writer(m_backend),
        m_flusher(config.autoflush, m_backend),
        m_rotator(config.rotation, m_backend)
    {}

    void consume(const std::string& message) {
        m_writer.write(message);
        m_flusher.flush();
        if (m_rotator.necessary(message)) {
            m_rotator.rotate();
        }
    }

    Backend& backend() {
        return m_backend;
    }
};

} // namespace sink

namespace generator {

template<class Backend, class Watcher>
struct id<sink::files_t<Backend, sink::rotator_t<Backend, Watcher>>> {
    typedef sink::rotator_t<Backend, Watcher> rotator_type;
    typedef sink::files_t<Backend, rotator_type> sink_type;

    static std::string extract(const boost::any& config) {
        std::map<std::string, boost::any> cfg;
        aux::any_to(config, cfg);

        if (cfg.find("rotation") != cfg.end()) {
            std::map<std::string, boost::any> rotation;
            aux::any_to(cfg["rotation"], rotation);
            auto size_it = rotation.find("size");
            auto period_it = rotation.find("period");

            if (size_it != rotation.end() && period_it != rotation.end()) {
                throw blackhole::error_t("set watcher is not implemented yet");
            } else if (size_it != rotation.end()) {
                return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), "size");
            } else if (period_it != rotation.end()) {
                return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), "datetime");
            }
        }

        return sink_type::name();
    }
};

} // namespace generator

template<class Backend>
struct config_traits<sink::files_t<Backend, sink::NoRotation>> {
    static std::string name() {
        return sink::files_t<Backend, sink::NoRotation>::name();
    }
};

template<class Backend, class Watcher>
struct config_traits<sink::files_t<Backend, sink::rotator_t<Backend, Watcher>>> {
    typedef sink::rotator_t<Backend, Watcher> rotator_type;
    typedef sink::files_t<Backend, rotator_type> sink_type;

    static std::string name() {
        return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), Watcher::name());
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend>> {
    typedef sink::files_t<Backend> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink::files_t<Backend>> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        return cfg;
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::size_t>>> {
    typedef typename sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::size_t>> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink_type> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        ex["rotation"]["pattern"].to(cfg.rotation.pattern);
        ex["rotation"]["backups"].to(cfg.rotation.backups);
        ex["rotation"]["size"].to(cfg.rotation.watcher.size);
        return cfg;
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::datetime_t<>>>> {
    typedef typename sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::datetime_t<>>> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink_type> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        ex["rotation"]["pattern"].to(cfg.rotation.pattern);
        ex["rotation"]["backups"].to(cfg.rotation.backups);
        ex["rotation"]["period"].to(cfg.rotation.watcher.period);
        return cfg;
    }
};

} // namespace blackhole
<commit_msg>Refactoring over files sink config id extractor.<commit_after>#pragma once

#include "blackhole/factory.hpp"
#include "blackhole/sink/files/backend.hpp"
#include "blackhole/sink/files/config.hpp"
#include "blackhole/sink/files/flusher.hpp"
#include "blackhole/sink/files/rotation.hpp"
#include "blackhole/sink/files/writer.hpp"

namespace blackhole {

namespace sink {

template<class Backend = files::boost_backend_t, class Rotator = NoRotation, typename = void>
class files_t;

template<class Backend>
class files_t<Backend, NoRotation, void> {
    Backend m_backend;
    files::writer_t<Backend> m_writer;
    files::flusher_t<Backend> m_flusher;
public:
    typedef files::config_t<NoRotation> config_type;

    static const char* name() {
        return "files";
    }

    files_t(const config_type& config) :
        m_backend(config.path),
        m_writer(m_backend),
        m_flusher(config.autoflush, m_backend)
    {}

    void consume(const std::string& message) {
        m_writer.write(message);
        m_flusher.flush();
    }

    Backend& backend() {
        return m_backend;
    }
};

template<class Backend, class Rotator>
class files_t<
    Backend,
    Rotator,
    typename std::enable_if<
        !std::is_same<Rotator, NoRotation>::value
    >::type>
{
    Backend m_backend;
    files::writer_t<Backend> m_writer;
    files::flusher_t<Backend> m_flusher;
    Rotator m_rotator;
public:
    typedef files::config_t<Rotator> config_type;

    static const char* name() {
        return "files";
    }

    files_t(const config_type& config) :
        m_backend(config.path),
        m_writer(m_backend),
        m_flusher(config.autoflush, m_backend),
        m_rotator(config.rotation, m_backend)
    {}

    void consume(const std::string& message) {
        m_writer.write(message);
        m_flusher.flush();
        if (m_rotator.necessary(message)) {
            m_rotator.rotate();
        }
    }

    Backend& backend() {
        return m_backend;
    }
};

} // namespace sink

namespace generator {

template<class Backend, class Watcher>
struct id<sink::files_t<Backend, sink::rotator_t<Backend, Watcher>>> {
    typedef sink::rotator_t<Backend, Watcher> rotator_type;
    typedef sink::files_t<Backend, rotator_type> sink_type;

    static std::string extract(const boost::any& config) {
        const std::map<std::string, boost::any>& cfg =
                boost::any_cast<std::map<std::string, boost::any>>(config);

        auto rotation_it = cfg.find("rotation");
        if (rotation_it != cfg.end()) {
            const std::map<std::string, boost::any>& rotation =
                    boost::any_cast<std::map<std::string, boost::any>>(rotation_it->second);

            const bool has_size_watcher = rotation.find("size") != rotation.end();
            const bool has_datetime_watcher = rotation.find("period") != rotation.end();

            if (has_size_watcher && has_datetime_watcher) {
                throw blackhole::error_t("set watcher is not implemented yet");
            } else if (has_size_watcher) {
                return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), "size");
            } else if (has_datetime_watcher) {
                return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), "datetime");
            }
        }

        return sink_type::name();
    }
};

} // namespace generator

template<class Backend>
struct config_traits<sink::files_t<Backend, sink::NoRotation>> {
    static std::string name() {
        return sink::files_t<Backend, sink::NoRotation>::name();
    }
};

template<class Backend, class Watcher>
struct config_traits<sink::files_t<Backend, sink::rotator_t<Backend, Watcher>>> {
    typedef sink::rotator_t<Backend, Watcher> rotator_type;
    typedef sink::files_t<Backend, rotator_type> sink_type;

    static std::string name() {
        return utils::format("%s/%s/%s", sink_type::name(), rotator_type::name(), Watcher::name());
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend>> {
    typedef sink::files_t<Backend> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink::files_t<Backend>> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        return cfg;
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::size_t>>> {
    typedef typename sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::size_t>> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink_type> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        ex["rotation"]["pattern"].to(cfg.rotation.pattern);
        ex["rotation"]["backups"].to(cfg.rotation.backups);
        ex["rotation"]["size"].to(cfg.rotation.watcher.size);
        return cfg;
    }
};

template<class Backend>
struct factory_traits<sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::datetime_t<>>>> {
    typedef typename sink::files_t<Backend, sink::rotator_t<Backend, sink::rotation::watcher::datetime_t<>>> sink_type;
    typedef typename sink_type::config_type config_type;

    static config_type map_config(const boost::any& config) {
        config_type cfg;
        aux::extractor<sink_type> ex(config);
        ex["path"].to(cfg.path);
        ex["autoflush"].to(cfg.autoflush);
        ex["rotation"]["pattern"].to(cfg.rotation.pattern);
        ex["rotation"]["backups"].to(cfg.rotation.backups);
        ex["rotation"]["period"].to(cfg.rotation.watcher.period);
        return cfg;
    }
};

} // namespace blackhole
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QRegExp>
#include <QTime>
#include <QDate>
#include <QStringList>

#include "duration.h"

const qint64 Duration::NANOSECS_PER_MSEC;
const qint64 Duration::NANOSECS_PER_SEC;
const qint64 Duration::NANOSECS_PER_MIN;
const qint64 Duration::NANOSECS_PER_HOUR;
const qint64 Duration::NANOSECS_PER_DAY;
const qint64 Duration::NANOSECS_PER_WEEK;
const qint64 Duration::MSECS_PER_DAY;
const qint64 Duration::SECS_PER_DAY;
const qint64 Duration::DAYS_PER_YEAR;
const qint64 Duration::DAYS_PER_WEEK;

Duration::Duration(quint64 nanoSecs) : totalNanoSecs_p(nanoSecs)
{
    QTime reftime = QTime().addMSecs((nanoSecs/NANOSECS_PER_MSEC)% MSECS_PER_DAY);
    quint64 days = nanoSecs/NANOSECS_PER_DAY;

    nanoSecs_p = totalNanoSecs_p%(NANOSECS_PER_SEC);
    seconds_p = reftime.second();
    minutes_p = reftime.minute();
    hours_p = reftime.hour();
    days_p = (days%DAYS_PER_YEAR)%DAYS_PER_WEEK;
    weeks_p = (days%DAYS_PER_YEAR)/DAYS_PER_WEEK;
    years_p = days/DAYS_PER_YEAR;
}

Duration::Duration(const QString &duration)
{
    QRegExp re("(?:(\\d+)Y)?\\s*(?:(\\d+)W)?\\s*(?:(\\d+)D)?\\s*(?:(\\d+)H)?\\s*(?:(\\d+)M)?\\s*(?:(\\d+)S)?");
    re.setCaseSensitivity(Qt::CaseInsensitive);

    if (re.exactMatch(duration.simplified()) && re.matchedLength()){
        QStringList list;
        list = re.capturedTexts();
        list.removeFirst();

        qint64 nanosec_year = list.at(0).toLongLong()*(52*NANOSECS_PER_WEEK+NANOSECS_PER_DAY);
        qint64 nanosec_week = list.at(1).toLongLong()*NANOSECS_PER_WEEK;
        qint64 nanosec_day = list.at(2).toLongLong()*NANOSECS_PER_DAY;
        qint64 nanosec_hour = list.at(3).toLongLong()*NANOSECS_PER_HOUR;
        qint64 nanosec_min = list.at(4).toLongLong()*NANOSECS_PER_MIN;
        qint64 nanosec_sec = list.at(5).toLongLong()*NANOSECS_PER_SEC;
        *this = Duration(nanosec_year+nanosec_week+nanosec_day+nanosec_hour+nanosec_min+nanosec_sec);
    }
}

bool Duration::operator==(const Duration &other) const {
    return (totalNanoSecs_p == other.totalNanoSecs_p);
}

Duration::Duration()
{
    totalNanoSecs_p = 0;
}

int Duration::nanoSecs() const
{
    return totalNanoSecs_p%(NANOSECS_PER_SEC);
}

int Duration::seconds() const
{
    return seconds_p;
}

int Duration::minutes() const
{
    return minutes_p;
}

int Duration::hours() const
{
    return hours_p;
}

int Duration::days() const
{
    return days_p;
}

int Duration::weeks() const
{
    return weeks_p;
}

int Duration::years() const
{
    return years_p;
}

QString Duration::toString() const
{
    QString retval;
    if(years_p) {
        retval.append(QString::number(years_p));
        retval.append(QString("Y "));
    }

    if(weeks_p) {
        retval.append(QString::number(weeks_p));
        retval.append(QString("W "));
    }

    if(days_p) {
        retval.append(QString::number(days_p));
        retval.append(QString("D "));
    }

    if(hours_p) {
        retval.append(QString::number(hours_p));
        retval.append(QString("H "));
    }

    if(minutes_p) {
        retval.append(QString::number(minutes_p));
        retval.append(QString("M "));
    }

    if(seconds_p) {
        retval.append(QString::number(seconds_p));
        retval.append(QString("S"));
    } else if (!years_p && !weeks_p && !days_p && !hours_p && !minutes_p && !seconds_p) {
        retval.append(QString("0S"));
    }
    return retval.simplified();
}

bool Duration::isNull() const
{
    return totalNanoSecs_p == 0;
}

bool Duration::isValid() const
{
    return !isNull();
}

quint64 Duration::toNanoSeconds() const
{
    return totalNanoSecs_p;
}

bool Duration::isDuration(const QString &duration)
{
    QRegExp re("(?:(\\d+)Y)?\\s*(?:(\\d+)W)?\\s*(?:(\\d+)D)?\\s*(?:(\\d+)H)?\\s*(?:(\\d+)M)?\\s*(?:(\\d+)S)?");
    re.setCaseSensitivity(Qt::CaseInsensitive);
    return re.exactMatch(duration.simplified()) && re.matchedLength();
}
<commit_msg>Duration error handling fixed.<commit_after>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QRegExp>
#include <QTime>
#include <QDate>
#include <QStringList>

#include "duration.h"

const qint64 Duration::NANOSECS_PER_MSEC;
const qint64 Duration::NANOSECS_PER_SEC;
const qint64 Duration::NANOSECS_PER_MIN;
const qint64 Duration::NANOSECS_PER_HOUR;
const qint64 Duration::NANOSECS_PER_DAY;
const qint64 Duration::NANOSECS_PER_WEEK;
const qint64 Duration::MSECS_PER_DAY;
const qint64 Duration::SECS_PER_DAY;
const qint64 Duration::DAYS_PER_YEAR;
const qint64 Duration::DAYS_PER_WEEK;

Duration::Duration(quint64 nanoSecs) : totalNanoSecs_p(nanoSecs)
{
    QTime reftime = QTime().addMSecs((nanoSecs/NANOSECS_PER_MSEC)% MSECS_PER_DAY);
    quint64 days = nanoSecs/NANOSECS_PER_DAY;

    nanoSecs_p = totalNanoSecs_p%(NANOSECS_PER_SEC);
    seconds_p = reftime.second();
    minutes_p = reftime.minute();
    hours_p = reftime.hour();
    days_p = (days%DAYS_PER_YEAR)%DAYS_PER_WEEK;
    weeks_p = (days%DAYS_PER_YEAR)/DAYS_PER_WEEK;
    years_p = days/DAYS_PER_YEAR;
}

Duration::Duration(const QString &duration)
{
    QRegExp re("(?:(\\d+)Y)?\\s*(?:(\\d+)W)?\\s*(?:(\\d+)D)?\\s*(?:(\\d+)H)?\\s*(?:(\\d+)M)?\\s*(?:(\\d+)S)?");
    re.setCaseSensitivity(Qt::CaseInsensitive);

    if (re.exactMatch(duration.simplified()) && re.matchedLength()){
        QStringList list;
        list = re.capturedTexts();
        list.removeFirst();

        qint64 nanosec_year = list.at(0).toLongLong()*(52*NANOSECS_PER_WEEK+NANOSECS_PER_DAY);
        qint64 nanosec_week = list.at(1).toLongLong()*NANOSECS_PER_WEEK;
        qint64 nanosec_day = list.at(2).toLongLong()*NANOSECS_PER_DAY;
        qint64 nanosec_hour = list.at(3).toLongLong()*NANOSECS_PER_HOUR;
        qint64 nanosec_min = list.at(4).toLongLong()*NANOSECS_PER_MIN;
        qint64 nanosec_sec = list.at(5).toLongLong()*NANOSECS_PER_SEC;
        *this = Duration(nanosec_year+nanosec_week+nanosec_day+nanosec_hour+nanosec_min+nanosec_sec);
    } else {
        totalNanoSecs_p = 0;
    }
}

bool Duration::operator==(const Duration &other) const {
    return (totalNanoSecs_p == other.totalNanoSecs_p);
}

Duration::Duration()
{
    totalNanoSecs_p = 0;
}

int Duration::nanoSecs() const
{
    return totalNanoSecs_p%(NANOSECS_PER_SEC);
}

int Duration::seconds() const
{
    return seconds_p;
}

int Duration::minutes() const
{
    return minutes_p;
}

int Duration::hours() const
{
    return hours_p;
}

int Duration::days() const
{
    return days_p;
}

int Duration::weeks() const
{
    return weeks_p;
}

int Duration::years() const
{
    return years_p;
}

QString Duration::toString() const
{
    QString retval;
    if(years_p) {
        retval.append(QString::number(years_p));
        retval.append(QString("Y "));
    }

    if(weeks_p) {
        retval.append(QString::number(weeks_p));
        retval.append(QString("W "));
    }

    if(days_p) {
        retval.append(QString::number(days_p));
        retval.append(QString("D "));
    }

    if(hours_p) {
        retval.append(QString::number(hours_p));
        retval.append(QString("H "));
    }

    if(minutes_p) {
        retval.append(QString::number(minutes_p));
        retval.append(QString("M "));
    }

    if(seconds_p) {
        retval.append(QString::number(seconds_p));
        retval.append(QString("S"));
    } else if (!years_p && !weeks_p && !days_p && !hours_p && !minutes_p && !seconds_p) {
        retval.append(QString("0S"));
    }
    return retval.simplified();
}

bool Duration::isNull() const
{
    return totalNanoSecs_p == 0;
}

bool Duration::isValid() const
{
    return !isNull();
}

quint64 Duration::toNanoSeconds() const
{
    return totalNanoSecs_p;
}

bool Duration::isDuration(const QString &duration)
{
    QRegExp re("(?:(\\d+)Y)?\\s*(?:(\\d+)W)?\\s*(?:(\\d+)D)?\\s*(?:(\\d+)H)?\\s*(?:(\\d+)M)?\\s*(?:(\\d+)S)?");
    re.setCaseSensitivity(Qt::CaseInsensitive);
    return re.exactMatch(duration.simplified()) && re.matchedLength();
}
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "classifier_factory.hpp"

#include <string>

#include "classifier.hpp"
#include "../common/exception.hpp"
#include "../common/jsonconfig.hpp"
#include "../storage/storage_base.hpp"
#include "../unlearner/unlearner_factory.hpp"

using jubatus::core::common::jsonconfig::config;;
using jubatus::core::common::jsonconfig::config_cast_check;
using jubatus::util::lang::shared_ptr;

namespace jubatus {
namespace core {
namespace classifier {
namespace {

struct unlearner_config {
  jubatus::util::data::optional<std::string> unlearner;
  jubatus::util::data::optional<config>
      unlearner_parameter;

  template<typename Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(unlearner) & JUBA_MEMBER(unlearner_parameter);
  }
};

}  // namespace

shared_ptr<classifier_base> classifier_factory::create_classifier(
    const std::string& name,
    const common::jsonconfig::config& param,
    jubatus::util::lang::shared_ptr<storage::storage_base> storage) {
  unlearner_config conf;
  try {
    conf = config_cast_check<unlearner_config>(param);
  } catch (const common::jsonconfig::cast_check_error& e) {
    // ignore
  }

  jubatus::util::lang::shared_ptr<unlearner::unlearner_base> unlearner;
  if (conf.unlearner) {
    if (!conf.unlearner_parameter) {
      throw JUBATUS_EXCEPTION(common::exception::runtime_error(
          "Unlearner is set but unlearner_parameter is not found"));
    }
    unlearner = unlearner::create_unlearner(
        *conf.unlearner, common::jsonconfig::config(
            *conf.unlearner_parameter));
  }
  shared_ptr<classifier_base> res;
  if (name == "perceptron") {
    // perceptron doesn't have parameter
    res.reset(new perceptron(storage));
  } else if (name == "PA" || name == "passive_aggressive") {
    // passive_aggressive doesn't have parameter
    res.reset(new passive_aggressive(storage));
  } else if (name == "PA1" || name == "passive_aggressive_1") {
    res.reset(new passive_aggressive_1(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "PA2" || name == "passive_aggressive_2") {
    res.reset(new passive_aggressive_2(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "CW" || name == "confidence_weighted") {
    res.reset(new confidence_weighted(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "AROW" || name == "arow") {
    res.reset(new arow(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "NHERD" || name == "normal_herd") {
    res.reset(new normal_herd(
        config_cast_check<classifier_config>(param), storage));
  } else {
    throw JUBATUS_EXCEPTION(common::unsupported_method(name));
  }
  res->set_label_unlearner(unlearner);
  return res;
}

}  // namespace classifier
}  // namespace core
}  // namespace jubatus
<commit_msg>remove unneeded deep copy of unlearner_parameter<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "classifier_factory.hpp"

#include <string>

#include "classifier.hpp"
#include "../common/exception.hpp"
#include "../common/jsonconfig.hpp"
#include "../storage/storage_base.hpp"
#include "../unlearner/unlearner_factory.hpp"

using jubatus::core::common::jsonconfig::config;;
using jubatus::core::common::jsonconfig::config_cast_check;
using jubatus::util::lang::shared_ptr;

namespace jubatus {
namespace core {
namespace classifier {
namespace {

struct unlearner_config {
  jubatus::util::data::optional<std::string> unlearner;
  jubatus::util::data::optional<config>
      unlearner_parameter;

  template<typename Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(unlearner) & JUBA_MEMBER(unlearner_parameter);
  }
};

}  // namespace

shared_ptr<classifier_base> classifier_factory::create_classifier(
    const std::string& name,
    const common::jsonconfig::config& param,
    jubatus::util::lang::shared_ptr<storage::storage_base> storage) {
  unlearner_config conf;
  try {
    conf = config_cast_check<unlearner_config>(param);
  } catch (const common::jsonconfig::cast_check_error& e) {
    // ignore
  }

  jubatus::util::lang::shared_ptr<unlearner::unlearner_base> unlearner;
  if (conf.unlearner) {
    if (!conf.unlearner_parameter) {
      throw JUBATUS_EXCEPTION(common::exception::runtime_error(
          "Unlearner is set but unlearner_parameter is not found"));
    }
    unlearner = unlearner::create_unlearner(
        *conf.unlearner, *conf.unlearner_parameter);
  }
  shared_ptr<classifier_base> res;
  if (name == "perceptron") {
    // perceptron doesn't have parameter
    res.reset(new perceptron(storage));
  } else if (name == "PA" || name == "passive_aggressive") {
    // passive_aggressive doesn't have parameter
    res.reset(new passive_aggressive(storage));
  } else if (name == "PA1" || name == "passive_aggressive_1") {
    res.reset(new passive_aggressive_1(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "PA2" || name == "passive_aggressive_2") {
    res.reset(new passive_aggressive_2(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "CW" || name == "confidence_weighted") {
    res.reset(new confidence_weighted(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "AROW" || name == "arow") {
    res.reset(new arow(
        config_cast_check<classifier_config>(param), storage));
  } else if (name == "NHERD" || name == "normal_herd") {
    res.reset(new normal_herd(
        config_cast_check<classifier_config>(param), storage));
  } else {
    throw JUBATUS_EXCEPTION(common::unsupported_method(name));
  }
  res->set_label_unlearner(unlearner);
  return res;
}

}  // namespace classifier
}  // namespace core
}  // namespace jubatus
<|endoftext|>


<commit_before>#include <libdariadb/interfaces/imeassource.h>

#include <libdariadb/storage/callbacks.h>
#include <libdariadb/utils/metrics.h>
#include <map>

using namespace dariadb;
using namespace dariadb::storage;

void IMeasSource::foreach (const QueryTimePoint &q, IReaderClb * clbk) {
  auto values = this->readTimePoint(q);
  for (auto &kv : values) {
    clbk->call(kv.second);
  }
}

MeasList IMeasSource::readInterval(const QueryInterval &q) {
  TIMECODE_METRICS(ctmd, "readInterval", "IMeasSource::readInterval");
  auto clbk= std::make_unique<MList_ReaderClb>();
  this->foreach (q, clbk.get());

  Id2MSet sub_result;
  for (auto v : clbk->mlist) {
    sub_result[v.id].insert(v);
  }
  MeasList result;
  for (auto id : q.ids) {
    auto sublist = sub_result.find(id);
    if (sublist == sub_result.end()) {
      continue;
    }
    for (auto v : sublist->second) {
      result.push_back(v);
    }
  }
  return result;
}

Id2MinMax IMeasSource::loadMinMax(){
    return Id2MinMax();
}
<commit_msg>IMeasSrouce::loadMinMax() - NOT_IMPLEMENTED.<commit_after>#include <libdariadb/interfaces/imeassource.h>

#include <libdariadb/storage/callbacks.h>
#include <libdariadb/utils/metrics.h>
#include <libdariadb/utils/utils.h>
#include <map>

using namespace dariadb;
using namespace dariadb::storage;

void IMeasSource::foreach (const QueryTimePoint &q, IReaderClb * clbk) {
  auto values = this->readTimePoint(q);
  for (auto &kv : values) {
    clbk->call(kv.second);
  }
}

MeasList IMeasSource::readInterval(const QueryInterval &q) {
  TIMECODE_METRICS(ctmd, "readInterval", "IMeasSource::readInterval");
  auto clbk= std::make_unique<MList_ReaderClb>();
  this->foreach (q, clbk.get());

  Id2MSet sub_result;
  for (auto v : clbk->mlist) {
    sub_result[v.id].insert(v);
  }
  MeasList result;
  for (auto id : q.ids) {
    auto sublist = sub_result.find(id);
    if (sublist == sub_result.end()) {
      continue;
    }
    for (auto v : sublist->second) {
      result.push_back(v);
    }
  }
  return result;
}

Id2MinMax IMeasSource::loadMinMax(){
    NOT_IMPLEMENTED;
    return Id2MinMax();
}
<|endoftext|>


<commit_before>#ifndef BONEFISH_WAMP_TRACE_HPP
#define BONEFISH_WAMP_TRACE_HPP

#include <boost/format.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <string.h>

namespace bonefish {
namespace trace {

extern bool _enabled;

inline bool is_enabled()
{
    return _enabled;
}

inline void set_enabled(bool is_enabled)
{
    _enabled = is_enabled;
}

inline const char* base_file_name(const char* file_path)
{
    const char* file_name = strrchr(file_path, '/');
    return file_name == nullptr ? file_path : file_name + 1;
}

} // namespace trace
} // namespace bonefish

// Macro for facilitating debug trace logging.
#define BONEFISH_TRACE(fmt, ...) \
    BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_VARIADIC_SIZE("dummy", ##__VA_ARGS__), 1), BONFISH_TRACE_ARGS(fmt, __VA_ARGS__), BONFISH_TRACE_NOARGS(fmt, __VA_ARGS__))

#define BONFISH_TRACE_NOARGS(fmt, ...) \
    std::cerr << "[" << bonefish::trace::base_file_name(__FILE__) << ":" << __LINE__ << "][" << __FUNCTION__ << "] " \
            << boost::format(fmt) << std::endl;

#define BONFISH_TRACE_ARGS(fmt, ...) \
    std::cerr << "[" << bonefish::trace::base_file_name(__FILE__) << ":" << __LINE__ << "][" << __FUNCTION__ << "] " \
            << (boost::format(fmt) % __VA_ARGS__) << std::endl;

#endif // BONEFISH_WAMP_TRACE_HPP
<commit_msg>Add missing header to tracing facilitites<commit_after>#ifndef BONEFISH_WAMP_TRACE_HPP
#define BONEFISH_WAMP_TRACE_HPP

#include <boost/format.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <iostream>
#include <string.h>

namespace bonefish {
namespace trace {

extern bool _enabled;

inline bool is_enabled()
{
    return _enabled;
}

inline void set_enabled(bool is_enabled)
{
    _enabled = is_enabled;
}

inline const char* base_file_name(const char* file_path)
{
    const char* file_name = strrchr(file_path, '/');
    return file_name == nullptr ? file_path : file_name + 1;
}

} // namespace trace
} // namespace bonefish

// Macro for facilitating debug trace logging.
#define BONEFISH_TRACE(fmt, ...) \
    BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_VARIADIC_SIZE("dummy", ##__VA_ARGS__), 1), BONFISH_TRACE_ARGS(fmt, __VA_ARGS__), BONFISH_TRACE_NOARGS(fmt, __VA_ARGS__))

#define BONFISH_TRACE_NOARGS(fmt, ...) \
    std::cerr << "[" << bonefish::trace::base_file_name(__FILE__) << ":" << __LINE__ << "][" << __FUNCTION__ << "] " \
            << boost::format(fmt) << std::endl;

#define BONFISH_TRACE_ARGS(fmt, ...) \
    std::cerr << "[" << bonefish::trace::base_file_name(__FILE__) << ":" << __LINE__ << "][" << __FUNCTION__ << "] " \
            << (boost::format(fmt) % __VA_ARGS__) << std::endl;

#endif // BONEFISH_WAMP_TRACE_HPP
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "EnvironmentFeature.h"
#include "Basics/process-utils.h"
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "StorageEngine/EngineSelectorFeature.h"

#ifdef __linux__
#include <sys/sysinfo.h>
#endif

using namespace arangodb;
using namespace arangodb::basics;

EnvironmentFeature::EnvironmentFeature(
    application_features::ApplicationServer* server)
    : ApplicationFeature(server, "Environment") {
  setOptional(false);
  requiresElevatedPrivileges(false);
  startsAfter("Greetings");
  startsAfter("Logger");
}

void EnvironmentFeature::prepare() {
  if (sizeof(void*) == 4) {
    // 32 bit build
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "this is a 32 bit build of ArangoDB. "
        << "it is recommended to run a 64 bit build instead because it can "
        << "address significantly bigger regions of memory";
  }

#ifdef __linux__
  // test local ipv4 port range
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/ip_local_port_range");

    std::vector<std::string> parts = basics::StringUtils::split(value, '\t');
    if (parts.size() == 2) {
      uint64_t lower = basics::StringUtils::uint64(parts[0]);
      uint64_t upper = basics::StringUtils::uint64(parts[1]);

      if (lower > upper || (upper - lower) < 16384) {
        LOG_TOPIC(WARN, arangodb::Logger::COMMUNICATION)
            << "local port range for ipv4/ipv6 ports is " << lower << " - " << upper
            << ", which does not look right. it is recommended to make at least 16K ports available";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo -e \\\"32768\\t60999\\\" > "
                                           "/proc/sys/net/ipv4/ip_local_port_range\"' or use an even bigger port range";
      }
    }
  } catch (...) {
    // file not found or values not convertible into integers
  }

  // test value tcp_tw_recycle
  // https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux
  // https://stackoverflow.com/questions/8893888/dropping-of-connections-with-tcp-tw-recycle
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/tcp_tw_recycle");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      LOG_TOPIC(WARN, Logger::COMMUNICATION)
          << "/proc/sys/net/ipv4/tcp_tw_recycle is enabled (" << v << ")"
          << "'. This can lead to all sorts of \"random\" network problems. "
          << "It is advised to leave it disabled (should be kernel default)";
      LOG_TOPIC(WARN, Logger::COMMUNICATION) << "execute 'sudo bash -c \"echo 0 > "
                                         "/proc/sys/net/ipv4/tcp_tw_recycle\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

#ifdef __GLIBC__
  // test presence of environment variable GLIBCXX_FORCE_NEW
  char const* v = getenv("GLIBCXX_FORCE_NEW");

  if (v == nullptr) {
    // environment variable not set
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "environment variable GLIBCXX_FORCE_NEW' is not set. "
        << "it is recommended to set it to some value to avoid unnecessary memory pooling in glibc++";
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "execute 'export GLIBCXX_FORCE_NEW=1'";
  }
#endif

  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/zone_reclaim_mode");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
      //
      //    This is value ORed together of
      //    1 = Zone reclaim on
      //    2 = Zone reclaim writes dirty pages out
      //    4 = Zone reclaim swaps pages
      //
      // https://www.poempelfox.de/blog/2010/03/19/
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "/proc/sys/vm/zone_reclaim_mode is set to '" << v
          << "'. It is recommended to set it to a value of 0";
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "execute 'sudo bash -c \"echo 0 > "
             "/proc/sys/vm/zone_reclaim_mode\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

  bool showHuge = false;
  std::vector<std::string> paths = {
      "/sys/kernel/mm/transparent_hugepage/enabled",
      "/sys/kernel/mm/transparent_hugepage/defrag"};

  for (auto file : paths) {
    try {
      std::string value = basics::FileUtils::slurp(file);
      size_t start = value.find('[');
      size_t end = value.find(']');

      if (start != std::string::npos && end != std::string::npos &&
          start < end && end - start >= 4) {
        value = value.substr(start + 1, end - start - 1);
        if (value == "always") {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << file << " is set to '" << value
              << "'. It is recommended to set it to a value of 'never' "
                 "or 'madvise'";
          showHuge = true;
        }
      }
    } catch (...) {
      // file not found
    }
  }

  if (showHuge) {
    for (auto file : paths) {
      LOG_TOPIC(WARN, Logger::MEMORY)
          << "execute 'sudo bash -c \"echo madvise > " << file << "\"'";
    }
  }

  bool numa = FileUtils::exists("/sys/devices/system/node/node1");

  if (numa) {
    try {
      std::string value = basics::FileUtils::slurp("/proc/self/numa_maps");
      auto values = basics::StringUtils::split(value, '\n', '\0');

      if (!values.empty()) {
        auto first = values[0];
        auto where = first.find(' ');

        if (where != std::string::npos &&
            !StringUtils::isPrefix(first.substr(where), " interleave")) {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "It is recommended to set NUMA to interleaved.";
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "put 'numactl --interleave=all' in front of your command";
        }
      }
    } catch (...) {
      // file not found
    }
  }

#endif
}

void EnvironmentFeature::start() {
#ifdef __linux__
  bool usingRocksDB =
    (EngineSelectorFeature::engineName() == RocksDBEngine::EngineName);
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_memory");
    uint64_t v = basics::StringUtils::uint64(value);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //   When this flag is 0, the kernel attempts to estimate the amount
    //   of free memory left when userspace requests more memory.
    //   When this flag is 1, the kernel pretends there is always enough
    //   memory until it actually runs out.
    //   When this flag is 2, the kernel uses a "never overcommit"
    //   policy that attempts to prevent any overcommit of memory.
    std::string ratio =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_ratio");
    uint64_t r = basics::StringUtils::uint64(ratio);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //  When overcommit_memory is set to 2, the committed address
    //  space is not permitted to exceed swap plus this percentage
    //  of physical RAM.

    if (usingRocksDB) {
      if (v != 2) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    } else {
      if (v == 1) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 0 or 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    }
    if (v == 2) {
      struct sysinfo info;
      int res = sysinfo(&info);
      if (res == 0) {
        double swapSpace = static_cast<double>(info.totalswap);
        double ram = static_cast<double>(TRI_PhysicalMemory);
        double rr = (ram >= swapSpace)
            ? 100.0 * ((ram - swapSpace) / ram)
            : 0.0;
        if (static_cast<double>(r) > 1.05 * rr ||
            static_cast<double>(r) < 0.95 * r) {
          LOG_TOPIC(WARN, Logger::MEMORY)
            << "/proc/sys/vm/overcommit_ratio is set to '" << r
            << "'. It is recommended to set it to " << static_cast<size_t>(rr)
            << " (100 * (max(0, (RAM - Swap Space)) / RAM)).";
          LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo "
                                          << rr << " > "
                                          << "/proc/sys/vm/overcommit_ratio\"'";
        }
      }
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }
#endif
}
<commit_msg>Fixed a typo in overcommit ratio warning logic and some formatting. (#2650)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "EnvironmentFeature.h"
#include "Basics/process-utils.h"
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "StorageEngine/EngineSelectorFeature.h"

#ifdef __linux__
#include <sys/sysinfo.h>
#endif

using namespace arangodb;
using namespace arangodb::basics;

EnvironmentFeature::EnvironmentFeature(
    application_features::ApplicationServer* server)
    : ApplicationFeature(server, "Environment") {
  setOptional(false);
  requiresElevatedPrivileges(false);
  startsAfter("Greetings");
  startsAfter("Logger");
}

void EnvironmentFeature::prepare() {
  if (sizeof(void*) == 4) {
    // 32 bit build
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "this is a 32 bit build of ArangoDB. "
        << "it is recommended to run a 64 bit build instead because it can "
        << "address significantly bigger regions of memory";
  }

#ifdef __linux__
  // test local ipv4 port range
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/ip_local_port_range");

    std::vector<std::string> parts = basics::StringUtils::split(value, '\t');
    if (parts.size() == 2) {
      uint64_t lower = basics::StringUtils::uint64(parts[0]);
      uint64_t upper = basics::StringUtils::uint64(parts[1]);

      if (lower > upper || (upper - lower) < 16384) {
        LOG_TOPIC(WARN, arangodb::Logger::COMMUNICATION)
            << "local port range for ipv4/ipv6 ports is " << lower << " - " << upper
            << ", which does not look right. it is recommended to make at least 16K ports available";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo -e \\\"32768\\t60999\\\" > "
                                           "/proc/sys/net/ipv4/ip_local_port_range\"' or use an even bigger port range";
      }
    }
  } catch (...) {
    // file not found or values not convertible into integers
  }

  // test value tcp_tw_recycle
  // https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux
  // https://stackoverflow.com/questions/8893888/dropping-of-connections-with-tcp-tw-recycle
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/tcp_tw_recycle");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      LOG_TOPIC(WARN, Logger::COMMUNICATION)
          << "/proc/sys/net/ipv4/tcp_tw_recycle is enabled (" << v << ")"
          << "'. This can lead to all sorts of \"random\" network problems. "
          << "It is advised to leave it disabled (should be kernel default)";
      LOG_TOPIC(WARN, Logger::COMMUNICATION) << "execute 'sudo bash -c \"echo 0 > "
                                         "/proc/sys/net/ipv4/tcp_tw_recycle\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

#ifdef __GLIBC__
  // test presence of environment variable GLIBCXX_FORCE_NEW
  char const* v = getenv("GLIBCXX_FORCE_NEW");

  if (v == nullptr) {
    // environment variable not set
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "environment variable GLIBCXX_FORCE_NEW' is not set. "
        << "it is recommended to set it to some value to avoid unnecessary memory pooling in glibc++";
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "execute 'export GLIBCXX_FORCE_NEW=1'";
  }
#endif

  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/zone_reclaim_mode");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
      //
      //    This is value ORed together of
      //    1 = Zone reclaim on
      //    2 = Zone reclaim writes dirty pages out
      //    4 = Zone reclaim swaps pages
      //
      // https://www.poempelfox.de/blog/2010/03/19/
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "/proc/sys/vm/zone_reclaim_mode is set to '" << v
          << "'. It is recommended to set it to a value of 0";
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "execute 'sudo bash -c \"echo 0 > "
             "/proc/sys/vm/zone_reclaim_mode\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

  bool showHuge = false;
  std::vector<std::string> paths = {
      "/sys/kernel/mm/transparent_hugepage/enabled",
      "/sys/kernel/mm/transparent_hugepage/defrag"};

  for (auto file : paths) {
    try {
      std::string value = basics::FileUtils::slurp(file);
      size_t start = value.find('[');
      size_t end = value.find(']');

      if (start != std::string::npos && end != std::string::npos &&
          start < end && end - start >= 4) {
        value = value.substr(start + 1, end - start - 1);
        if (value == "always") {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << file << " is set to '" << value
              << "'. It is recommended to set it to a value of 'never' "
                 "or 'madvise'";
          showHuge = true;
        }
      }
    } catch (...) {
      // file not found
    }
  }

  if (showHuge) {
    for (auto file : paths) {
      LOG_TOPIC(WARN, Logger::MEMORY)
          << "execute 'sudo bash -c \"echo madvise > " << file << "\"'";
    }
  }

  bool numa = FileUtils::exists("/sys/devices/system/node/node1");

  if (numa) {
    try {
      std::string value = basics::FileUtils::slurp("/proc/self/numa_maps");
      auto values = basics::StringUtils::split(value, '\n', '\0');

      if (!values.empty()) {
        auto first = values[0];
        auto where = first.find(' ');

        if (where != std::string::npos &&
            !StringUtils::isPrefix(first.substr(where), " interleave")) {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "It is recommended to set NUMA to interleaved.";
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "put 'numactl --interleave=all' in front of your command";
        }
      }
    } catch (...) {
      // file not found
    }
  }

#endif
}

void EnvironmentFeature::start() {
#ifdef __linux__
  bool usingRocksDB =
    (EngineSelectorFeature::engineName() == RocksDBEngine::EngineName);
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_memory");
    uint64_t v = basics::StringUtils::uint64(value);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //   When this flag is 0, the kernel attempts to estimate the amount
    //   of free memory left when userspace requests more memory.
    //   When this flag is 1, the kernel pretends there is always enough
    //   memory until it actually runs out.
    //   When this flag is 2, the kernel uses a "never overcommit"
    //   policy that attempts to prevent any overcommit of memory.
    std::string ratio =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_ratio");
    uint64_t r = basics::StringUtils::uint64(ratio);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //  When overcommit_memory is set to 2, the committed address
    //  space is not permitted to exceed swap plus this percentage
    //  of physical RAM.

    if (usingRocksDB) {
      if (v != 2) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    } else {
      if (v == 1) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 0 or 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    }
    if (v == 2) {
      struct sysinfo info;
      int res = sysinfo(&info);
      if (res == 0) {
        double swapSpace = static_cast<double>(info.totalswap);
        double ram = static_cast<double>(TRI_PhysicalMemory);
        double rr = (ram >= swapSpace)
            ? 100.0 * ((ram - swapSpace) / ram)
            : 0.0;
        if (static_cast<double>(r) > 1.05 * rr ||
            static_cast<double>(r) < 0.95 * rr) {
          LOG_TOPIC(WARN, Logger::MEMORY)
            << "/proc/sys/vm/overcommit_ratio is set to '" << r
            << "'. It is recommended to set it to '" << std::llround(rr)
            << "' (100 * (max(0, (RAM - Swap Space)) / RAM)).";
          LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo "
                                          << std::llround(rr) << " > "
                                          << "/proc/sys/vm/overcommit_ratio\"'";
        }
      }
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }
#endif
}
<|endoftext|>


<commit_before>// Author: Jingyue

#define DEBUG_TYPE "dyn-aa"

#include <string>

#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"

#include "rcs/IntraReach.h"
#include "rcs/IDAssigner.h"

#include "dyn-aa/Utils.h"

using namespace std;
using namespace llvm;
using namespace rcs;
using namespace dyn_aa;

namespace dyn_aa {
struct AliasCheckerInstrumenter: public FunctionPass {
  static const string AssertNoAliasHookName;

  static char ID;

  AliasCheckerInstrumenter();
  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
  virtual bool doInitialization(Module &M);
  virtual bool runOnFunction(Function &F);

 private:
  bool isFree(Function *F) const;
  void computeAliasChecks(Function &F,
                          DenseMap<BasicBlock *, InstList> &PointerInsts,
                          vector<InstPair> &Checks);
  void addAliasChecks(const vector<InstPair> &Checks);
  void addAliasChecks(Instruction *P, const InstList &Qs);
  void addAliasCheck(Instruction *P, Instruction *Q, SSAUpdater &SU);

  Function *AssertNoAliasHook;
  // Types.
  Type *VoidType;
  IntegerType *CharType, *IntType;
  PointerType *CharStarType;
  // List of freers.
  vector<string> FreeNames;
};
}

static RegisterPass<AliasCheckerInstrumenter> X(
    "instrument-alias-checker",
    "Instrument the alias checker",
    false, // Is CFG Only?
    false); // Is Analysis?

static cl::opt<unsigned> MaxNumAliasChecks(
    "max-alias-checks",
    cl::desc("Add at most this many alias checks. Used for debugging"),
    cl::init((unsigned)-1));

const string AliasCheckerInstrumenter::AssertNoAliasHookName = "AssertNoAlias";

char AliasCheckerInstrumenter::ID = 0;

AliasCheckerInstrumenter::AliasCheckerInstrumenter(): FunctionPass(ID) {
  AssertNoAliasHook = NULL;
  VoidType = NULL;
  CharType = IntType = NULL;
  CharStarType = NULL;
}

void AliasCheckerInstrumenter::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<AliasAnalysis>();
  AU.addRequired<IntraReach>();
  AU.addRequired<DominatorTree>();
  AU.addRequired<IDAssigner>();
}

#if 0
static bool SortBBByName(const BasicBlock *B1, const BasicBlock *B2) {
  assert(B1->hasName() && B2->hasName());
  return B1->getName() < B2->getName();
}
#endif

void AliasCheckerInstrumenter::computeAliasChecks(
    Function &F,
    DenseMap<BasicBlock *, InstList> &PointerInsts,
    vector<InstPair> &Checks) {
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  IntraReach &IR = getAnalysis<IntraReach>();

  // TODO: consider arguments
  for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
    for (BasicBlock::iterator Ins = BB->begin(); Ins != BB->end(); ++Ins) {
      if (!Ins->getType()->isPointerTy())
        continue;
      if (!DynAAUtils::PointerIsAccessed(Ins))
        continue;
      PointerInsts[BB].push_back(Ins);
    }
  }

  // Do not query AA on modified bc. Therefore, we store the checks we are
  // going to add in Checks, and add them to the program later.
  unsigned NumAliasQueries = 0;
  for (Function::iterator B1 = F.begin(); B1 != F.end(); ++B1) {
    if (!PointerInsts.count(B1))
      continue;
    ConstBBSet ReachableBBs;
    IR.floodfill(B1, ConstBBSet(), ReachableBBs);
    assert(ReachableBBs.count(B1));
    InstList &PointerInstsInB1 = PointerInsts[B1];
    for (size_t i1 = 0, e1 = PointerInstsInB1.size(); i1 < e1; ++i1) {
      Instruction *I1 = PointerInstsInB1[i1];
      for (ConstBBSet::iterator IB2 = ReachableBBs.begin();
           IB2 != ReachableBBs.end(); ++IB2) {
        BasicBlock *B2 = const_cast<BasicBlock *>(*IB2);
        if (!PointerInsts.count(B2))
          continue;
        InstList &PointerInstsInB2 = PointerInsts[B2];
        for (size_t i2 = (B2 == B1 ? i1 + 1 : 0), e2 = PointerInstsInB2.size();
             i2 < e2; ++i2) {
          Instruction *I2 = PointerInstsInB2[i2];
          ++NumAliasQueries;
          if (AA.alias(I1, I2) == AliasAnalysis::NoAlias) {
            Checks.push_back(make_pair(I1, I2));
            if (Checks.size() == MaxNumAliasChecks)
              return;
          }
        }
      }
    }
  }
  errs() << "# of alias queries = " << NumAliasQueries << "\n";
  assert(Checks.size() <= MaxNumAliasChecks);
}

void AliasCheckerInstrumenter::addAliasChecks(const vector<InstPair> &Checks) {
  errs() << "Adding " << Checks.size() << " alias checkers...\n";
  // Checks are clustered on the first item in the pair.
  for (size_t i = 0; i < Checks.size(); ) {
    InstList Qs;
    size_t j = i;
    while (j < Checks.size() &&
           Checks[j].first == Checks[i].first) {
      Qs.push_back(Checks[j].second);
      ++j;
    }
    addAliasChecks(Checks[i].first, Qs);
    i = j;
  }
}

bool AliasCheckerInstrumenter::runOnFunction(Function &F) {
  errs() << "Processing function " << F.getName() << "...\n";

  // Do not query AA on modified bc. Therefore, we store the checks we are
  // going to add in Checks, and add them to the program later.
  DenseMap<BasicBlock *, InstList> PointerInsts;
  vector<InstPair> Checks;
  computeAliasChecks(F, PointerInsts, Checks);

  addAliasChecks(Checks);

  // Remove deallocators.
  for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
    for (BasicBlock::iterator Ins = BB->begin(); Ins != BB->end(); ) {
      BasicBlock::iterator NextIns = Ins; ++NextIns;
      CallSite CS(Ins);
      if (CS && isFree(CS.getCalledFunction()))
        Ins->eraseFromParent();
      Ins = NextIns;
    }
  }

  return true;
}

bool AliasCheckerInstrumenter::doInitialization(Module &M) {
  // Initialize freer list.
  FreeNames.push_back("free");
  FreeNames.push_back("_ZdlPv");
  FreeNames.push_back("_ZdaPv");

  // Initialize basic types.
  VoidType = Type::getVoidTy(M.getContext());
  CharType = Type::getInt8Ty(M.getContext());
  IntType = Type::getInt32Ty(M.getContext());
  CharStarType = PointerType::getUnqual(CharType);

  // Initialize function types.
  vector<Type *> ArgTypes;
  ArgTypes.push_back(CharStarType);
  ArgTypes.push_back(IntType);
  ArgTypes.push_back(CharStarType);
  ArgTypes.push_back(IntType);
  FunctionType *AssertNoAliasHookType = FunctionType::get(VoidType,
                                                          ArgTypes,
                                                          false);

  // Initialize hooks.
  AssertNoAliasHook = Function::Create(AssertNoAliasHookType,
                                       GlobalValue::ExternalLinkage,
                                       AssertNoAliasHookName,
                                       &M);

  return true;
}

void AliasCheckerInstrumenter::addAliasChecks(Instruction *P,
                                              const InstList &Qs) {
  SSAUpdater SU;
  PointerType *TypeOfP = cast<PointerType>(P->getType());
  SU.Initialize(TypeOfP, P->getName());
  SU.AddAvailableValue(P->getParent(), P);
  if (P->getParent() != P->getParent()->getParent()->begin()) {
    SU.AddAvailableValue(P->getParent()->getParent()->begin(),
                         ConstantPointerNull::get(TypeOfP));
  }

  for (size_t i = 0; i < Qs.size(); ++i) {
    addAliasCheck(P, Qs[i], SU);
  }
}

void AliasCheckerInstrumenter::addAliasCheck(Instruction *P,
                                             Instruction *Q,
                                             SSAUpdater &SU) {
  // It's safe to use DominatorTree here, because SSAUpdater preserves CFG.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  IDAssigner &IDA = getAnalysis<IDAssigner>();

  // Compute the location to add the checker.
  BasicBlock::iterator Loc = Q;
  if (isa<PHINode>(Loc))
    Loc = Loc->getParent()->getFirstNonPHI();
  else if (!Loc->isTerminator())
    ++Loc;
  else
    Loc = cast<InvokeInst>(Loc)->getNormalDest()->getFirstNonPHI();

  // Convert <P> and <Q> to "char *".
  BitCastInst *P2 = new BitCastInst(P, CharStarType, "", Loc);
  BitCastInst *Q2 = new BitCastInst(Q, CharStarType, "", Loc);

  // Compute <P> and <Q>'s value IDs.
  unsigned VIDOfP = IDA.getValueID(P), VIDOfQ = IDA.getValueID(Q);
  assert(VIDOfP != IDAssigner::InvalidID && VIDOfQ != IDAssigner::InvalidID);

  // Add a function call to AssertNoAlias.
  vector<Value *> Args;
  Args.push_back(P2);
  Args.push_back(ConstantInt::get(IntType, VIDOfP));
  Args.push_back(Q2);
  Args.push_back(ConstantInt::get(IntType, VIDOfQ));
  CallInst::Create(AssertNoAliasHook, Args, "", Loc);

  // The function call just added may be broken, because <P> may not
  // dominate <Q>. Use SSAUpdater to fix it if necessary.
  if (!DT.dominates(P, P2)) {
    assert(P2->getOperand(0) == P);
    SU.RewriteUse(P2->getOperandUse(0));
  }
}

bool AliasCheckerInstrumenter::isFree(Function *F) const {
  if (!F)
    return false;

  vector<string>::const_iterator Pos = find(FreeNames.begin(),
                                            FreeNames.end(),
                                            F->getName());
  return Pos != FreeNames.end();
}
<commit_msg>Use isFreeCall in LLVM<commit_after>// Author: Jingyue

#define DEBUG_TYPE "dyn-aa"

#include <string>

#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"

#include "rcs/IntraReach.h"
#include "rcs/IDAssigner.h"

#include "dyn-aa/Utils.h"

using namespace std;
using namespace llvm;
using namespace rcs;
using namespace dyn_aa;

namespace dyn_aa {
struct AliasCheckerInstrumenter: public FunctionPass {
  static const string AssertNoAliasHookName;

  static char ID;

  AliasCheckerInstrumenter();
  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
  virtual bool doInitialization(Module &M);
  virtual bool runOnFunction(Function &F);

 private:
  void computeAliasChecks(Function &F,
                          DenseMap<BasicBlock *, InstList> &PointerInsts,
                          vector<InstPair> &Checks);
  void addAliasChecks(const vector<InstPair> &Checks);
  void addAliasChecks(Instruction *P, const InstList &Qs);
  void addAliasCheck(Instruction *P, Instruction *Q, SSAUpdater &SU);

  Function *AssertNoAliasHook;
  // Types.
  Type *VoidType;
  IntegerType *CharType, *IntType;
  PointerType *CharStarType;
};
}

static RegisterPass<AliasCheckerInstrumenter> X(
    "instrument-alias-checker",
    "Instrument the alias checker",
    false, // Is CFG Only?
    false); // Is Analysis?

static cl::opt<unsigned> MaxNumAliasChecks(
    "max-alias-checks",
    cl::desc("Add at most this many alias checks. Used for debugging"),
    cl::init((unsigned)-1));

const string AliasCheckerInstrumenter::AssertNoAliasHookName = "AssertNoAlias";

char AliasCheckerInstrumenter::ID = 0;

AliasCheckerInstrumenter::AliasCheckerInstrumenter(): FunctionPass(ID) {
  AssertNoAliasHook = NULL;
  VoidType = NULL;
  CharType = IntType = NULL;
  CharStarType = NULL;
}

void AliasCheckerInstrumenter::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<AliasAnalysis>();
  AU.addRequired<IntraReach>();
  AU.addRequired<DominatorTree>();
  AU.addRequired<IDAssigner>();
}

#if 0
static bool SortBBByName(const BasicBlock *B1, const BasicBlock *B2) {
  assert(B1->hasName() && B2->hasName());
  return B1->getName() < B2->getName();
}
#endif

void AliasCheckerInstrumenter::computeAliasChecks(
    Function &F,
    DenseMap<BasicBlock *, InstList> &PointerInsts,
    vector<InstPair> &Checks) {
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  IntraReach &IR = getAnalysis<IntraReach>();

  // TODO: consider arguments
  for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
    for (BasicBlock::iterator Ins = BB->begin(); Ins != BB->end(); ++Ins) {
      if (!Ins->getType()->isPointerTy())
        continue;
      if (!DynAAUtils::PointerIsAccessed(Ins))
        continue;
      PointerInsts[BB].push_back(Ins);
    }
  }

  // Do not query AA on modified bc. Therefore, we store the checks we are
  // going to add in Checks, and add them to the program later.
  unsigned NumAliasQueries = 0;
  for (Function::iterator B1 = F.begin(); B1 != F.end(); ++B1) {
    if (!PointerInsts.count(B1))
      continue;
    ConstBBSet ReachableBBs;
    IR.floodfill(B1, ConstBBSet(), ReachableBBs);
    assert(ReachableBBs.count(B1));
    InstList &PointerInstsInB1 = PointerInsts[B1];
    for (size_t i1 = 0, e1 = PointerInstsInB1.size(); i1 < e1; ++i1) {
      Instruction *I1 = PointerInstsInB1[i1];
      for (ConstBBSet::iterator IB2 = ReachableBBs.begin();
           IB2 != ReachableBBs.end(); ++IB2) {
        BasicBlock *B2 = const_cast<BasicBlock *>(*IB2);
        if (!PointerInsts.count(B2))
          continue;
        InstList &PointerInstsInB2 = PointerInsts[B2];
        for (size_t i2 = (B2 == B1 ? i1 + 1 : 0), e2 = PointerInstsInB2.size();
             i2 < e2; ++i2) {
          Instruction *I2 = PointerInstsInB2[i2];
          ++NumAliasQueries;
          if (AA.alias(I1, I2) == AliasAnalysis::NoAlias) {
            Checks.push_back(make_pair(I1, I2));
            if (Checks.size() == MaxNumAliasChecks)
              return;
          }
        }
      }
    }
  }
  errs() << "# of alias queries = " << NumAliasQueries << "\n";
  assert(Checks.size() <= MaxNumAliasChecks);
}

void AliasCheckerInstrumenter::addAliasChecks(const vector<InstPair> &Checks) {
  errs() << "Adding " << Checks.size() << " alias checkers...\n";
  // Checks are clustered on the first item in the pair.
  for (size_t i = 0; i < Checks.size(); ) {
    InstList Qs;
    size_t j = i;
    while (j < Checks.size() &&
           Checks[j].first == Checks[i].first) {
      Qs.push_back(Checks[j].second);
      ++j;
    }
    addAliasChecks(Checks[i].first, Qs);
    i = j;
  }
}

bool AliasCheckerInstrumenter::runOnFunction(Function &F) {
  errs() << "Processing function " << F.getName() << "...\n";

  // Do not query AA on modified bc. Therefore, we store the checks we are
  // going to add in Checks, and add them to the program later.
  DenseMap<BasicBlock *, InstList> PointerInsts;
  vector<InstPair> Checks;
  computeAliasChecks(F, PointerInsts, Checks);

  addAliasChecks(Checks);

  // Remove deallocators.
  for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
    for (BasicBlock::iterator Ins = BB->begin(); Ins != BB->end(); ) {
      BasicBlock::iterator NextIns = Ins; ++NextIns;
      if (isFreeCall(Ins))
        Ins->eraseFromParent();
      Ins = NextIns;
    }
  }

  return true;
}

bool AliasCheckerInstrumenter::doInitialization(Module &M) {
  // Initialize basic types.
  VoidType = Type::getVoidTy(M.getContext());
  CharType = Type::getInt8Ty(M.getContext());
  IntType = Type::getInt32Ty(M.getContext());
  CharStarType = PointerType::getUnqual(CharType);

  // Initialize function types.
  vector<Type *> ArgTypes;
  ArgTypes.push_back(CharStarType);
  ArgTypes.push_back(IntType);
  ArgTypes.push_back(CharStarType);
  ArgTypes.push_back(IntType);
  FunctionType *AssertNoAliasHookType = FunctionType::get(VoidType,
                                                          ArgTypes,
                                                          false);

  // Initialize hooks.
  AssertNoAliasHook = Function::Create(AssertNoAliasHookType,
                                       GlobalValue::ExternalLinkage,
                                       AssertNoAliasHookName,
                                       &M);

  return true;
}

void AliasCheckerInstrumenter::addAliasChecks(Instruction *P,
                                              const InstList &Qs) {
  SSAUpdater SU;
  PointerType *TypeOfP = cast<PointerType>(P->getType());
  SU.Initialize(TypeOfP, P->getName());
  SU.AddAvailableValue(P->getParent(), P);
  if (P->getParent() != P->getParent()->getParent()->begin()) {
    SU.AddAvailableValue(P->getParent()->getParent()->begin(),
                         ConstantPointerNull::get(TypeOfP));
  }

  for (size_t i = 0; i < Qs.size(); ++i) {
    addAliasCheck(P, Qs[i], SU);
  }
}

void AliasCheckerInstrumenter::addAliasCheck(Instruction *P,
                                             Instruction *Q,
                                             SSAUpdater &SU) {
  // It's safe to use DominatorTree here, because SSAUpdater preserves CFG.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  IDAssigner &IDA = getAnalysis<IDAssigner>();

  // Compute the location to add the checker.
  BasicBlock::iterator Loc = Q;
  if (isa<PHINode>(Loc))
    Loc = Loc->getParent()->getFirstNonPHI();
  else if (!Loc->isTerminator())
    ++Loc;
  else
    Loc = cast<InvokeInst>(Loc)->getNormalDest()->getFirstNonPHI();

  // Convert <P> and <Q> to "char *".
  BitCastInst *P2 = new BitCastInst(P, CharStarType, "", Loc);
  BitCastInst *Q2 = new BitCastInst(Q, CharStarType, "", Loc);

  // Compute <P> and <Q>'s value IDs.
  unsigned VIDOfP = IDA.getValueID(P), VIDOfQ = IDA.getValueID(Q);
  assert(VIDOfP != IDAssigner::InvalidID && VIDOfQ != IDAssigner::InvalidID);

  // Add a function call to AssertNoAlias.
  vector<Value *> Args;
  Args.push_back(P2);
  Args.push_back(ConstantInt::get(IntType, VIDOfP));
  Args.push_back(Q2);
  Args.push_back(ConstantInt::get(IntType, VIDOfQ));
  CallInst::Create(AssertNoAliasHook, Args, "", Loc);

  // The function call just added may be broken, because <P> may not
  // dominate <Q>. Use SSAUpdater to fix it if necessary.
  if (!DT.dominates(P, P2)) {
    assert(P2->getOperand(0) == P);
    SU.RewriteUse(P2->getOperandUse(0));
  }
}
<|endoftext|>


<commit_before>//===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the unwind opcode assmebler for ARM exception handling
// table.
//
//===----------------------------------------------------------------------===//

#include "ARMUnwindOpAsm.h"
#include "llvm/Support/ARMEHABI.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"

using namespace llvm;

namespace {
  /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
  /// with MSB to LSB per uint32_t ordering.  For example, the first byte will
  /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
  /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
  class UnwindOpcodeStreamer {
  private:
    SmallVectorImpl<uint8_t> &Vec;
    size_t Pos;

  public:
    UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V), Pos(3) {
    }

    /// Emit the byte in MSB to LSB per uint32_t order.
    inline void EmitByte(uint8_t elem) {
      Vec[Pos] = elem;
      Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
    }

    /// Emit the size prefix.
    inline void EmitSize(size_t Size) {
      size_t SizeInWords = (Size + 3) / 4;
      assert(SizeInWords <= 0x100u &&
             "Only 256 additional words are allowed for unwind opcodes");
      EmitByte(static_cast<uint8_t>(SizeInWords - 1));
    }

    /// Emit the personality index prefix.
    inline void EmitPersonalityIndex(unsigned PI) {
      assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
             "Invalid personality prefix");
      EmitByte(ARM::EHABI::EHT_COMPACT | PI);
    }

    /// Fill the rest of bytes with FINISH opcode.
    inline void FillFinishOpcode() {
      while (Pos < Vec.size())
        EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
    }
  };
}

void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
  if (RegSave == 0u)
    return;

  // One byte opcode to save register r14 and r11-r4
  if (RegSave & (1u << 4)) {
    // The one byte opcode will always save r4, thus we can't use the one byte
    // opcode when r4 is not in .save directive.

    // Compute the consecutive registers from r4 to r11.
    uint32_t Range = 0;
    uint32_t Mask = (1u << 4);
    for (uint32_t Bit = (1u << 5); Bit < (1u << 12); Bit <<= 1) {
      if ((RegSave & Bit) == 0u)
        break;
      ++Range;
      Mask |= Bit;
    }

    // Emit this opcode when the mask covers every registers.
    uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
    if (UnmaskedReg == 0u) {
      // Pop r[4 : (4 + n)]
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
      RegSave &= 0x000fu;
    } else if (UnmaskedReg == (1u << 14)) {
      // Pop r[14] + r[4 : (4 + n)]
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
      RegSave &= 0x000fu;
    }
  }

  // Two bytes opcode to save register r15-r4
  if ((RegSave & 0xfff0u) != 0)
    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));

  // Opcode to save register r3-r0
  if ((RegSave & 0x000fu) != 0)
    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
}

/// Emit unwind opcodes for .vsave directives
void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
  size_t i = 32;

  while (i > 16) {
    uint32_t Bit = 1u << (i - 1);
    if ((VFPRegSave & Bit) == 0u) {
      --i;
      continue;
    }

    uint32_t Range = 0;

    --i;
    Bit >>= 1;

    while (i > 16 && (VFPRegSave & Bit)) {
      --i;
      ++Range;
      Bit >>= 1;
    }

    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16 |
              ((i - 16) << 4) | Range);
  }

  while (i > 0) {
    uint32_t Bit = 1u << (i - 1);
    if ((VFPRegSave & Bit) == 0u) {
      --i;
      continue;
    }

    uint32_t Range = 0;

    --i;
    Bit >>= 1;

    while (i > 0 && (VFPRegSave & Bit)) {
      --i;
      ++Range;
      Bit >>= 1;
    }

    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD | (i << 4) |
              Range);
  }
}

/// Emit unwind opcodes to copy address from source register to $sp.
void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
  EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
}

/// Emit unwind opcodes to add $sp with an offset.
void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
  if (Offset > 0x200) {
    uint8_t Buff[16];
    Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
    size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
    EmitBytes(Buff, ULEBSize + 1);
  } else if (Offset > 0) {
    if (Offset > 0x100) {
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
      Offset -= 0x100;
    }
    EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
             static_cast<uint8_t>((Offset - 4) >> 2));
  } else if (Offset < 0) {
    while (Offset < -0x100) {
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
      Offset += 0x100;
    }
    EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
             static_cast<uint8_t>(((-Offset) - 4) >> 2));
  }
}

void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
                                     SmallVectorImpl<uint8_t> &Result) {

  UnwindOpcodeStreamer OpStreamer(Result);

  if (HasPersonality) {
    // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
    PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
    size_t TotalSize = Ops.size() + 1;
    size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
    Result.resize(RoundUpSize);
    OpStreamer.EmitSize(RoundUpSize);
  } else {
    // If no personalityindex is specified, select ane
    if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
      PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
                                           : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
    if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
      // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
      assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
      Result.resize(4);
      OpStreamer.EmitPersonalityIndex(PersonalityIndex);
    } else {
      // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
      size_t TotalSize = Ops.size() + 2;
      size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
      Result.resize(RoundUpSize);
      OpStreamer.EmitPersonalityIndex(PersonalityIndex);
      OpStreamer.EmitSize(RoundUpSize);
    }
  }

  // Copy the unwind opcodes
  for (size_t i = OpBegins.size() - 1; i > 0; --i)
    for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
      OpStreamer.EmitByte(Ops[j]);

  // Emit the padding finish opcodes if the size is not multiple of 4.
  OpStreamer.FillFinishOpcode();

  // Reset the assembler state
  Reset();
}
<commit_msg>[ARM] Rewrite .save/.vsave emission with bit math<commit_after>//===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the unwind opcode assmebler for ARM exception handling
// table.
//
//===----------------------------------------------------------------------===//

#include "ARMUnwindOpAsm.h"
#include "llvm/Support/ARMEHABI.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"

using namespace llvm;

namespace {
  /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
  /// with MSB to LSB per uint32_t ordering.  For example, the first byte will
  /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
  /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
  class UnwindOpcodeStreamer {
  private:
    SmallVectorImpl<uint8_t> &Vec;
    size_t Pos;

  public:
    UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V), Pos(3) {
    }

    /// Emit the byte in MSB to LSB per uint32_t order.
    inline void EmitByte(uint8_t elem) {
      Vec[Pos] = elem;
      Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
    }

    /// Emit the size prefix.
    inline void EmitSize(size_t Size) {
      size_t SizeInWords = (Size + 3) / 4;
      assert(SizeInWords <= 0x100u &&
             "Only 256 additional words are allowed for unwind opcodes");
      EmitByte(static_cast<uint8_t>(SizeInWords - 1));
    }

    /// Emit the personality index prefix.
    inline void EmitPersonalityIndex(unsigned PI) {
      assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
             "Invalid personality prefix");
      EmitByte(ARM::EHABI::EHT_COMPACT | PI);
    }

    /// Fill the rest of bytes with FINISH opcode.
    inline void FillFinishOpcode() {
      while (Pos < Vec.size())
        EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
    }
  };
}

void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
  if (RegSave == 0u)
    return;

  // One byte opcode to save register r14 and r11-r4
  if (RegSave & (1u << 4)) {
    // The one byte opcode will always save r4, thus we can't use the one byte
    // opcode when r4 is not in .save directive.

    // Compute the consecutive registers from r4 to r11.
    uint32_t Mask = RegSave & 0xff0u;
    uint32_t Range = countTrailingOnes(Mask >> 5); // Exclude r4.
    // Mask off non-consecutive registers. Keep r4.
    Mask &= ~(0xffffffe0u << Range);

    // Emit this opcode when the mask covers every registers.
    uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
    if (UnmaskedReg == 0u) {
      // Pop r[4 : (4 + n)]
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
      RegSave &= 0x000fu;
    } else if (UnmaskedReg == (1u << 14)) {
      // Pop r[14] + r[4 : (4 + n)]
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
      RegSave &= 0x000fu;
    }
  }

  // Two bytes opcode to save register r15-r4
  if ((RegSave & 0xfff0u) != 0)
    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));

  // Opcode to save register r3-r0
  if ((RegSave & 0x000fu) != 0)
    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
}

/// Emit unwind opcodes for .vsave directives
void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
  // We only have 4 bits to save the offset in the opcode so look at the lower
  // and upper 16 bits separately.
  for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
    while (Regs) {
      // Now look for a run of set bits. Remember the MSB and LSB of the run.
      auto RangeMSB = 32 - countLeadingZeros(Regs);
      auto RangeLen = countLeadingOnes(Regs << (32 - RangeMSB));
      auto RangeLSB = RangeMSB - RangeLen;

      int Opcode = RangeLSB >= 16
                       ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
                       : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;

      EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));

      // Zero out bits we're done with.
      Regs &= ~(-1u << RangeLSB);
    }
  }
}

/// Emit unwind opcodes to copy address from source register to $sp.
void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
  EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
}

/// Emit unwind opcodes to add $sp with an offset.
void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
  if (Offset > 0x200) {
    uint8_t Buff[16];
    Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
    size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
    EmitBytes(Buff, ULEBSize + 1);
  } else if (Offset > 0) {
    if (Offset > 0x100) {
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
      Offset -= 0x100;
    }
    EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
             static_cast<uint8_t>((Offset - 4) >> 2));
  } else if (Offset < 0) {
    while (Offset < -0x100) {
      EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
      Offset += 0x100;
    }
    EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
             static_cast<uint8_t>(((-Offset) - 4) >> 2));
  }
}

void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
                                     SmallVectorImpl<uint8_t> &Result) {

  UnwindOpcodeStreamer OpStreamer(Result);

  if (HasPersonality) {
    // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
    PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
    size_t TotalSize = Ops.size() + 1;
    size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
    Result.resize(RoundUpSize);
    OpStreamer.EmitSize(RoundUpSize);
  } else {
    // If no personalityindex is specified, select ane
    if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
      PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
                                           : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
    if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
      // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
      assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
      Result.resize(4);
      OpStreamer.EmitPersonalityIndex(PersonalityIndex);
    } else {
      // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
      size_t TotalSize = Ops.size() + 2;
      size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
      Result.resize(RoundUpSize);
      OpStreamer.EmitPersonalityIndex(PersonalityIndex);
      OpStreamer.EmitSize(RoundUpSize);
    }
  }

  // Copy the unwind opcodes
  for (size_t i = OpBegins.size() - 1; i > 0; --i)
    for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
      OpStreamer.EmitByte(Ops[j]);

  // Emit the padding finish opcodes if the size is not multiple of 4.
  OpStreamer.FillFinishOpcode();

  // Reset the assembler state
  Reset();
}
<|endoftext|>