<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief file utilities
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2008-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "FileUtils.h"

#include <errno.h>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef TRI_HAVE_DIRENT_H
#include <dirent.h>
#endif

#ifdef TRI_HAVE_DIRECT_H
#include <direct.h>
#endif

#include "Basics/Exceptions.h"
#include "Logger/Logger.h"
#include "Basics/StringBuffer.h"
#include "BasicsC/files.h"
#include "BasicsC/tri-strings.h"

namespace triagens {
  namespace basics {
    namespace FileUtils {
      ifstream * createInput (string const& filename) {
        ifstream * s = new ifstream(filename.c_str());

        if (!*s) {
          delete s;
          return 0;
        }

        return s;
      }

      ofstream * createOutput (string const& filename) {
        ofstream * s = new ofstream(filename.c_str());

        if (!*s) {
          delete s;
          return 0;
        }

        return s;
      }

      string slurp (string const& filename) {
        int fd = TRI_OPEN(filename.c_str(), O_RDONLY);

        if (fd == -1) {
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY", errno);
        }

        char buffer[10240];
        StringBuffer result(TRI_CORE_MEM_ZONE);

        while (true) {
          ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

          if (n == 0) {
            break;
          }

          if (n < 0) {
            TRI_set_errno(TRI_ERROR_SYS_ERROR);

            LOGGER_TRACE("read failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);

            TRI_CLOSE(fd);
            THROW_FILE_FUNC_ERROR("read", "", errno);
          }

          result.appendText(buffer, n);
        }

        TRI_CLOSE(fd);

        string r(result.c_str(), result.length());

        return r;
      }

      void slurp (string const& filename, StringBuffer& result) {
        int fd = TRI_OPEN(filename.c_str(), O_RDONLY);

        if (fd == -1) {
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY", errno);
        }

        // reserve space in the output buffer
        off_t fileSize = size(filename);
        if (fileSize > 0) {
          result.reserve((size_t) fileSize);
        }

        char buffer[10240];

        while (true) {
          ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

          if (n == 0) {
            break;
          }

          if (n < 0) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("read failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("read", "", errno);
          }

          result.appendText(buffer, n);
        }

        TRI_CLOSE(fd);
      }

      void spit (string const& filename, const char* ptr, size_t len) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY | O_CREAT | O_TRUNC", errno);
        }

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      void spit (string const& filename, string const& content) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY | O_CREAT | O_TRUNC", errno);
        }

        char const* ptr = content.c_str();
        size_t len = content.size();

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      void spit (string const& filename, StringBuffer const& content) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_WRONLY | O_CREAT | O_TRUNC", errno);
        }

        char const* ptr = content.c_str();
        size_t len = content.length();

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      bool remove (string const& fileName, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = std::remove(fileName.c_str());

        if (errorNumber != 0) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      bool rename (string const& oldName, string const& newName, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = std::rename(oldName.c_str(), newName.c_str());

        if (errorNumber) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      bool createDirectory (string const& name, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        return createDirectory(name, 0777, errorNumber);
      }

      bool createDirectory (string const& name, int mask, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = TRI_MKDIR(name.c_str(), mask);

        if (result != 0 && errno == EEXIST && isDirectory(name)) {
          result = 0;
        }

        if (errorNumber) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      vector<string> listFiles (string const& directory) {
        vector < string > result;

#ifdef TRI_HAVE_WIN32_LIST_FILES

        struct _finddata_t fd;
        intptr_t handle;

        string filter = directory + "\\*";
        handle = _findfirst(filter.c_str(), &fd);

        if (handle == -1) {
          return result;
        }

        do {
          if (strcmp(fd.name, ".") != 0 && strcmp(fd.name, "..") != 0) {
            result.push_back(fd.name);
          }
        } while(_findnext(handle, &fd) != -1);

        _findclose(handle);

#else

        DIR * d = opendir(directory.c_str());

        if (d == 0) {
          return result;
        }

        dirent * de = readdir(d);

        while (de != 0) {
          if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
            result.push_back(de->d_name);
          }

          de = readdir(d);
        }

        closedir(d);

#endif

        return result;
      }

      bool isDirectory (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFDIR);
      }

      bool isSymbolicLink (string const& path) {

#ifdef TRI_HAVE_WIN32_SYMBOLIC_LINK

        // .........................................................................
        // TODO: On the NTFS file system, there are the following file links:
        // hard links -
        // junctions -
        // symbolic links -
        // .........................................................................
        return false;

#else

        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFLNK);

#endif
      }

      bool isRegularFile (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFREG);
      }

      bool exists (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return res == 0;
      }

      off_t size (string const& path) {
        int64_t result = TRI_SizeFile(path.c_str());

        if (result < 0) {
          return (off_t) 0;
        }

        return (off_t) result;
      }

      string stripExtension (string const& path, string const& extension) {
        size_t pos = path.rfind(extension);
        if (pos == string::npos) {
          return path;
        }

        string last = path.substr(pos);
        if (last == extension) {
          return path.substr(0, pos);
        }

        return path;
      }

      bool changeDirectory (string const& path) {
        return TRI_CHDIR(path.c_str()) == 0;
      }

      string currentDirectory (int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        size_t len = 1000;
        char* current = new char[len];

        while (TRI_GETCWD(current, len) == NULL) {
          if (errno == ERANGE) {
            len += 1000;
            delete[] current;
            current = new char[len];
          }
          else {
            delete[] current;

            if (errorNumber != 0) {
              *errorNumber = errno;
            }

            return "";
          }
        }

        string result = current;

        delete[] current;

        return result;
      }

      string homeDirectory () {
        char* dir = TRI_HomeDirectory();
        string result = dir;
        TRI_FreeString(TRI_CORE_MEM_ZONE, dir);

        return result;
      }
    }
  }
}

<commit_msg>properly set error code<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief file utilities
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2008-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "FileUtils.h"

#include <errno.h>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef TRI_HAVE_DIRENT_H
#include <dirent.h>
#endif

#ifdef TRI_HAVE_DIRECT_H
#include <direct.h>
#endif

#include "Basics/Exceptions.h"
#include "Logger/Logger.h"
#include "Basics/StringBuffer.h"
#include "BasicsC/files.h"
#include "BasicsC/tri-strings.h"

namespace triagens {
  namespace basics {
    namespace FileUtils {
      ifstream * createInput (string const& filename) {
        ifstream * s = new ifstream(filename.c_str());

        if (!*s) {
          delete s;
          return 0;
        }

        return s;
      }

      ofstream * createOutput (string const& filename) {
        ofstream * s = new ofstream(filename.c_str());

        if (!*s) {
          delete s;
          return 0;
        }

        return s;
      }

      string slurp (string const& filename) {
        int fd = TRI_OPEN(filename.c_str(), O_RDONLY);

        if (fd == -1) {
          TRI_set_errno(errno);
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY", errno);
        }

        char buffer[10240];
        StringBuffer result(TRI_CORE_MEM_ZONE);

        while (true) {
          ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

          if (n == 0) {
            break;
          }

          if (n < 0) {
            TRI_set_errno(TRI_ERROR_SYS_ERROR);

            LOGGER_TRACE("read failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);

            TRI_CLOSE(fd);
            THROW_FILE_FUNC_ERROR("read", "", errno);
          }

          result.appendText(buffer, n);
        }

        TRI_CLOSE(fd);

        string r(result.c_str(), result.length());

        return r;
      }

      void slurp (string const& filename, StringBuffer& result) {
        int fd = TRI_OPEN(filename.c_str(), O_RDONLY);

        if (fd == -1) {
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY", errno);
        }

        // reserve space in the output buffer
        off_t fileSize = size(filename);
        if (fileSize > 0) {
          result.reserve((size_t) fileSize);
        }

        char buffer[10240];

        while (true) {
          ssize_t n = TRI_READ(fd, buffer, sizeof(buffer));

          if (n == 0) {
            break;
          }

          if (n < 0) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("read failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("read", "", errno);
          }

          result.appendText(buffer, n);
        }

        TRI_CLOSE(fd);
      }

      void spit (string const& filename, const char* ptr, size_t len) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY | O_CREAT | O_TRUNC", errno);
        }

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      void spit (string const& filename, string const& content) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY | O_CREAT | O_TRUNC", errno);
        }

        char const* ptr = content.c_str();
        size_t len = content.size();

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      void spit (string const& filename, StringBuffer const& content) {
        int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);

        if (fd == -1) {
          LOGGER_TRACE("open failed for '" << filename << "' with " << strerror(errno));
          THROW_FILE_OPEN_ERROR("open", filename, "O_WRONLY | O_CREAT | O_TRUNC", errno);
        }

        char const* ptr = content.c_str();
        size_t len = content.length();

        while (0 < len) {
          ssize_t n = TRI_WRITE(fd, ptr, len);

          if (n < 1) {
            TRI_CLOSE(fd);
            LOGGER_TRACE("write failed for '" << filename
                         << "' with " << strerror(errno) << " and result " << n
                         << " on fd " << fd);
            THROW_FILE_FUNC_ERROR("write", "", errno);
          }

          ptr += n;
          len -= n;
        }

        TRI_CLOSE(fd);
        return;
      }

      bool remove (string const& fileName, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = std::remove(fileName.c_str());

        if (errorNumber != 0) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      bool rename (string const& oldName, string const& newName, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = std::rename(oldName.c_str(), newName.c_str());

        if (errorNumber) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      bool createDirectory (string const& name, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        return createDirectory(name, 0777, errorNumber);
      }

      bool createDirectory (string const& name, int mask, int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        int result = TRI_MKDIR(name.c_str(), mask);

        if (result != 0 && errno == EEXIST && isDirectory(name)) {
          result = 0;
        }

        if (errorNumber) {
          *errorNumber = errno;
        }

        return (result != 0) ? false : true;
      }

      vector<string> listFiles (string const& directory) {
        vector < string > result;

#ifdef TRI_HAVE_WIN32_LIST_FILES

        struct _finddata_t fd;
        intptr_t handle;

        string filter = directory + "\\*";
        handle = _findfirst(filter.c_str(), &fd);

        if (handle == -1) {
          return result;
        }

        do {
          if (strcmp(fd.name, ".") != 0 && strcmp(fd.name, "..") != 0) {
            result.push_back(fd.name);
          }
        } while(_findnext(handle, &fd) != -1);

        _findclose(handle);

#else

        DIR * d = opendir(directory.c_str());

        if (d == 0) {
          return result;
        }

        dirent * de = readdir(d);

        while (de != 0) {
          if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
            result.push_back(de->d_name);
          }

          de = readdir(d);
        }

        closedir(d);

#endif

        return result;
      }

      bool isDirectory (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFDIR);
      }

      bool isSymbolicLink (string const& path) {

#ifdef TRI_HAVE_WIN32_SYMBOLIC_LINK

        // .........................................................................
        // TODO: On the NTFS file system, there are the following file links:
        // hard links -
        // junctions -
        // symbolic links -
        // .........................................................................
        return false;

#else

        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFLNK);

#endif
      }

      bool isRegularFile (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFREG);
      }

      bool exists (string const& path) {
        struct stat stbuf;
        int res = stat(path.c_str(), &stbuf);

        return res == 0;
      }

      off_t size (string const& path) {
        int64_t result = TRI_SizeFile(path.c_str());

        if (result < 0) {
          return (off_t) 0;
        }

        return (off_t) result;
      }

      string stripExtension (string const& path, string const& extension) {
        size_t pos = path.rfind(extension);
        if (pos == string::npos) {
          return path;
        }

        string last = path.substr(pos);
        if (last == extension) {
          return path.substr(0, pos);
        }

        return path;
      }

      bool changeDirectory (string const& path) {
        return TRI_CHDIR(path.c_str()) == 0;
      }

      string currentDirectory (int* errorNumber) {
        if (errorNumber != 0) {
          *errorNumber = 0;
        }

        size_t len = 1000;
        char* current = new char[len];

        while (TRI_GETCWD(current, len) == NULL) {
          if (errno == ERANGE) {
            len += 1000;
            delete[] current;
            current = new char[len];
          }
          else {
            delete[] current;

            if (errorNumber != 0) {
              *errorNumber = errno;
            }

            return "";
          }
        }

        string result = current;

        delete[] current;

        return result;
      }

      string homeDirectory () {
        char* dir = TRI_HomeDirectory();
        string result = dir;
        TRI_FreeString(TRI_CORE_MEM_ZONE, dir);

        return result;
      }
    }
  }
}

<|endoftext|>


<commit_before><commit_msg>arm: Fix timing wakeup with LLSC (transplanted from d1dce0b728b6181ce8e14f24c0301d012e2c4ad8)<commit_after><|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief debugging helpers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Basics/Common.h"
#include "Basics/locks.h"
#include "Basics/logging.h"

#ifdef TRI_ENABLE_MAINTAINER_MODE
#if HAVE_BACKTRACE

#include <execinfo.h>
#include <cxxabi.h>

#endif
#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief a global string containing the currently registered failure points
/// the string is a comma-separated list of point names
////////////////////////////////////////////////////////////////////////////////

static char* FailurePoints;

////////////////////////////////////////////////////////////////////////////////
/// @brief a read-write lock for thread-safe access to the failure-points list
////////////////////////////////////////////////////////////////////////////////

TRI_read_write_lock_t FailurePointsLock;

#ifdef TRI_ENABLE_FAILURE_TESTS

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief make a delimited value from a string, so we can unambigiously
/// search for it (e.g. searching for just "foo" would find "foo" and "foobar",
/// so we'll be putting the value inside some delimiter: ",foo,")
////////////////////////////////////////////////////////////////////////////////

static char* MakeValue (char const* value) {
  if (value == nullptr || strlen(value) == 0) {
    return nullptr;
  }

  char* delimited = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(value) + 3, false));

  if (delimited != nullptr) {
    memcpy(delimited + 1, value, strlen(value));
    delimited[0] = ',';
    delimited[strlen(value) + 1] = ',';
    delimited[strlen(value) + 2] = '\0';
  }

  return delimited;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief cause a segmentation violation
/// this is used for crash and recovery tests
////////////////////////////////////////////////////////////////////////////////

void TRI_SegfaultDebugging (char const* message) {
  LOG_WARNING("%s: summon Baal!", message);
  // make sure the latest log messages are flushed
  TRI_ShutdownLogging(true);

  // and now crash
#ifndef __APPLE__
  // on MacOS, the following statement makes the server hang but not crash
  *((char*) -1) = '!';
#endif

  // ensure the process is terminated
  abort();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief check whether we should fail at a specific failure point
////////////////////////////////////////////////////////////////////////////////

bool TRI_ShouldFailDebugging (char const* value) {
  char* found = nullptr;

  // try without the lock first (to speed things up)
  if (FailurePoints == nullptr) {
    return false;
  }

  TRI_ReadLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints != nullptr) {
    char* checkValue = MakeValue(value);

    if (checkValue != nullptr) {
      found = strstr(FailurePoints, checkValue);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
    }
  }

  TRI_ReadUnlockReadWriteLock(&FailurePointsLock);

  return (found != nullptr);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add a failure point
////////////////////////////////////////////////////////////////////////////////

void TRI_AddFailurePointDebugging (char const* value) {
  char* found;
  char* checkValue;

  checkValue = MakeValue(value);

  if (checkValue == nullptr) {
    return;
  }

  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints == nullptr) {
    found = nullptr;
  }
  else {
    found = strstr(FailurePoints, checkValue);
  }

  if (found == nullptr) {
    // not yet found. so add it
    char* copy;
    size_t n;

    LOG_WARNING("activating intentional failure point '%s'. the server will misbehave!", value);
    n = strlen(checkValue);

    if (FailurePoints == nullptr) {
      copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, n + 1, false));

      if (copy == nullptr) {
        TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
        TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
        return;
      }

      memcpy(copy, checkValue, n);
      copy[n] = '\0';
    }
    else {
      copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, n + strlen(FailurePoints), false));

      if (copy == nullptr) {
        TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
        TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
        return;
      }

      memcpy(copy, FailurePoints, strlen(FailurePoints));
      memcpy(copy + strlen(FailurePoints) - 1, checkValue, n);
      copy[strlen(FailurePoints) + n - 1] = '\0';
    }

    FailurePoints = copy;
  }

  TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
  TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief remove a failure points
////////////////////////////////////////////////////////////////////////////////

void TRI_RemoveFailurePointDebugging (char const* value) {
  char* checkValue;

  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints == nullptr) {
    TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
    return;
  }

  checkValue = MakeValue(value);

  if (checkValue != nullptr) {
    char* found;
    char* copy;
    size_t n;

    found = strstr(FailurePoints, checkValue);

    if (found == nullptr) {
      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    if (strlen(FailurePoints) - strlen(checkValue) <= 2) {
      TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
      FailurePoints = nullptr;

      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(FailurePoints) - strlen(checkValue) + 2, false));

    if (copy == nullptr) {
      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    // copy start of string
    n = found - FailurePoints;
    memcpy(copy, FailurePoints, n);

    // copy remainder of string
    memcpy(copy + n, found + strlen(checkValue) - 1, strlen(FailurePoints) - strlen(checkValue) - n + 1);

    copy[strlen(FailurePoints) - strlen(checkValue) + 1] = '\0';
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
    FailurePoints = copy;

    TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
    TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief clear all failure points
////////////////////////////////////////////////////////////////////////////////

void TRI_ClearFailurePointsDebugging () {
  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints != nullptr) {
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
  }

  FailurePoints = nullptr;

  TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the debugging
////////////////////////////////////////////////////////////////////////////////

void TRI_InitialiseDebugging () {
  FailurePoints = nullptr;
  TRI_InitReadWriteLock(&FailurePointsLock);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief shutdown the debugging
////////////////////////////////////////////////////////////////////////////////

void TRI_ShutdownDebugging () {
  if (FailurePoints != nullptr) {
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
  }

  FailurePoints = nullptr;

  TRI_DestroyReadWriteLock(&FailurePointsLock);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief appends a backtrace to the string provided
////////////////////////////////////////////////////////////////////////////////

void TRI_GetBacktrace (std::string& btstr) {
#if HAVE_BACKTRACE
#ifdef _WIN32
  unsigned int   i;
  void         * stack[ 100 ];
  unsigned short frames;
  SYMBOL_INFO  * symbol;
  HANDLE         process;

  process = GetCurrentProcess();

  SymInitialize( process, NULL, TRUE );

  frames               = CaptureStackBackTrace( 0, 100, stack, NULL );
  symbol               = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
  symbol->MaxNameLen   = 255;
  symbol->SizeOfStruct = sizeof( SYMBOL_INFO );

  for( i = 0; i < frames; i++ )
    {
      char address[64];
      SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );

      snprintf(address, sizeof(address),  "0x%0X", symbol->Address );
      bstr += std::string(frames - i - 1) + std::string(": ") + symbol->Name + std::string(" [") + address + std::string("]\n");
    }

  free( symbol );

#else
  void* stack_frames[50];
  size_t size, i;
  char** strings;

  size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
  strings = backtrace_symbols(stack_frames, size);
  for (i = 0; i < size; i++) {
    std::stringstream ss;
    if (strings != nullptr) {
      char *mangled_name = nullptr, *offset_begin = nullptr, *offset_end = nullptr;

      // find parantheses and +address offset surrounding mangled name
      for (char *p = strings[i]; *p; ++p) {
        if (*p == '(') {
          mangled_name = p;
        }
        else if (*p == '+') {
          offset_begin = p;
        }
        else if (*p == ')') {
          offset_end = p;
          break;
        }
      }

      // if the line could be processed, attempt to demangle the symbol
      if (mangled_name && offset_begin && offset_end &&
          mangled_name < offset_begin) {
        *mangled_name++ = '\0';
        *offset_begin++ = '\0';
        *offset_end++ = '\0';
        int status = 0;
        char * demangled_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);

        if (demangled_name != nullptr) {
          if (status == 0) {
            ss << stack_frames[i];
            btstr +=  strings[i] +
              std::string("() [") +
              ss.str() +
              std::string("] ") +
              demangled_name +
              std::string("\n");
          }
          else {
            btstr += strings[i] +
              std::string("\n");
          }
          TRI_SystemFree(demangled_name);
        }
      }
      else {
        btstr += strings[i] +
          std::string("\n");
      }
    }
    else {
      ss << stack_frames[i];
      btstr += ss.str() +
        std::string("\n");
    }
  }
  if (strings != nullptr) {
    TRI_SystemFree(strings);
  }
#endif
#endif
}

////////////////////////////////////////////////////////////////////////////////
/// @brief prints a backtrace on stderr
////////////////////////////////////////////////////////////////////////////////

void TRI_PrintBacktrace () {
#if HAVE_BACKTRACE
  std::string out;
  TRI_GetBacktrace(out);
  fprintf(stderr, "%s", out.c_str());
#endif
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>NULL => nullptr<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief debugging helpers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Basics/Common.h"
#include "Basics/locks.h"
#include "Basics/logging.h"

#ifdef TRI_ENABLE_MAINTAINER_MODE
#if HAVE_BACKTRACE

#include <execinfo.h>
#include <cxxabi.h>

#endif
#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief a global string containing the currently registered failure points
/// the string is a comma-separated list of point names
////////////////////////////////////////////////////////////////////////////////

static char* FailurePoints;

////////////////////////////////////////////////////////////////////////////////
/// @brief a read-write lock for thread-safe access to the failure-points list
////////////////////////////////////////////////////////////////////////////////

TRI_read_write_lock_t FailurePointsLock;

#ifdef TRI_ENABLE_FAILURE_TESTS

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief make a delimited value from a string, so we can unambigiously
/// search for it (e.g. searching for just "foo" would find "foo" and "foobar",
/// so we'll be putting the value inside some delimiter: ",foo,")
////////////////////////////////////////////////////////////////////////////////

static char* MakeValue (char const* value) {
  if (value == nullptr || strlen(value) == 0) {
    return nullptr;
  }

  char* delimited = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(value) + 3, false));

  if (delimited != nullptr) {
    memcpy(delimited + 1, value, strlen(value));
    delimited[0] = ',';
    delimited[strlen(value) + 1] = ',';
    delimited[strlen(value) + 2] = '\0';
  }

  return delimited;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief cause a segmentation violation
/// this is used for crash and recovery tests
////////////////////////////////////////////////////////////////////////////////

void TRI_SegfaultDebugging (char const* message) {
  LOG_WARNING("%s: summon Baal!", message);
  // make sure the latest log messages are flushed
  TRI_ShutdownLogging(true);

  // and now crash
#ifndef __APPLE__
  // on MacOS, the following statement makes the server hang but not crash
  *((char*) -1) = '!';
#endif

  // ensure the process is terminated
  abort();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief check whether we should fail at a specific failure point
////////////////////////////////////////////////////////////////////////////////

bool TRI_ShouldFailDebugging (char const* value) {
  char* found = nullptr;

  // try without the lock first (to speed things up)
  if (FailurePoints == nullptr) {
    return false;
  }

  TRI_ReadLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints != nullptr) {
    char* checkValue = MakeValue(value);

    if (checkValue != nullptr) {
      found = strstr(FailurePoints, checkValue);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
    }
  }

  TRI_ReadUnlockReadWriteLock(&FailurePointsLock);

  return (found != nullptr);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add a failure point
////////////////////////////////////////////////////////////////////////////////

void TRI_AddFailurePointDebugging (char const* value) {
  char* found;
  char* checkValue;

  checkValue = MakeValue(value);

  if (checkValue == nullptr) {
    return;
  }

  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints == nullptr) {
    found = nullptr;
  }
  else {
    found = strstr(FailurePoints, checkValue);
  }

  if (found == nullptr) {
    // not yet found. so add it
    char* copy;
    size_t n;

    LOG_WARNING("activating intentional failure point '%s'. the server will misbehave!", value);
    n = strlen(checkValue);

    if (FailurePoints == nullptr) {
      copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, n + 1, false));

      if (copy == nullptr) {
        TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
        TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
        return;
      }

      memcpy(copy, checkValue, n);
      copy[n] = '\0';
    }
    else {
      copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, n + strlen(FailurePoints), false));

      if (copy == nullptr) {
        TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
        TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
        return;
      }

      memcpy(copy, FailurePoints, strlen(FailurePoints));
      memcpy(copy + strlen(FailurePoints) - 1, checkValue, n);
      copy[strlen(FailurePoints) + n - 1] = '\0';
    }

    FailurePoints = copy;
  }

  TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
  TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief remove a failure points
////////////////////////////////////////////////////////////////////////////////

void TRI_RemoveFailurePointDebugging (char const* value) {
  char* checkValue;

  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints == nullptr) {
    TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
    return;
  }

  checkValue = MakeValue(value);

  if (checkValue != nullptr) {
    char* found;
    char* copy;
    size_t n;

    found = strstr(FailurePoints, checkValue);

    if (found == nullptr) {
      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    if (strlen(FailurePoints) - strlen(checkValue) <= 2) {
      TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
      FailurePoints = nullptr;

      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    copy = static_cast<char*>(TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(FailurePoints) - strlen(checkValue) + 2, false));

    if (copy == nullptr) {
      TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
      TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
      return;
    }

    // copy start of string
    n = found - FailurePoints;
    memcpy(copy, FailurePoints, n);

    // copy remainder of string
    memcpy(copy + n, found + strlen(checkValue) - 1, strlen(FailurePoints) - strlen(checkValue) - n + 1);

    copy[strlen(FailurePoints) - strlen(checkValue) + 1] = '\0';
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
    FailurePoints = copy;

    TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
    TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief clear all failure points
////////////////////////////////////////////////////////////////////////////////

void TRI_ClearFailurePointsDebugging () {
  TRI_WriteLockReadWriteLock(&FailurePointsLock);

  if (FailurePoints != nullptr) {
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
  }

  FailurePoints = nullptr;

  TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the debugging
////////////////////////////////////////////////////////////////////////////////

void TRI_InitialiseDebugging () {
  FailurePoints = nullptr;
  TRI_InitReadWriteLock(&FailurePointsLock);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief shutdown the debugging
////////////////////////////////////////////////////////////////////////////////

void TRI_ShutdownDebugging () {
  if (FailurePoints != nullptr) {
    TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
  }

  FailurePoints = nullptr;

  TRI_DestroyReadWriteLock(&FailurePointsLock);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief appends a backtrace to the string provided
////////////////////////////////////////////////////////////////////////////////

void TRI_GetBacktrace (std::string& btstr) {
#if HAVE_BACKTRACE
#ifdef _WIN32
  void         * stack[100];
  unsigned short frames;
  SYMBOL_INFO  * symbol;
  HANDLE         process;

  process = GetCurrentProcess();

  SymInitialize(process, nullptr, true);

  frames               = CaptureStackBackTrace(0, 100, stack, nullptr);
  symbol               = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);

  if (symbol == nullptr) {
    // cannot allocate memory
    return;
  }

  symbol->MaxNameLen   = 255;
  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

  for (unsigned int i = 0; i < frames; i++) {
    char address[64];
    SymFromAddr(process, (DWORD64) stack[i], 0, symbol);

    snprintf(address, sizeof(address), "0x%0X", symbol->Address);
    bstr += std::string(frames - i - 1) + std::string(": ") + symbol->Name + std::string(" [") + address + std::string("]\n");
  }

  TRI_SystemFree(symbol);

#else
  void* stack_frames[50];
  size_t size, i;
  char** strings;

  size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
  strings = backtrace_symbols(stack_frames, size);
  for (i = 0; i < size; i++) {
    std::stringstream ss;
    if (strings != nullptr) {
      char *mangled_name = nullptr, *offset_begin = nullptr, *offset_end = nullptr;

      // find parantheses and +address offset surrounding mangled name
      for (char *p = strings[i]; *p; ++p) {
        if (*p == '(') {
          mangled_name = p;
        }
        else if (*p == '+') {
          offset_begin = p;
        }
        else if (*p == ')') {
          offset_end = p;
          break;
        }
      }

      // if the line could be processed, attempt to demangle the symbol
      if (mangled_name && offset_begin && offset_end &&
          mangled_name < offset_begin) {
        *mangled_name++ = '\0';
        *offset_begin++ = '\0';
        *offset_end++ = '\0';
        int status = 0;
        char * demangled_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);

        if (demangled_name != nullptr) {
          if (status == 0) {
            ss << stack_frames[i];
            btstr +=  strings[i] +
              std::string("() [") +
              ss.str() +
              std::string("] ") +
              demangled_name +
              std::string("\n");
          }
          else {
            btstr += strings[i] +
              std::string("\n");
          }
          TRI_SystemFree(demangled_name);
        }
      }
      else {
        btstr += strings[i] +
          std::string("\n");
      }
    }
    else {
      ss << stack_frames[i];
      btstr += ss.str() +
        std::string("\n");
    }
  }
  if (strings != nullptr) {
    TRI_SystemFree(strings);
  }
#endif
#endif
}

////////////////////////////////////////////////////////////////////////////////
/// @brief prints a backtrace on stderr
////////////////////////////////////////////////////////////////////////////////

void TRI_PrintBacktrace () {
#if HAVE_BACKTRACE
  std::string out;
  TRI_GetBacktrace(out);
  fprintf(stderr, "%s", out.c_str());
#endif
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before><commit_msg>fix sibcoin help dialog<commit_after><|endoftext|>


<commit_before>//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/ASTConsumers.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
using namespace clang;
using namespace llvm;

namespace {
  class BackendConsumer : public ASTConsumer {
    Diagnostic &Diags;
    BackendAction Action;
    const CodeGenOptions &CodeGenOpts;
    const LangOptions &LangOpts;
    const TargetOptions &TargetOpts;
    llvm::raw_ostream *AsmOutStream;
    llvm::formatted_raw_ostream FormattedOutStream;
    ASTContext *Context;

    Timer LLVMIRGeneration;
    Timer CodeGenerationTime;

    llvm::OwningPtr<CodeGenerator> Gen;

    llvm::Module *TheModule;
    llvm::TargetData *TheTargetData;

    mutable llvm::ModuleProvider *ModuleProvider;
    mutable FunctionPassManager *CodeGenPasses;
    mutable PassManager *PerModulePasses;
    mutable FunctionPassManager *PerFunctionPasses;

    FunctionPassManager *getCodeGenPasses() const;
    PassManager *getPerModulePasses() const;
    FunctionPassManager *getPerFunctionPasses() const;

    void CreatePasses();

    /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
    ///
    /// \return True on success.
    bool AddEmitPasses();

    void EmitAssembly();

  public:
    BackendConsumer(BackendAction action, Diagnostic &_Diags,
                    const LangOptions &langopts, const CodeGenOptions &compopts,
                    const TargetOptions &targetopts, bool TimePasses,
                    const std::string &infile, llvm::raw_ostream *OS,
                    LLVMContext& C) :
      Diags(_Diags),
      Action(action),
      CodeGenOpts(compopts),
      LangOpts(langopts),
      TargetOpts(targetopts),
      AsmOutStream(OS),
      LLVMIRGeneration("LLVM IR Generation Time"),
      CodeGenerationTime("Code Generation Time"),
      Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
      TheModule(0), TheTargetData(0), ModuleProvider(0),
      CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {

      if (AsmOutStream)
        FormattedOutStream.setStream(*AsmOutStream,
                                     formatted_raw_ostream::PRESERVE_STREAM);

      llvm::TimePassesIsEnabled = TimePasses;
    }

    ~BackendConsumer() {
      delete TheTargetData;
      delete ModuleProvider;
      delete CodeGenPasses;
      delete PerModulePasses;
      delete PerFunctionPasses;
    }

    virtual void Initialize(ASTContext &Ctx) {
      Context = &Ctx;

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.startTimer();

      Gen->Initialize(Ctx);

      TheModule = Gen->GetModule();
      ModuleProvider = new ExistingModuleProvider(TheModule);
      TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTopLevelDecl(DeclGroupRef D) {
      PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.startTimer();

      Gen->HandleTopLevelDecl(D);

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTranslationUnit(ASTContext &C) {
      {
        PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
        if (llvm::TimePassesIsEnabled)
          LLVMIRGeneration.startTimer();

        Gen->HandleTranslationUnit(C);

        if (llvm::TimePassesIsEnabled)
          LLVMIRGeneration.stopTimer();
      }

      // EmitAssembly times and registers crash info itself.
      EmitAssembly();

      // Force a flush here in case we never get released.
      if (AsmOutStream)
        FormattedOutStream.flush();
    }

    virtual void HandleTagDeclDefinition(TagDecl *D) {
      PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");
      Gen->HandleTagDeclDefinition(D);
    }

    virtual void CompleteTentativeDefinition(VarDecl *D) {
      Gen->CompleteTentativeDefinition(D);
    }
  };
}

FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
  if (!CodeGenPasses) {
    CodeGenPasses = new FunctionPassManager(ModuleProvider);
    CodeGenPasses->add(new TargetData(*TheTargetData));
  }

  return CodeGenPasses;
}

PassManager *BackendConsumer::getPerModulePasses() const {
  if (!PerModulePasses) {
    PerModulePasses = new PassManager();
    PerModulePasses->add(new TargetData(*TheTargetData));
  }

  return PerModulePasses;
}

FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
  if (!PerFunctionPasses) {
    PerFunctionPasses = new FunctionPassManager(ModuleProvider);
    PerFunctionPasses->add(new TargetData(*TheTargetData));
  }

  return PerFunctionPasses;
}

bool BackendConsumer::AddEmitPasses() {
  if (Action == Backend_EmitNothing)
    return true;

  if (Action == Backend_EmitBC) {
    getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream));
  } else if (Action == Backend_EmitLL) {
    getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
  } else {
    bool Fast = CodeGenOpts.OptimizationLevel == 0;

    // Create the TargetMachine for generating code.
    std::string Error;
    std::string Triple = TheModule->getTargetTriple();
    const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
    if (!TheTarget) {
      Diags.Report(diag::err_fe_unable_to_create_target) << Error;
      return false;
    }

    // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
    // being gross, this is also totally broken if we ever care about
    // concurrency.
    std::vector<const char *> BackendArgs;
    BackendArgs.push_back("clang"); // Fake program name.
    if (CodeGenOpts.AsmVerbose)
      BackendArgs.push_back("-asm-verbose");
    if (!CodeGenOpts.CodeModel.empty()) {
      BackendArgs.push_back("-code-model");
      BackendArgs.push_back(CodeGenOpts.CodeModel.c_str());
    }
    if (!CodeGenOpts.DebugPass.empty()) {
      BackendArgs.push_back("-debug-pass");
      BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
    }
    if (CodeGenOpts.DisableFPElim)
      BackendArgs.push_back("-disable-fp-elim");
    if (!CodeGenOpts.FloatABI.empty()) {
      BackendArgs.push_back("-float-abi");
      BackendArgs.push_back(CodeGenOpts.FloatABI.c_str());
    }
    if (!CodeGenOpts.LimitFloatPrecision.empty()) {
      BackendArgs.push_back("-limit-float-precision");
      BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
    }
    if (CodeGenOpts.NoZeroInitializedInBSS)
      BackendArgs.push_back("-nozero-initialized-in-bss");
    if (CodeGenOpts.SoftFloat)
      BackendArgs.push_back("-soft-float");
    BackendArgs.push_back("-relocation-model");
    BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str());
    if (llvm::TimePassesIsEnabled)
      BackendArgs.push_back("-time-passes");
    if (CodeGenOpts.UnwindTables)
      BackendArgs.push_back("-unwind-tables");
    BackendArgs.push_back(0);
    llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
                                      (char**) &BackendArgs[0]);

    std::string FeaturesStr;
    if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
      SubtargetFeatures Features;
      Features.setCPU(TargetOpts.CPU);
      for (std::vector<std::string>::const_iterator
             it = TargetOpts.Features.begin(),
             ie = TargetOpts.Features.end(); it != ie; ++it)
        Features.AddFeature(*it);
      FeaturesStr = Features.getString();
    }
    TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);

    // Set register scheduler & allocation policy.
    RegisterScheduler::setDefault(createDefaultScheduler);
    RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
                                 createLinearScanRegisterAllocator);

    // From llvm-gcc:
    // If there are passes we have to run on the entire module, we do codegen
    // as a separate "pass" after that happens.
    // FIXME: This is disabled right now until bugs can be worked out.  Reenable
    // this for fast -O0 compiles!
    FunctionPassManager *PM = getCodeGenPasses();
    CodeGenOpt::Level OptLevel = CodeGenOpt::Default;

    switch (CodeGenOpts.OptimizationLevel) {
    default: break;
    case 0: OptLevel = CodeGenOpt::None; break;
    case 3: OptLevel = CodeGenOpt::Aggressive; break;
    }

    // Normal mode, emit a .s file by running the code generator.
    // Note, this also adds codegenerator level optimization passes.
    switch (TM->addPassesToEmitFile(*PM, FormattedOutStream,
                                    TargetMachine::AssemblyFile, OptLevel)) {
    default:
    case FileModel::Error:
      Diags.Report(diag::err_fe_unable_to_interface_with_target);
      return false;
    case FileModel::AsmFile:
      break;
    }

    if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
                                      OptLevel)) {
      Diags.Report(diag::err_fe_unable_to_interface_with_target);
      return false;
    }
  }

  return true;
}

void BackendConsumer::CreatePasses() {
  unsigned OptLevel = CodeGenOpts.OptimizationLevel;
  CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (CodeGenOpts.DisableLLVMOpts) {
    OptLevel = 0;
    Inlining = CodeGenOpts.NoInlining;
  }

  // In -O0 if checking is disabled, we don't even have per-function passes.
  if (CodeGenOpts.VerifyModule)
    getPerFunctionPasses()->add(createVerifierPass());

  // Assume that standard function passes aren't run for -O0.
  if (OptLevel > 0)
    llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel);

  llvm::Pass *InliningPass = 0;
  switch (Inlining) {
  case CodeGenOptions::NoInlining: break;
  case CodeGenOptions::NormalInlining: {
    // Set the inline threshold following llvm-gcc.
    //
    // FIXME: Derive these constants in a principled fashion.
    unsigned Threshold = 200;
    if (CodeGenOpts.OptimizeSize)
      Threshold = 50;
    else if (OptLevel > 2)
      Threshold = 250;
    InliningPass = createFunctionInliningPass(Threshold);
    break;
  }
  case CodeGenOptions::OnlyAlwaysInlining:
    InliningPass = createAlwaysInlinerPass();         // Respect always_inline
    break;
  }

  // For now we always create per module passes.
  PassManager *PM = getPerModulePasses();
  llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
                                   CodeGenOpts.UnitAtATime,
                                   CodeGenOpts.UnrollLoops,
                                   /*SimplifyLibCalls=*/!LangOpts.NoBuiltin,
                                   /*HaveExceptions=*/true,
                                   InliningPass);
}

/// EmitAssembly - Handle interaction with LLVM backend to generate
/// actual machine code.
void BackendConsumer::EmitAssembly() {
  // Silently ignore if we weren't initialized for some reason.
  if (!TheModule || !TheTargetData)
    return;

  TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);

  // Make sure IR generation is happy with the module. This is
  // released by the module provider.
  Module *M = Gen->ReleaseModule();
  if (!M) {
    // The module has been released by IR gen on failures, do not
    // double free.
    ModuleProvider->releaseModule();
    TheModule = 0;
    return;
  }

  assert(TheModule == M && "Unexpected module change during IR generation");

  CreatePasses();
  if (!AddEmitPasses())
    return;

  // Run passes. For now we do all passes at once, but eventually we
  // would like to have the option of streaming code generation.

  if (PerFunctionPasses) {
    PrettyStackTraceString CrashInfo("Per-function optimization");

    PerFunctionPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        PerFunctionPasses->run(*I);
    PerFunctionPasses->doFinalization();
  }

  if (PerModulePasses) {
    PrettyStackTraceString CrashInfo("Per-module optimization passes");
    PerModulePasses->run(*M);
  }

  if (CodeGenPasses) {
    PrettyStackTraceString CrashInfo("Code generation");
    CodeGenPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        CodeGenPasses->run(*I);
    CodeGenPasses->doFinalization();
  }
}

ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
                                          Diagnostic &Diags,
                                          const LangOptions &LangOpts,
                                          const CodeGenOptions &CodeGenOpts,
                                          const TargetOptions &TargetOpts,
                                          bool TimePasses,
                                          const std::string& InFile,
                                          llvm::raw_ostream* OS,
                                          LLVMContext& C) {
  return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
                             TargetOpts, TimePasses, InFile, OS, C);
}
<commit_msg>Backend: Switch to using TargetOptions or TargetMachine to set some options instead of llvm::cl.<commit_after>//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/ASTConsumers.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
using namespace clang;
using namespace llvm;

namespace {
  class BackendConsumer : public ASTConsumer {
    Diagnostic &Diags;
    BackendAction Action;
    const CodeGenOptions &CodeGenOpts;
    const LangOptions &LangOpts;
    const TargetOptions &TargetOpts;
    llvm::raw_ostream *AsmOutStream;
    llvm::formatted_raw_ostream FormattedOutStream;
    ASTContext *Context;

    Timer LLVMIRGeneration;
    Timer CodeGenerationTime;

    llvm::OwningPtr<CodeGenerator> Gen;

    llvm::Module *TheModule;
    llvm::TargetData *TheTargetData;

    mutable llvm::ModuleProvider *ModuleProvider;
    mutable FunctionPassManager *CodeGenPasses;
    mutable PassManager *PerModulePasses;
    mutable FunctionPassManager *PerFunctionPasses;

    FunctionPassManager *getCodeGenPasses() const;
    PassManager *getPerModulePasses() const;
    FunctionPassManager *getPerFunctionPasses() const;

    void CreatePasses();

    /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
    ///
    /// \return True on success.
    bool AddEmitPasses();

    void EmitAssembly();

  public:
    BackendConsumer(BackendAction action, Diagnostic &_Diags,
                    const LangOptions &langopts, const CodeGenOptions &compopts,
                    const TargetOptions &targetopts, bool TimePasses,
                    const std::string &infile, llvm::raw_ostream *OS,
                    LLVMContext& C) :
      Diags(_Diags),
      Action(action),
      CodeGenOpts(compopts),
      LangOpts(langopts),
      TargetOpts(targetopts),
      AsmOutStream(OS),
      LLVMIRGeneration("LLVM IR Generation Time"),
      CodeGenerationTime("Code Generation Time"),
      Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
      TheModule(0), TheTargetData(0), ModuleProvider(0),
      CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {

      if (AsmOutStream)
        FormattedOutStream.setStream(*AsmOutStream,
                                     formatted_raw_ostream::PRESERVE_STREAM);

      llvm::TimePassesIsEnabled = TimePasses;
    }

    ~BackendConsumer() {
      delete TheTargetData;
      delete ModuleProvider;
      delete CodeGenPasses;
      delete PerModulePasses;
      delete PerFunctionPasses;
    }

    virtual void Initialize(ASTContext &Ctx) {
      Context = &Ctx;

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.startTimer();

      Gen->Initialize(Ctx);

      TheModule = Gen->GetModule();
      ModuleProvider = new ExistingModuleProvider(TheModule);
      TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTopLevelDecl(DeclGroupRef D) {
      PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.startTimer();

      Gen->HandleTopLevelDecl(D);

      if (llvm::TimePassesIsEnabled)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTranslationUnit(ASTContext &C) {
      {
        PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
        if (llvm::TimePassesIsEnabled)
          LLVMIRGeneration.startTimer();

        Gen->HandleTranslationUnit(C);

        if (llvm::TimePassesIsEnabled)
          LLVMIRGeneration.stopTimer();
      }

      // EmitAssembly times and registers crash info itself.
      EmitAssembly();

      // Force a flush here in case we never get released.
      if (AsmOutStream)
        FormattedOutStream.flush();
    }

    virtual void HandleTagDeclDefinition(TagDecl *D) {
      PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");
      Gen->HandleTagDeclDefinition(D);
    }

    virtual void CompleteTentativeDefinition(VarDecl *D) {
      Gen->CompleteTentativeDefinition(D);
    }
  };
}

FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
  if (!CodeGenPasses) {
    CodeGenPasses = new FunctionPassManager(ModuleProvider);
    CodeGenPasses->add(new TargetData(*TheTargetData));
  }

  return CodeGenPasses;
}

PassManager *BackendConsumer::getPerModulePasses() const {
  if (!PerModulePasses) {
    PerModulePasses = new PassManager();
    PerModulePasses->add(new TargetData(*TheTargetData));
  }

  return PerModulePasses;
}

FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
  if (!PerFunctionPasses) {
    PerFunctionPasses = new FunctionPassManager(ModuleProvider);
    PerFunctionPasses->add(new TargetData(*TheTargetData));
  }

  return PerFunctionPasses;
}

bool BackendConsumer::AddEmitPasses() {
  if (Action == Backend_EmitNothing)
    return true;

  if (Action == Backend_EmitBC) {
    getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream));
  } else if (Action == Backend_EmitLL) {
    getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
  } else {
    bool Fast = CodeGenOpts.OptimizationLevel == 0;

    // Create the TargetMachine for generating code.
    std::string Error;
    std::string Triple = TheModule->getTargetTriple();
    const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
    if (!TheTarget) {
      Diags.Report(diag::err_fe_unable_to_create_target) << Error;
      return false;
    }

    // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
    // being gross, this is also totally broken if we ever care about
    // concurrency.
    llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim;
    if (CodeGenOpts.FloatABI == "soft")
      llvm::FloatABIType = llvm::FloatABI::Soft;
    else if (CodeGenOpts.FloatABI == "hard")
      llvm::FloatABIType = llvm::FloatABI::Hard;
    else {
      assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
      llvm::FloatABIType = llvm::FloatABI::Default;
    }
    NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
    llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
    UnwindTablesMandatory = CodeGenOpts.UnwindTables;

    TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);

    // FIXME: Parse this earlier.
    if (CodeGenOpts.RelocationModel == "static") {
      TargetMachine::setRelocationModel(llvm::Reloc::Static);
    } else if (CodeGenOpts.RelocationModel == "pic") {
      TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
    } else {
      assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
             "Invalid PIC model!");
      TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
    }
    // FIXME: Parse this earlier.
    if (CodeGenOpts.CodeModel == "small") {
      TargetMachine::setCodeModel(llvm::CodeModel::Small);
    } else if (CodeGenOpts.CodeModel == "kernel") {
      TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
    } else if (CodeGenOpts.CodeModel == "medium") {
      TargetMachine::setCodeModel(llvm::CodeModel::Medium);
    } else if (CodeGenOpts.CodeModel == "large") {
      TargetMachine::setCodeModel(llvm::CodeModel::Large);
    } else {
      assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
      TargetMachine::setCodeModel(llvm::CodeModel::Default);
    }

    std::vector<const char *> BackendArgs;
    BackendArgs.push_back("clang"); // Fake program name.
    if (!CodeGenOpts.DebugPass.empty()) {
      BackendArgs.push_back("-debug-pass");
      BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
    }
    if (!CodeGenOpts.LimitFloatPrecision.empty()) {
      BackendArgs.push_back("-limit-float-precision");
      BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
    }
    if (llvm::TimePassesIsEnabled)
      BackendArgs.push_back("-time-passes");
    BackendArgs.push_back(0);
    llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
                                      (char**) &BackendArgs[0]);

    std::string FeaturesStr;
    if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
      SubtargetFeatures Features;
      Features.setCPU(TargetOpts.CPU);
      for (std::vector<std::string>::const_iterator
             it = TargetOpts.Features.begin(),
             ie = TargetOpts.Features.end(); it != ie; ++it)
        Features.AddFeature(*it);
      FeaturesStr = Features.getString();
    }
    TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);

    // Set register scheduler & allocation policy.
    RegisterScheduler::setDefault(createDefaultScheduler);
    RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
                                 createLinearScanRegisterAllocator);

    // From llvm-gcc:
    // If there are passes we have to run on the entire module, we do codegen
    // as a separate "pass" after that happens.
    // FIXME: This is disabled right now until bugs can be worked out.  Reenable
    // this for fast -O0 compiles!
    FunctionPassManager *PM = getCodeGenPasses();
    CodeGenOpt::Level OptLevel = CodeGenOpt::Default;

    switch (CodeGenOpts.OptimizationLevel) {
    default: break;
    case 0: OptLevel = CodeGenOpt::None; break;
    case 3: OptLevel = CodeGenOpt::Aggressive; break;
    }

    // Normal mode, emit a .s file by running the code generator.
    // Note, this also adds codegenerator level optimization passes.
    switch (TM->addPassesToEmitFile(*PM, FormattedOutStream,
                                    TargetMachine::AssemblyFile, OptLevel)) {
    default:
    case FileModel::Error:
      Diags.Report(diag::err_fe_unable_to_interface_with_target);
      return false;
    case FileModel::AsmFile:
      break;
    }

    if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
                                      OptLevel)) {
      Diags.Report(diag::err_fe_unable_to_interface_with_target);
      return false;
    }
  }

  return true;
}

void BackendConsumer::CreatePasses() {
  unsigned OptLevel = CodeGenOpts.OptimizationLevel;
  CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;

  // Handle disabling of LLVM optimization, where we want to preserve the
  // internal module before any optimization.
  if (CodeGenOpts.DisableLLVMOpts) {
    OptLevel = 0;
    Inlining = CodeGenOpts.NoInlining;
  }

  // In -O0 if checking is disabled, we don't even have per-function passes.
  if (CodeGenOpts.VerifyModule)
    getPerFunctionPasses()->add(createVerifierPass());

  // Assume that standard function passes aren't run for -O0.
  if (OptLevel > 0)
    llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel);

  llvm::Pass *InliningPass = 0;
  switch (Inlining) {
  case CodeGenOptions::NoInlining: break;
  case CodeGenOptions::NormalInlining: {
    // Set the inline threshold following llvm-gcc.
    //
    // FIXME: Derive these constants in a principled fashion.
    unsigned Threshold = 200;
    if (CodeGenOpts.OptimizeSize)
      Threshold = 50;
    else if (OptLevel > 2)
      Threshold = 250;
    InliningPass = createFunctionInliningPass(Threshold);
    break;
  }
  case CodeGenOptions::OnlyAlwaysInlining:
    InliningPass = createAlwaysInlinerPass();         // Respect always_inline
    break;
  }

  // For now we always create per module passes.
  PassManager *PM = getPerModulePasses();
  llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
                                   CodeGenOpts.UnitAtATime,
                                   CodeGenOpts.UnrollLoops,
                                   /*SimplifyLibCalls=*/!LangOpts.NoBuiltin,
                                   /*HaveExceptions=*/true,
                                   InliningPass);
}

/// EmitAssembly - Handle interaction with LLVM backend to generate
/// actual machine code.
void BackendConsumer::EmitAssembly() {
  // Silently ignore if we weren't initialized for some reason.
  if (!TheModule || !TheTargetData)
    return;

  TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);

  // Make sure IR generation is happy with the module. This is
  // released by the module provider.
  Module *M = Gen->ReleaseModule();
  if (!M) {
    // The module has been released by IR gen on failures, do not
    // double free.
    ModuleProvider->releaseModule();
    TheModule = 0;
    return;
  }

  assert(TheModule == M && "Unexpected module change during IR generation");

  CreatePasses();
  if (!AddEmitPasses())
    return;

  // Run passes. For now we do all passes at once, but eventually we
  // would like to have the option of streaming code generation.

  if (PerFunctionPasses) {
    PrettyStackTraceString CrashInfo("Per-function optimization");

    PerFunctionPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        PerFunctionPasses->run(*I);
    PerFunctionPasses->doFinalization();
  }

  if (PerModulePasses) {
    PrettyStackTraceString CrashInfo("Per-module optimization passes");
    PerModulePasses->run(*M);
  }

  if (CodeGenPasses) {
    PrettyStackTraceString CrashInfo("Code generation");
    CodeGenPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        CodeGenPasses->run(*I);
    CodeGenPasses->doFinalization();
  }
}

ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
                                          Diagnostic &Diags,
                                          const LangOptions &LangOpts,
                                          const CodeGenOptions &CodeGenOpts,
                                          const TargetOptions &TargetOpts,
                                          bool TimePasses,
                                          const std::string& InFile,
                                          llvm::raw_ostream* OS,
                                          LLVMContext& C) {
  return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
                             TargetOpts, TimePasses, InFile, OS, C);
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrStencilAndCoverPathRenderer.h"
#include "GrAAHairLinePathRenderer.h"
#include "GrAAConvexPathRenderer.h"
#include "GrAALinearizingConvexPathRenderer.h"
#include "GrAADistanceFieldPathRenderer.h"
#include "GrContext.h"
#include "GrDashLinePathRenderer.h"
#include "GrGpu.h"
#include "GrTessellatingPathRenderer.h"

#ifndef GR_TESSELLATING_PATH_RENDERING
#define GR_TESSELLATING_PATH_RENDERING 1
#endif

void GrPathRenderer::AddPathRenderers(GrContext* ctx, GrPathRendererChain* chain) {
    chain->addPathRenderer(SkNEW(GrDashLinePathRenderer))->unref();

    if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx->resourceProvider(),
                                                                   *ctx->caps())) {
        chain->addPathRenderer(pr)->unref();
    }
#if GR_TESSELLATING_PATH_RENDERING
    chain->addPathRenderer(new GrTessellatingPathRenderer)->unref();
#endif
    if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create()) {
        chain->addPathRenderer(pr)->unref();
    }
//    chain->addPathRenderer(SkNEW(GrAALinearizingConvexPathRenderer))->unref();
    chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
    chain->addPathRenderer(SkNEW_ARGS(GrAADistanceFieldPathRenderer, (ctx)))->unref();
}
<commit_msg>reenabled GrAALinearizingConvexPathRenderer, but only for stroked paths<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrStencilAndCoverPathRenderer.h"
#include "GrAAHairLinePathRenderer.h"
#include "GrAAConvexPathRenderer.h"
#include "GrAALinearizingConvexPathRenderer.h"
#include "GrAADistanceFieldPathRenderer.h"
#include "GrContext.h"
#include "GrDashLinePathRenderer.h"
#include "GrGpu.h"
#include "GrTessellatingPathRenderer.h"

#ifndef GR_TESSELLATING_PATH_RENDERING
#define GR_TESSELLATING_PATH_RENDERING 1
#endif

void GrPathRenderer::AddPathRenderers(GrContext* ctx, GrPathRendererChain* chain) {
    chain->addPathRenderer(SkNEW(GrDashLinePathRenderer))->unref();

    if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx->resourceProvider(),
                                                                   *ctx->caps())) {
        chain->addPathRenderer(pr)->unref();
    }
#if GR_TESSELLATING_PATH_RENDERING
    chain->addPathRenderer(new GrTessellatingPathRenderer)->unref();
#endif
    if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create()) {
        chain->addPathRenderer(pr)->unref();
    }
    chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
    chain->addPathRenderer(SkNEW(GrAALinearizingConvexPathRenderer))->unref();
    chain->addPathRenderer(SkNEW_ARGS(GrAADistanceFieldPathRenderer, (ctx)))->unref();
}
<|endoftext|>


<commit_before>#include <vector>
#include <iostream>
#include <assert.h>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <map>
#include <set>

#define FAIL 0
#define START 1
#define ALPHABET_SIZE 26
#define MAX_S 30
#define DEBUG cout << "DEBUG" << endl

using namespace std;

typedef std::vector<std::string> vs;
typedef std::vector<int> vi;

int fail[MAX_S];
int go_to[MAX_S][ALPHABET_SIZE];
set<int> occ[MAX_S];

void print_goto()
{
    cout << "  ";
    for (int i=0; i < ALPHABET_SIZE; ++i) {
        char tmp = i+'a';
        cout << tmp << " ";
    }
    cout << endl;
    for (int i=0; i < MAX_S; ++i) {
        cout << i%10 << " ";
        for (int j=0; j < ALPHABET_SIZE; ++j) {
            cout << go_to[i][j] << " ";
        }
        cout << endl;
    }
}

void print_fail()
{
    cout << "--FAIL--" << endl;
    for (int i=0; i < MAX_S; ++i) {
        cout << i << "\t" << fail[i] << endl;
    }
    cout << "--FAIL--" << endl;
}

void build_goto(const vs &patterns) {
    memset(go_to, 0, sizeof go_to);

    int curr = START;
    int state = 2;
    for (int i=0; i < patterns.size(); ++i) {
        curr = START;
        string pat = patterns[i];
        for (int j=0; j < pat.size(); ++j) {
            int key = pat[j]-'a';
            if (go_to[curr][key] == FAIL) {
                go_to[curr][key] = state;
                state += 1;
            }
            curr = go_to[curr][key];
        }
        occ[curr].insert(i+1);
    }
}

void build_fail(const vs &patterns) {

    queue<int> q;
    for (int a=0; a < ALPHABET_SIZE; ++a) {
        int s = go_to[START][a];
        if (s != FAIL) {
            q.push(s);
            fail[s] = FAIL;
        }
    }

    while (!q.empty()) {
        int r = q.front(); q.pop();
        for (int a=0; a < ALPHABET_SIZE; ++a) {
            int s = go_to[r][a];
            int u = r;
            if (s != FAIL) {
                q.push(s);
                int state = fail[r];
                while (u != FAIL && go_to[state][a] == FAIL)
                    u = fail[u];
                fail[u] = (u == START) ? START : go_to[fail[u]][a];
                occ[s].insert(occ[fail[s]].begin(), occ[fail[s]].end());
            }
        }
    }
}

void build_fsm(const vs &patterns) {
    build_goto(patterns);
    build_fail(patterns);
}

void aho_corasick(const vs &patterns, const string &text){
    int state = START;
    for (int i=0; i < text.length(); ++i) {
        int a_i = text[i]-'a';
        while (go_to[state][a_i] == FAIL && state != FAIL)
            state = fail[state];
        state = (state == FAIL) ? START : go_to[state][a_i];
        if (!occ[state].empty()) {
            for (set<int>::iterator it = occ[state].begin();
                    it != occ[state].end(); ++it)
            {
                int o = patterns[(*it)-1].length();
                cout << i-o+1 << " " << patterns[(*it)-1] << endl;
            }
        }
    }
}

int main() {
    vs pats;
    pats.push_back("she"); pats.push_back("som"); pats.push_back("he");
    pats.push_back("hers");
    build_fsm(pats);
    string text = "guilhermepalmapeixoto";
    aho_corasick(pats, text);
    return 0;
}
<commit_msg>working optmized version of aho-corasick<commit_after>#include <vector>
#include <iostream>
#include <assert.h>
#include <string>
#include <queue>
#include <set>

#define FAIL 0
#define START 1
#define MIN_CHAR 32
#define MAX_CHAR 126
#define SIZE MAX_CHAR - MIN_CHAR
#define MAX_ST 30

using namespace std;

typedef vector<string> vs;
typedef vector<int> vi;
typedef pair<string, int> psi;
typedef vector<psi> v_psi;

int fail[MAX_ST];
int go_to[MAX_ST][SIZE];
set<string> occ[MAX_ST];

void build_goto(const vs &patterns) {
    memset(go_to, FAIL, sizeof go_to);
    int newstate = START;
    for (string pat : patterns)
    {
        int state = START;
        int j = 0;
        int pat_j = pat[j] - MIN_CHAR;

        while (j < pat.length() && go_to[state][pat_j] != FAIL)
        {
            state = go_to[state][pat_j];
            j += 1;
            pat_j = pat[j] - MIN_CHAR;
        }

        while (j < pat.length())
        {
            newstate += 1;
            pat_j = pat[j] - MIN_CHAR;
            go_to[state][pat_j] = newstate;
            state = newstate;
            j += 1;
        }
        occ[state].insert(pat);
    }

    for (int a=0; a < SIZE; ++a)
        if (go_to[START][a] == FAIL)
            go_to[START][a] = START;
}

void build_fail(const vs &patterns) {
    queue<int> q;
    for (int a=0; a < SIZE; ++a)
    {
        if (go_to[START][a] != START) {
            q.push(go_to[START][a]);
            fail[go_to[START][a]] = START;
        }
    }

    while (!q.empty())
    {
        int cur = q.front(); q.pop();
        for (int a=0; a < SIZE; ++a)
        {
            if (go_to[cur][a] != FAIL) {
                int nextnode = go_to[cur][a];
                q.push(go_to[cur][a]);
                int brd = fail[cur];
                while (go_to[brd][a] == FAIL)
                    brd = fail[brd];
                fail[nextnode] = go_to[brd][a];
                set<string>::iterator it = occ[fail[nextnode]].begin();
                while (it != occ[fail[nextnode]].end())
                {
                    occ[nextnode].insert(*it);
                    ++it;
                }
            }
        }
    }
}

void build_fsm(const vs &patterns) {
    build_goto(patterns);
    build_fail(patterns);
}

v_psi aho_corasick(const vs &patterns, const string &text) {
    int cur = START;
    v_psi occs;
    for (int i=0; i < text.length(); ++i)
    {
        int a = text[i] - MIN_CHAR;
        while (go_to[cur][a] == FAIL){
            cur = fail[cur];
        }
        cur = go_to[cur][a];
        set<string>::iterator it = occ[cur].begin();
        while (it != occ[cur].end())
        {
            occs.push_back(psi(*it, i-(*it).length()+1));
            ++it;
        }
    }
    return occs;
}

void print_results(const v_psi &occs, const string &text) {
    for (int i=0; i < text.length(); ++i)
    {
        string prt = ((i/10)>0 && i%10==0) ? to_string(char(i/10)) : " ";
        cout << prt;
    }
    cout << endl;

    for (int i=0; i < text.length(); ++i)
        cout << i%10;

    cout << endl;
    cout << text << endl << endl;
    for (psi pat_pos : occs)
    {
        cout << pat_pos.first << " " << pat_pos.second << endl;
    }
}

int main() {
    vs pats;
    pats.push_back("sit");
    pats.push_back("sect");
    pats.push_back("...");
    pats.push_back("dolor");
    pats.push_back(" dolor ");
    pats.push_back("r s");
    pats.push_back(",");
    build_fsm(pats);

    string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit...";
    v_psi occs = aho_corasick(pats, text);

    print_results(occs, text);
    return 0;
}

<|endoftext|>


<commit_before><commit_msg>Allow upper case in pinyin<commit_after><|endoftext|>


<commit_before>//
// ulib - a collection of useful classes
// Copyright (C) 2008-2020 Michael Fink
//
/// \file Win7Taskbar.hpp Windows 7 Taskbar classes
//
#pragma once

#include <memory>

namespace Win32
{
   class TaskbarImpl;

   /// Taskbar progress bar access
   class TaskbarProgressBar
   {
   public:
      /// state of task bar progress bar
      enum TaskbarProgressBarState
      {
         TBPF_NOPROGRESS = 0,
         TBPF_INDETERMINATE = 0x1,
         TBPF_NORMAL = 0x2,
         TBPF_ERROR = 0x4,
         TBPF_PAUSED = 0x8
      };

      /// copy ctor; not available
      TaskbarProgressBar(const TaskbarProgressBar&) = delete;

      // move ctor; not available
      TaskbarProgressBar(TaskbarProgressBar&&) = delete;

      /// dtor; returns progress to "none"
      ~TaskbarProgressBar()
      {
         SetState(TBPF_NOPROGRESS);
      }

      /// copy assignment operator; not available
      TaskbarProgressBar& operator=(const TaskbarProgressBar&) = delete;

      /// move assignment operator; not available
      TaskbarProgressBar& operator=(TaskbarProgressBar&&) = delete;

      /// sets new progress bar state
      void SetState(TaskbarProgressBarState state);

      /// sets new progress bar position
      void SetPos(UINT currentPos, UINT maxPos);

   private:
      friend class Taskbar;

      /// ctor; can only be called from Taskbar
      explicit TaskbarProgressBar(const std::shared_ptr<TaskbarImpl>& impl)
         :m_impl(impl)
      {
         SetState(TBPF_INDETERMINATE);
      }

   private:
      /// implementation
      std::shared_ptr<TaskbarImpl> m_impl;
   };

   /// Windows 7 taskbar access
   class Taskbar
   {
   public:
      /// accesses task bar; uses task bar icon associated with given window
      explicit Taskbar(HWND hwnd);

      /// returns if task bar is available (Windows 7 and higher)
      bool IsAvailable() const;

      /// dtor
      ~Taskbar()
      {
         // nothing to cleanup
      }

      TaskbarProgressBar OpenProgressBar()
      {
         ATLASSERT(IsAvailable());
         return TaskbarProgressBar(m_impl);
      }

   private:
      std::shared_ptr<TaskbarImpl> m_impl;
   };

} // namespace Win32
<commit_msg>removed deleted TaskbarProgressBar ctors and assignment operatos so that it can be stored in std::optional<commit_after>//
// ulib - a collection of useful classes
// Copyright (C) 2008-2020 Michael Fink
//
/// \file Win7Taskbar.hpp Windows 7 Taskbar classes
//
#pragma once

#include <memory>

namespace Win32
{
   class TaskbarImpl;

   /// Taskbar progress bar access
   class TaskbarProgressBar
   {
   public:
      /// state of task bar progress bar
      enum TaskbarProgressBarState
      {
         TBPF_NOPROGRESS = 0,
         TBPF_INDETERMINATE = 0x1,
         TBPF_NORMAL = 0x2,
         TBPF_ERROR = 0x4,
         TBPF_PAUSED = 0x8
      };

      /// dtor; returns progress to "none"
      ~TaskbarProgressBar()
      {
         SetState(TBPF_NOPROGRESS);
      }

      /// sets new progress bar state
      void SetState(TaskbarProgressBarState state);

      /// sets new progress bar position
      void SetPos(UINT currentPos, UINT maxPos);

   private:
      friend class Taskbar;

      /// ctor; can only be called from Taskbar
      explicit TaskbarProgressBar(const std::shared_ptr<TaskbarImpl>& impl)
         :m_impl(impl)
      {
         SetState(TBPF_INDETERMINATE);
      }

   private:
      /// implementation
      std::shared_ptr<TaskbarImpl> m_impl;
   };

   /// Windows 7 taskbar access
   class Taskbar
   {
   public:
      /// accesses task bar; uses task bar icon associated with given window
      explicit Taskbar(HWND hwnd);

      /// returns if task bar is available (Windows 7 and higher)
      bool IsAvailable() const;

      /// dtor
      ~Taskbar()
      {
         // nothing to cleanup
      }

      TaskbarProgressBar OpenProgressBar()
      {
         ATLASSERT(IsAvailable());
         return TaskbarProgressBar(m_impl);
      }

   private:
      std::shared_ptr<TaskbarImpl> m_impl;
   };

} // namespace Win32
<|endoftext|>