<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/user_data_manager.h"

#include <string>

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"

#if defined(OS_WIN)
#include <windows.h>
#include "chrome/installer/util/shell_util.h"
#endif

namespace {

// Helper to start chrome for a given profile index. The helper takes care of
// enumerating profiles on the file thread and then it launches Chrome for the
// appropriate profile on the original thread.
// An instance of this class should always be created on the heap, and it will
// delete itself when the launch is done.
class LaunchChromeForProfileIndexHelper : GetProfilesHelper::Delegate {
 public:
  // Creates an instance with the given data manager and to launch chrome for
  // the profile with the given index.
  LaunchChromeForProfileIndexHelper(const UserDataManager* manager, int index);
  virtual ~LaunchChromeForProfileIndexHelper();

  // Starts the asynchronous launch.
  void StartLaunch();

  // GetProfilesHelper::Delegate method.
  void OnGetProfilesDone(const std::vector<std::wstring>& profiles);

 private:
  int index_;
  const UserDataManager* manager_;
  scoped_refptr<GetProfilesHelper> profiles_helper_;

  DISALLOW_COPY_AND_ASSIGN(LaunchChromeForProfileIndexHelper);
};

}  // namespace

LaunchChromeForProfileIndexHelper::LaunchChromeForProfileIndexHelper(
    const UserDataManager* manager,
    int index)
    : index_(index),
      manager_(manager),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          profiles_helper_(new GetProfilesHelper(this))) {
  DCHECK(manager);
}

LaunchChromeForProfileIndexHelper::~LaunchChromeForProfileIndexHelper() {
  profiles_helper_->OnDelegateDeleted();
}

void LaunchChromeForProfileIndexHelper::StartLaunch() {
  profiles_helper_->GetProfiles(NULL);
}

void LaunchChromeForProfileIndexHelper::OnGetProfilesDone(
    const std::vector<std::wstring>& profiles) {
  if (index_ >= 0 && index_ < static_cast<int>(profiles.size()))
    manager_->LaunchChromeForProfile(profiles[index_]);

  // We are done, delete ourselves.
  delete this;
}

// Separator used in folder names between the prefix and the profile name.
// For e.g. a folder for the profile "Joe" would be named "User Data-Joe".
static const wchar_t kProfileFolderSeparator[] = L"-";

// static
UserDataManager* UserDataManager::instance_ = NULL;

// static
UserDataManager* UserDataManager::Create() {
  DCHECK(!instance_);
  std::wstring user_data;
  PathService::Get(chrome::DIR_USER_DATA, &user_data);
  instance_ = new UserDataManager(user_data);
  return instance_;
}

// static
UserDataManager* UserDataManager::Get() {
  DCHECK(instance_);
  return instance_;
}

UserDataManager::UserDataManager(const std::wstring& user_data_root)
    : user_data_root_(user_data_root) {
  // Determine current profile name and current folder name.
  current_folder_name_ = file_util::GetFilenameFromPath(user_data_root);
  bool success = GetProfileNameFromFolderName(current_folder_name_,
                                              &current_profile_name_);
  // The current profile is a default profile if the current user data folder
  // name is just kUserDataDirname or when the folder name doesn't have the
  // kUserDataDirname as prefix.
  is_current_profile_default_ =
      !success || (current_folder_name_ == chrome::kUserDataDirname);

  // (TODO:munjal) Fix issue 5070:
  // http://code.google.com/p/chromium/issues/detail?id=5070

  file_util::UpOneDirectory(&user_data_root_);
}

UserDataManager::~UserDataManager() {
  if (instance_ == this)
    instance_ = NULL;
}

// static
bool UserDataManager::GetProfileNameFromFolderName(
    const std::wstring& folder_name,
    std::wstring* profile_name) {
  // The folder name should start with a specific prefix for it to be a valid
  // profile folder.
  if (folder_name.find(chrome::kUserDataDirname) != 0)
    return false;

  // Seems like we cannot use arraysize macro for externally defined constants.
  // Is there a way?
  unsigned int prefix_length = wcslen(chrome::kUserDataDirname);
  // Subtract 1 from the size of the array for trailing null character.
  unsigned int separator_length = arraysize(kProfileFolderSeparator) - 1;

  // It's safe to use profile_name variable for intermediate values since we
  // will always return true now.
  *profile_name = folder_name.substr(prefix_length);
  // Remove leading separator if present.
  if (profile_name->find_first_of(kProfileFolderSeparator) == 0)
    *profile_name = profile_name->substr(separator_length);

  if (profile_name->empty())
    *profile_name = chrome::kNotSignedInProfile;

  return true;
}

// static
std::wstring UserDataManager::GetFolderNameFromProfileName(
    const std::wstring& profile_name) {
  std::wstring folder_name = chrome::kUserDataDirname;
  if (profile_name != chrome::kNotSignedInProfile) {
    folder_name += kProfileFolderSeparator;
    folder_name += profile_name;
  }
  return folder_name;
}

std::wstring UserDataManager::GetUserDataFolderForProfile(
    const std::wstring& profile_name) const {
  std::wstring folder_name = GetFolderNameFromProfileName(profile_name);
  std::wstring folder_path(user_data_root_);
  file_util::AppendToPath(&folder_path, folder_name);
  return folder_path;
}

void UserDataManager::LaunchChromeForProfile(
    const std::wstring& profile_name) const {
  std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
  std::wstring command;
  PathService::Get(base::FILE_EXE, &command);
  CommandLine command_line(command);
  command_line.AppendSwitch(switches::kEnableUserDataDirProfiles);
  command_line.AppendSwitchWithValue(switches::kUserDataDir,
                                     user_data_dir);
  std::wstring local_state_path;
  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
  command_line.AppendSwitchWithValue(switches::kParentProfile,
                                     local_state_path);
  base::LaunchApp(command_line, false, false, NULL);
}

void UserDataManager::LaunchChromeForProfile(int index) const {
  // Helper deletes itself when done.
  LaunchChromeForProfileIndexHelper* helper =
      new LaunchChromeForProfileIndexHelper(this, index);
  helper->StartLaunch();
}

void UserDataManager::GetProfiles(std::vector<std::wstring>* profiles) const {
  // This function should be called on the file thread.
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));
  file_util::FileEnumerator file_enum(
      FilePath::FromWStringHack(user_data_root_),
      false, file_util::FileEnumerator::DIRECTORIES);
  std::wstring folder_name;
  while (!(folder_name = file_enum.Next().ToWStringHack()).empty()) {
    folder_name = file_util::GetFilenameFromPath(folder_name);
    std::wstring profile_name;
    if (GetProfileNameFromFolderName(folder_name, &profile_name))
      profiles->push_back(profile_name);
  }
}

bool UserDataManager::CreateDesktopShortcutForProfile(
    const std::wstring& profile_name) const {
#if defined(OS_WIN)
  std::wstring exe_path;
  std::wstring shortcut_path;
  if (!PathService::Get(base::FILE_EXE, &exe_path) ||
      !ShellUtil::GetDesktopPath(false, &shortcut_path))
    return false;

  // Working directory.
  std::wstring exe_folder = file_util::GetDirectoryFromPath(exe_path);

  // Command and arguments.
  std::wstring cmd;
  cmd = StringPrintf(L"\"%ls\"", exe_path.c_str());
  std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
  std::wstring args = CommandLine::PrefixedSwitchStringWithValue(
      switches::kUserDataDir,
      user_data_dir);
  args = StringPrintf(L"\"%ls\"", args.c_str());

  // Shortcut path.
  std::wstring shortcut_name = l10n_util::GetStringF(
      IDS_START_IN_PROFILE_SHORTCUT_NAME,
      profile_name);
  shortcut_name.append(L".lnk");
  file_util::AppendToPath(&shortcut_path, shortcut_name);

  return file_util::CreateShortcutLink(cmd.c_str(),
                                       shortcut_path.c_str(),
                                       exe_folder.c_str(),
                                       args.c_str(),
                                       NULL,
                                       exe_path.c_str(),
                                       0);
#else
  // TODO(port): should probably use freedesktop.org standard for desktop files.
  NOTIMPLEMENTED();
  return false;
#endif
}

GetProfilesHelper::GetProfilesHelper(Delegate* delegate)
    : delegate_(delegate) {
}

void GetProfilesHelper::GetProfiles(MessageLoop* target_loop) {
  // If the target loop is not NULL then use the target loop, or if it's NULL
  // then use the current message loop to post a task on it later when we are
  // done building a list of profiles.
  if (target_loop) {
    message_loop_ = target_loop;
  } else {
    message_loop_ = MessageLoop::current();
  }
  DCHECK(message_loop_);
  MessageLoop* file_loop = ChromeThread::GetMessageLoop(ChromeThread::FILE);
  file_loop->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &GetProfilesHelper::GetProfilesFromManager));
}

// Records that the delegate is closed.
void GetProfilesHelper::OnDelegateDeleted() {
  delegate_ = NULL;
}

void GetProfilesHelper::GetProfilesFromManager() {
  // This function should be called on the file thread.
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));

  // If the delegate is gone by now, no need to do any work.
  if (!delegate_)
    return;

  scoped_ptr< std::vector<std::wstring> > profiles(
      new std::vector<std::wstring>);
  UserDataManager::Get()->GetProfiles(profiles.get());

  // Post a task on the original thread to call the delegate.
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &GetProfilesHelper::InvokeDelegate,
                        profiles.release()));
}

void GetProfilesHelper::InvokeDelegate(std::vector<std::wstring>* profiles) {
  scoped_ptr< std::vector<std::wstring> > udd_profiles(profiles);
  // If the delegate is gone by now, no need to do any work.
  if (delegate_)
    delegate_->OnGetProfilesDone(*udd_profiles.get());
}
<commit_msg>Coverity: Initialize message_loop_ in the constructor.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/user_data_manager.h"

#include <string>

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"

#if defined(OS_WIN)
#include <windows.h>
#include "chrome/installer/util/shell_util.h"
#endif

namespace {

// Helper to start chrome for a given profile index. The helper takes care of
// enumerating profiles on the file thread and then it launches Chrome for the
// appropriate profile on the original thread.
// An instance of this class should always be created on the heap, and it will
// delete itself when the launch is done.
class LaunchChromeForProfileIndexHelper : GetProfilesHelper::Delegate {
 public:
  // Creates an instance with the given data manager and to launch chrome for
  // the profile with the given index.
  LaunchChromeForProfileIndexHelper(const UserDataManager* manager, int index);
  virtual ~LaunchChromeForProfileIndexHelper();

  // Starts the asynchronous launch.
  void StartLaunch();

  // GetProfilesHelper::Delegate method.
  void OnGetProfilesDone(const std::vector<std::wstring>& profiles);

 private:
  int index_;
  const UserDataManager* manager_;
  scoped_refptr<GetProfilesHelper> profiles_helper_;

  DISALLOW_COPY_AND_ASSIGN(LaunchChromeForProfileIndexHelper);
};

}  // namespace

LaunchChromeForProfileIndexHelper::LaunchChromeForProfileIndexHelper(
    const UserDataManager* manager,
    int index)
    : index_(index),
      manager_(manager),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          profiles_helper_(new GetProfilesHelper(this))) {
  DCHECK(manager);
}

LaunchChromeForProfileIndexHelper::~LaunchChromeForProfileIndexHelper() {
  profiles_helper_->OnDelegateDeleted();
}

void LaunchChromeForProfileIndexHelper::StartLaunch() {
  profiles_helper_->GetProfiles(NULL);
}

void LaunchChromeForProfileIndexHelper::OnGetProfilesDone(
    const std::vector<std::wstring>& profiles) {
  if (index_ >= 0 && index_ < static_cast<int>(profiles.size()))
    manager_->LaunchChromeForProfile(profiles[index_]);

  // We are done, delete ourselves.
  delete this;
}

// Separator used in folder names between the prefix and the profile name.
// For e.g. a folder for the profile "Joe" would be named "User Data-Joe".
static const wchar_t kProfileFolderSeparator[] = L"-";

// static
UserDataManager* UserDataManager::instance_ = NULL;

// static
UserDataManager* UserDataManager::Create() {
  DCHECK(!instance_);
  std::wstring user_data;
  PathService::Get(chrome::DIR_USER_DATA, &user_data);
  instance_ = new UserDataManager(user_data);
  return instance_;
}

// static
UserDataManager* UserDataManager::Get() {
  DCHECK(instance_);
  return instance_;
}

UserDataManager::UserDataManager(const std::wstring& user_data_root)
    : user_data_root_(user_data_root) {
  // Determine current profile name and current folder name.
  current_folder_name_ = file_util::GetFilenameFromPath(user_data_root);
  bool success = GetProfileNameFromFolderName(current_folder_name_,
                                              &current_profile_name_);
  // The current profile is a default profile if the current user data folder
  // name is just kUserDataDirname or when the folder name doesn't have the
  // kUserDataDirname as prefix.
  is_current_profile_default_ =
      !success || (current_folder_name_ == chrome::kUserDataDirname);

  // (TODO:munjal) Fix issue 5070:
  // http://code.google.com/p/chromium/issues/detail?id=5070

  file_util::UpOneDirectory(&user_data_root_);
}

UserDataManager::~UserDataManager() {
  if (instance_ == this)
    instance_ = NULL;
}

// static
bool UserDataManager::GetProfileNameFromFolderName(
    const std::wstring& folder_name,
    std::wstring* profile_name) {
  // The folder name should start with a specific prefix for it to be a valid
  // profile folder.
  if (folder_name.find(chrome::kUserDataDirname) != 0)
    return false;

  // Seems like we cannot use arraysize macro for externally defined constants.
  // Is there a way?
  unsigned int prefix_length = wcslen(chrome::kUserDataDirname);
  // Subtract 1 from the size of the array for trailing null character.
  unsigned int separator_length = arraysize(kProfileFolderSeparator) - 1;

  // It's safe to use profile_name variable for intermediate values since we
  // will always return true now.
  *profile_name = folder_name.substr(prefix_length);
  // Remove leading separator if present.
  if (profile_name->find_first_of(kProfileFolderSeparator) == 0)
    *profile_name = profile_name->substr(separator_length);

  if (profile_name->empty())
    *profile_name = chrome::kNotSignedInProfile;

  return true;
}

// static
std::wstring UserDataManager::GetFolderNameFromProfileName(
    const std::wstring& profile_name) {
  std::wstring folder_name = chrome::kUserDataDirname;
  if (profile_name != chrome::kNotSignedInProfile) {
    folder_name += kProfileFolderSeparator;
    folder_name += profile_name;
  }
  return folder_name;
}

std::wstring UserDataManager::GetUserDataFolderForProfile(
    const std::wstring& profile_name) const {
  std::wstring folder_name = GetFolderNameFromProfileName(profile_name);
  std::wstring folder_path(user_data_root_);
  file_util::AppendToPath(&folder_path, folder_name);
  return folder_path;
}

void UserDataManager::LaunchChromeForProfile(
    const std::wstring& profile_name) const {
  std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
  std::wstring command;
  PathService::Get(base::FILE_EXE, &command);
  CommandLine command_line(command);
  command_line.AppendSwitch(switches::kEnableUserDataDirProfiles);
  command_line.AppendSwitchWithValue(switches::kUserDataDir,
                                     user_data_dir);
  std::wstring local_state_path;
  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
  command_line.AppendSwitchWithValue(switches::kParentProfile,
                                     local_state_path);
  base::LaunchApp(command_line, false, false, NULL);
}

void UserDataManager::LaunchChromeForProfile(int index) const {
  // Helper deletes itself when done.
  LaunchChromeForProfileIndexHelper* helper =
      new LaunchChromeForProfileIndexHelper(this, index);
  helper->StartLaunch();
}

void UserDataManager::GetProfiles(std::vector<std::wstring>* profiles) const {
  // This function should be called on the file thread.
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));
  file_util::FileEnumerator file_enum(
      FilePath::FromWStringHack(user_data_root_),
      false, file_util::FileEnumerator::DIRECTORIES);
  std::wstring folder_name;
  while (!(folder_name = file_enum.Next().ToWStringHack()).empty()) {
    folder_name = file_util::GetFilenameFromPath(folder_name);
    std::wstring profile_name;
    if (GetProfileNameFromFolderName(folder_name, &profile_name))
      profiles->push_back(profile_name);
  }
}

bool UserDataManager::CreateDesktopShortcutForProfile(
    const std::wstring& profile_name) const {
#if defined(OS_WIN)
  std::wstring exe_path;
  std::wstring shortcut_path;
  if (!PathService::Get(base::FILE_EXE, &exe_path) ||
      !ShellUtil::GetDesktopPath(false, &shortcut_path))
    return false;

  // Working directory.
  std::wstring exe_folder = file_util::GetDirectoryFromPath(exe_path);

  // Command and arguments.
  std::wstring cmd;
  cmd = StringPrintf(L"\"%ls\"", exe_path.c_str());
  std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
  std::wstring args = CommandLine::PrefixedSwitchStringWithValue(
      switches::kUserDataDir,
      user_data_dir);
  args = StringPrintf(L"\"%ls\"", args.c_str());

  // Shortcut path.
  std::wstring shortcut_name = l10n_util::GetStringF(
      IDS_START_IN_PROFILE_SHORTCUT_NAME,
      profile_name);
  shortcut_name.append(L".lnk");
  file_util::AppendToPath(&shortcut_path, shortcut_name);

  return file_util::CreateShortcutLink(cmd.c_str(),
                                       shortcut_path.c_str(),
                                       exe_folder.c_str(),
                                       args.c_str(),
                                       NULL,
                                       exe_path.c_str(),
                                       0);
#else
  // TODO(port): should probably use freedesktop.org standard for desktop files.
  NOTIMPLEMENTED();
  return false;
#endif
}

GetProfilesHelper::GetProfilesHelper(Delegate* delegate)
    : delegate_(delegate),
      message_loop_(NULL) {
}

void GetProfilesHelper::GetProfiles(MessageLoop* target_loop) {
  // If the target loop is not NULL then use the target loop, or if it's NULL
  // then use the current message loop to post a task on it later when we are
  // done building a list of profiles.
  if (target_loop) {
    message_loop_ = target_loop;
  } else {
    message_loop_ = MessageLoop::current();
  }
  DCHECK(message_loop_);
  MessageLoop* file_loop = ChromeThread::GetMessageLoop(ChromeThread::FILE);
  file_loop->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &GetProfilesHelper::GetProfilesFromManager));
}

// Records that the delegate is closed.
void GetProfilesHelper::OnDelegateDeleted() {
  delegate_ = NULL;
}

void GetProfilesHelper::GetProfilesFromManager() {
  // This function should be called on the file thread.
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));

  // If the delegate is gone by now, no need to do any work.
  if (!delegate_)
    return;

  scoped_ptr< std::vector<std::wstring> > profiles(
      new std::vector<std::wstring>);
  UserDataManager::Get()->GetProfiles(profiles.get());

  // Post a task on the original thread to call the delegate.
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &GetProfilesHelper::InvokeDelegate,
                        profiles.release()));
}

void GetProfilesHelper::InvokeDelegate(std::vector<std::wstring>* profiles) {
  scoped_ptr< std::vector<std::wstring> > udd_profiles(profiles);
  // If the delegate is gone by now, no need to do any work.
  if (delegate_)
    delegate_->OnGetProfilesDone(*udd_profiles.get());
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/prctl.h>
#include <sys/wait.h>

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/global_descriptors_posix.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/rand_util.h"
#include "base/sys_info.h"
#include "base/unix_domain_socket_posix.h"

#include "chrome/browser/zygote_host_linux.h"
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/sandbox_methods_linux.h"

#include "media/base/media.h"

#include "skia/ext/SkFontHost_fontconfig_control.h"

// http://code.google.com/p/chromium/wiki/LinuxZygote

static const int kMagicSandboxIPCDescriptor = 5;

// This is the object which implements the zygote. The ZygoteMain function,
// which is called from ChromeMain, at the the bottom and simple constructs one
// of these objects and runs it.
class Zygote {
 public:
  bool ProcessRequests() {
    // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
    // browser on it.
    // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel.
    // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC

    // We need to accept SIGCHLD, even though our handler is a no-op because
    // otherwise we cannot wait on children. (According to POSIX 2001.)
    struct sigaction action;
    memset(&action, 0, sizeof(action));
    action.sa_handler = SIGCHLDHandler;
    CHECK(sigaction(SIGCHLD, &action, NULL) == 0);

    for (;;) {
      if (HandleRequestFromBrowser(3))
        return true;
    }
  }

 private:
  // See comment below, where sigaction is called.
  static void SIGCHLDHandler(int signal) { }

  // ---------------------------------------------------------------------------
  // Requests from the browser...

  // Read and process a request from the browser. Returns true if we are in a
  // new process and thus need to unwind back into ChromeMain.
  bool HandleRequestFromBrowser(int fd) {
    std::vector<int> fds;
    static const unsigned kMaxMessageLength = 1024;
    char buf[kMaxMessageLength];
    const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
    if (len == -1) {
      LOG(WARNING) << "Error reading message from browser: " << errno;
      return false;
    }

    if (len == 0) {
      // EOF from the browser. We should die.
      _exit(0);
      return false;
    }

    Pickle pickle(buf, len);
    void* iter = NULL;

    int kind;
    if (pickle.ReadInt(&iter, &kind)) {
      switch (kind) {
        case ZygoteHost::kCmdFork:
          return HandleForkRequest(fd, pickle, iter, fds);
        case ZygoteHost::kCmdReap:
          if (!fds.empty())
            break;
          return HandleReapRequest(fd, pickle, iter);
        case ZygoteHost::kCmdDidProcessCrash:
          if (!fds.empty())
            break;
          return HandleDidProcessCrash(fd, pickle, iter);
        default:
          NOTREACHED();
          break;
      }
    }

    LOG(WARNING) << "Error parsing message from browser";
    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);
    return false;
  }

  bool HandleReapRequest(int fd, Pickle& pickle, void* iter) {
    pid_t child;

    if (!pickle.ReadInt(&iter, &child)) {
      LOG(WARNING) << "Error parsing reap request from browser";
      return false;
    }

    ProcessWatcher::EnsureProcessTerminated(child);

    return false;
  }

  bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) {
    base::ProcessHandle child;

    if (!pickle.ReadInt(&iter, &child)) {
      LOG(WARNING) << "Error parsing DidProcessCrash request from browser";
      return false;
    }

    bool child_exited;
    bool did_crash = base::DidProcessCrash(&child_exited, child);

    Pickle write_pickle;
    write_pickle.WriteBool(did_crash);
    write_pickle.WriteBool(child_exited);
    HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));

    return false;
  }

  // Handle a 'fork' request from the browser: this means that the browser
  // wishes to start a new renderer.
  bool HandleForkRequest(int fd, Pickle& pickle, void* iter,
                         std::vector<int>& fds) {
    std::vector<std::string> args;
    int argc, numfds;
    base::GlobalDescriptors::Mapping mapping;
    pid_t child;

    if (!pickle.ReadInt(&iter, &argc))
      goto error;

    for (int i = 0; i < argc; ++i) {
      std::string arg;
      if (!pickle.ReadString(&iter, &arg))
        goto error;
      args.push_back(arg);
    }

    if (!pickle.ReadInt(&iter, &numfds))
      goto error;
    if (numfds != static_cast<int>(fds.size()))
      goto error;

    for (int i = 0; i < numfds; ++i) {
      base::GlobalDescriptors::Key key;
      if (!pickle.ReadUInt32(&iter, &key))
        goto error;
      mapping.push_back(std::make_pair(key, fds[i]));
    }

    mapping.push_back(std::make_pair(
        static_cast<uint32_t>(kSandboxIPCChannel), 5));

    child = fork();

    if (!child) {
      close(3);  // our socket from the browser is in fd 3
      Singleton<base::GlobalDescriptors>()->Reset(mapping);
      CommandLine::Reset();
      CommandLine::Init(args);
      return true;
    }

    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);

    HANDLE_EINTR(write(fd, &child, sizeof(child)));
    return false;

   error:
    LOG(WARNING) << "Error parsing fork request from browser";
    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);
    return false;
  }
};

// Patched dynamic symbol wrapper functions...
namespace sandbox_wrapper {

void do_localtime(time_t input, struct tm* output, char* timezone_out,
                  size_t timezone_out_len) {
  Pickle request;
  request.WriteInt(LinuxSandbox::METHOD_LOCALTIME);
  request.WriteString(
      std::string(reinterpret_cast<char*>(&input), sizeof(input)));

  uint8_t reply_buf[512];
  const ssize_t r = base::SendRecvMsg(
      kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, request);
  if (r == -1) {
    memset(output, 0, sizeof(struct tm));
    return;
  }

  Pickle reply(reinterpret_cast<char*>(reply_buf), r);
  void* iter = NULL;
  std::string result, timezone;
  if (!reply.ReadString(&iter, &result) ||
      !reply.ReadString(&iter, &timezone) ||
      result.size() != sizeof(struct tm)) {
    memset(output, 0, sizeof(struct tm));
    return;
  }

  memcpy(output, result.data(), sizeof(struct tm));
  if (timezone_out_len) {
    const size_t copy_len = std::min(timezone_out_len - 1, timezone.size());
    memcpy(timezone_out, timezone.data(), copy_len);
    timezone_out[copy_len] = 0;
    output->tm_zone = timezone_out;
  } else {
    output->tm_zone = NULL;
  }
}

struct tm* localtime(const time_t* timep) {
  static struct tm time_struct;
  static char timezone_string[64];
  do_localtime(*timep, &time_struct, timezone_string, sizeof(timezone_string));
  return &time_struct;
}

struct tm* localtime_r(const time_t* timep, struct tm* result) {
  do_localtime(*timep, result, NULL, 0);
  return result;
}

}  // namespace sandbox_wrapper

/* On IA-32, function calls which need to be resolved by the dynamic linker are
 * directed to the producure linking table (PLT). Each PLT entry contains code
 * which jumps (indirectly) via the global offset table (GOT):
 *   Dump of assembler code for function f@plt:
 *   0x0804830c <f@plt+0>:   jmp    *0x804a004  # GOT indirect jump
 *   0x08048312 <f@plt+6>:   push   $0x8
 *   0x08048317 <f@plt+11>:  jmp    0x80482ec <_init+48>
 *
 * At the beginning of a process's lifetime, the GOT entry jumps back to
 * <f@plt+6> end then enters the dynamic linker. Once the symbol has been
 * resolved, the GOT entry is patched so that future calls go directly to the
 * resolved function.
 *
 * This macro finds the PLT entry for a given symbol, |symbol|, and reads the
 * GOT entry address from the first instruction. It then patches that address
 * with the address of a replacement function, |replacement|.
 */
#define PATCH_GLOBAL_OFFSET_TABLE(symbol, replacement) \
       /* First, get the current instruction pointer since the PLT address */ \
       /* is IP relative */ \
  asm ("call 0f\n" \
       "0: pop %%ecx\n" \
       /* Move the IP relative address of the PLT entry into EAX */ \
       "mov $" #symbol "@plt,%%eax\n" \
       /* Add EAX to ECX to get an absolute entry */ \
       "add %%eax,%%ecx\n" \
       /* The value in ECX was relative to the add instruction, however, */ \
       /* the IP value was that of the pop. The pop and mov take 6 */ \
       /* bytes, so adding 6 gets us the correct address for the PLT. The */ \
       /* first instruction at the PLT is FF 25 <abs address>, so we skip 2 */ \
       /* bytes to get to the address. 6 + 2 = 8: */ \
       "movl 8(%%ecx),%%ecx\n" \
       /* Now ECX contains the address of the GOT entry, we poke our */ \
       /* replacement function in there: */ \
       "movl %0,(%%ecx)\n" \
       :  /* no output */ \
       :  "r" (replacement) \
       : "memory", "%eax", "%ecx");

static bool MaybeEnterChroot() {
  const char* const sandbox_fd_string = getenv("SBX_D");
  if (sandbox_fd_string) {
    // The SUID sandbox sets this environment variable to a file descriptor
    // over which we can signal that we have completed our startup and can be
    // chrooted.

    char* endptr;
    const long fd_long = strtol(sandbox_fd_string, &endptr, 10);
    if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX)
      return false;
    const int fd = fd_long;

    // Before entering the sandbox, "prime" any systems that need to open
    // files and cache the results or the descriptors.
    base::RandUint64();

    base::SysInfo::MaxSharedMemorySize();

    // To make wcstombs/mbstowcs work in a renderer, setlocale() has to be
    // called before the sandbox is triggered. It's possible to avoid calling
    // setlocale() by pulling out the conversion between FilePath and
    // WebCore String out of the renderer and using string16 in place of
    // FilePath for IPC.
    const char* locale = setlocale(LC_ALL, "");
    LOG_IF(WARNING, locale == NULL) << "setlocale failed.";

#if defined(ARCH_CPU_X86)
    PATCH_GLOBAL_OFFSET_TABLE(localtime, sandbox_wrapper::localtime);
    PATCH_GLOBAL_OFFSET_TABLE(localtime_r, sandbox_wrapper::localtime_r);
#endif

    FilePath module_path;
    if (PathService::Get(base::DIR_MODULE, &module_path))
      media::InitializeMediaLibrary(module_path);

    static const char kChrootMe = 'C';
    static const char kChrootMeSuccess = 'O';

    if (HANDLE_EINTR(write(fd, &kChrootMe, 1)) != 1) {
      LOG(ERROR) << "Failed to write to chroot pipe: " << errno;
      return false;
    }

    // We need to reap the chroot helper process in any event:
    wait(NULL);

    char reply;
    if (HANDLE_EINTR(read(fd, &reply, 1)) != 1) {
      LOG(ERROR) << "Failed to read from chroot pipe: " << errno;
      return false;
    }

    if (reply != kChrootMeSuccess) {
      LOG(ERROR) << "Error code reply from chroot helper";
      return false;
    }

    SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);

    // Previously, we required that the binary be non-readable. This causes the
    // kernel to mark the process as non-dumpable at startup. The thinking was
    // that, although we were putting the renderers into a PID namespace (with
    // the SUID sandbox), they would nonetheless be in the /same/ PID
    // namespace. So they could ptrace each other unless they were non-dumpable.
    //
    // If the binary was readable, then there would be a window between process
    // startup and the point where we set the non-dumpable flag in which a
    // compromised renderer could ptrace attach.
    //
    // However, now that we have a zygote model, only the (trusted) zygote
    // exists at this point and we can set the non-dumpable flag which is
    // inherited by all our renderer children.
    //
    // Note: a non-dumpable process can't be debugged. To debug sandbox-related
    // issues, one can specify --allow-sandbox-debugging to let the process be
    // dumpable.
    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
      prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
      if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
        LOG(ERROR) << "Failed to set non-dumpable flag";
        return false;
      }
    }
  } else {
    SkiaFontConfigUseDirectImplementation();
  }

  return true;
}

bool ZygoteMain(const MainFunctionParams& params) {
  if (!MaybeEnterChroot()) {
    LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
               << errno << ")";
    return false;
  }

  Zygote zygote;
  return zygote.ProcessRequests();
}
<commit_msg>Linux: don't use GOT patching to intercept localtime(_r)<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <dlfcn.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/prctl.h>
#include <sys/wait.h>

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/global_descriptors_posix.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/rand_util.h"
#include "base/sys_info.h"
#include "base/unix_domain_socket_posix.h"

#include "chrome/browser/zygote_host_linux.h"
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/sandbox_methods_linux.h"

#include "media/base/media.h"

#include "skia/ext/SkFontHost_fontconfig_control.h"

// http://code.google.com/p/chromium/wiki/LinuxZygote

static const int kMagicSandboxIPCDescriptor = 5;

// This is the object which implements the zygote. The ZygoteMain function,
// which is called from ChromeMain, at the the bottom and simple constructs one
// of these objects and runs it.
class Zygote {
 public:
  bool ProcessRequests() {
    // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
    // browser on it.
    // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel.
    // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC

    // We need to accept SIGCHLD, even though our handler is a no-op because
    // otherwise we cannot wait on children. (According to POSIX 2001.)
    struct sigaction action;
    memset(&action, 0, sizeof(action));
    action.sa_handler = SIGCHLDHandler;
    CHECK(sigaction(SIGCHLD, &action, NULL) == 0);

    for (;;) {
      if (HandleRequestFromBrowser(3))
        return true;
    }
  }

 private:
  // See comment below, where sigaction is called.
  static void SIGCHLDHandler(int signal) { }

  // ---------------------------------------------------------------------------
  // Requests from the browser...

  // Read and process a request from the browser. Returns true if we are in a
  // new process and thus need to unwind back into ChromeMain.
  bool HandleRequestFromBrowser(int fd) {
    std::vector<int> fds;
    static const unsigned kMaxMessageLength = 1024;
    char buf[kMaxMessageLength];
    const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
    if (len == -1) {
      LOG(WARNING) << "Error reading message from browser: " << errno;
      return false;
    }

    if (len == 0) {
      // EOF from the browser. We should die.
      _exit(0);
      return false;
    }

    Pickle pickle(buf, len);
    void* iter = NULL;

    int kind;
    if (pickle.ReadInt(&iter, &kind)) {
      switch (kind) {
        case ZygoteHost::kCmdFork:
          return HandleForkRequest(fd, pickle, iter, fds);
        case ZygoteHost::kCmdReap:
          if (!fds.empty())
            break;
          return HandleReapRequest(fd, pickle, iter);
        case ZygoteHost::kCmdDidProcessCrash:
          if (!fds.empty())
            break;
          return HandleDidProcessCrash(fd, pickle, iter);
        default:
          NOTREACHED();
          break;
      }
    }

    LOG(WARNING) << "Error parsing message from browser";
    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);
    return false;
  }

  bool HandleReapRequest(int fd, Pickle& pickle, void* iter) {
    pid_t child;

    if (!pickle.ReadInt(&iter, &child)) {
      LOG(WARNING) << "Error parsing reap request from browser";
      return false;
    }

    ProcessWatcher::EnsureProcessTerminated(child);

    return false;
  }

  bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) {
    base::ProcessHandle child;

    if (!pickle.ReadInt(&iter, &child)) {
      LOG(WARNING) << "Error parsing DidProcessCrash request from browser";
      return false;
    }

    bool child_exited;
    bool did_crash = base::DidProcessCrash(&child_exited, child);

    Pickle write_pickle;
    write_pickle.WriteBool(did_crash);
    write_pickle.WriteBool(child_exited);
    HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));

    return false;
  }

  // Handle a 'fork' request from the browser: this means that the browser
  // wishes to start a new renderer.
  bool HandleForkRequest(int fd, Pickle& pickle, void* iter,
                         std::vector<int>& fds) {
    std::vector<std::string> args;
    int argc, numfds;
    base::GlobalDescriptors::Mapping mapping;
    pid_t child;

    if (!pickle.ReadInt(&iter, &argc))
      goto error;

    for (int i = 0; i < argc; ++i) {
      std::string arg;
      if (!pickle.ReadString(&iter, &arg))
        goto error;
      args.push_back(arg);
    }

    if (!pickle.ReadInt(&iter, &numfds))
      goto error;
    if (numfds != static_cast<int>(fds.size()))
      goto error;

    for (int i = 0; i < numfds; ++i) {
      base::GlobalDescriptors::Key key;
      if (!pickle.ReadUInt32(&iter, &key))
        goto error;
      mapping.push_back(std::make_pair(key, fds[i]));
    }

    mapping.push_back(std::make_pair(
        static_cast<uint32_t>(kSandboxIPCChannel), 5));

    child = fork();

    if (!child) {
      close(3);  // our socket from the browser is in fd 3
      Singleton<base::GlobalDescriptors>()->Reset(mapping);
      CommandLine::Reset();
      CommandLine::Init(args);
      return true;
    }

    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);

    HANDLE_EINTR(write(fd, &child, sizeof(child)));
    return false;

   error:
    LOG(WARNING) << "Error parsing fork request from browser";
    for (std::vector<int>::const_iterator
         i = fds.begin(); i != fds.end(); ++i)
      close(*i);
    return false;
  }
};

static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
                                        char* timezone_out,
                                        size_t timezone_out_len) {
  Pickle request;
  request.WriteInt(LinuxSandbox::METHOD_LOCALTIME);
  request.WriteString(
      std::string(reinterpret_cast<char*>(&input), sizeof(input)));

  uint8_t reply_buf[512];
  const ssize_t r = base::SendRecvMsg(
      kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, request);
  if (r == -1) {
    memset(output, 0, sizeof(struct tm));
    return;
  }

  Pickle reply(reinterpret_cast<char*>(reply_buf), r);
  void* iter = NULL;
  std::string result, timezone;
  if (!reply.ReadString(&iter, &result) ||
      !reply.ReadString(&iter, &timezone) ||
      result.size() != sizeof(struct tm)) {
    memset(output, 0, sizeof(struct tm));
    return;
  }

  memcpy(output, result.data(), sizeof(struct tm));
  if (timezone_out_len) {
    const size_t copy_len = std::min(timezone_out_len - 1, timezone.size());
    memcpy(timezone_out, timezone.data(), copy_len);
    timezone_out[copy_len] = 0;
    output->tm_zone = timezone_out;
  } else {
    output->tm_zone = NULL;
  }
}

static bool g_am_zygote_or_renderer = false;

// Sandbox interception of libc calls.
//
// Because we are running in a sandbox certain libc calls will fail (localtime
// being the motivating example - it needs to read /etc/localtime). We need to
// intercept these calls and proxy them to the browser. However, these calls
// may come from us or from our libraries. In some cases we can't just change
// our code.
//
// It's for these cases that we have the following setup:
//
// We define global functions for those functions which we wish to override.
// Since we will be first in the dynamic resolution order, the dynamic linker
// will point callers to our versions of these functions. However, we have the
// same binary for both the browser and the renderers, which means that our
// overrides will apply in the browser too.
//
// The global |g_am_zygote_or_renderer| is true iff we are in a zygote or
// renderer process. It's set in ZygoteMain and inherited by the renderers when
// they fork. (This means that it'll be incorrect for global constructor
// functions and before ZygoteMain is called - beware).
//
// Our replacement functions can check this global and either proxy
// the call to the browser over the sandbox IPC
// (http://code.google.com/p/chromium/wiki/LinuxSandboxIPC) or they can use
// dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in the
// current module.
//
// Other avenues:
//
// Our first attempt involved some assembly to patch the GOT of the current
// module. This worked, but was platform specific and doesn't catch the case
// where a library makes a call rather than current module.
//
// We also considered patching the function in place, but this would again by
// platform specific and the above technique seems to work well enough.

struct tm* localtime(const time_t* timep) {
  if (g_am_zygote_or_renderer) {
    static struct tm time_struct;
    static char timezone_string[64];
    ProxyLocaltimeCallToBrowser(*timep, &time_struct, timezone_string,
                                sizeof(timezone_string));
    return &time_struct;
  } else {
    typedef struct tm* (*LocaltimeFunction)(const time_t* timep);
    static LocaltimeFunction libc_localtime;
    if (!libc_localtime)
      libc_localtime = (LocaltimeFunction) dlsym(RTLD_NEXT, "localtime");

    return libc_localtime(timep);
  }
}

struct tm* localtime_r(const time_t* timep, struct tm* result) {
  if (g_am_zygote_or_renderer) {
    ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0);
    return result;
  } else {
    typedef struct tm* (*LocaltimeRFunction)(const time_t* timep,
                                             struct tm* result);
    static LocaltimeRFunction libc_localtime_r;
    if (!libc_localtime_r)
      libc_localtime_r = (LocaltimeRFunction) dlsym(RTLD_NEXT, "localtime_r");

    return libc_localtime_r(timep, result);
  }
}

static bool MaybeEnterChroot() {
  const char* const sandbox_fd_string = getenv("SBX_D");
  if (sandbox_fd_string) {
    // The SUID sandbox sets this environment variable to a file descriptor
    // over which we can signal that we have completed our startup and can be
    // chrooted.

    char* endptr;
    const long fd_long = strtol(sandbox_fd_string, &endptr, 10);
    if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX)
      return false;
    const int fd = fd_long;

    // Before entering the sandbox, "prime" any systems that need to open
    // files and cache the results or the descriptors.
    base::RandUint64();

    base::SysInfo::MaxSharedMemorySize();

    // To make wcstombs/mbstowcs work in a renderer, setlocale() has to be
    // called before the sandbox is triggered. It's possible to avoid calling
    // setlocale() by pulling out the conversion between FilePath and
    // WebCore String out of the renderer and using string16 in place of
    // FilePath for IPC.
    const char* locale = setlocale(LC_ALL, "");
    LOG_IF(WARNING, locale == NULL) << "setlocale failed.";

    FilePath module_path;
    if (PathService::Get(base::DIR_MODULE, &module_path))
      media::InitializeMediaLibrary(module_path);

    static const char kChrootMe = 'C';
    static const char kChrootMeSuccess = 'O';

    if (HANDLE_EINTR(write(fd, &kChrootMe, 1)) != 1) {
      LOG(ERROR) << "Failed to write to chroot pipe: " << errno;
      return false;
    }

    // We need to reap the chroot helper process in any event:
    wait(NULL);

    char reply;
    if (HANDLE_EINTR(read(fd, &reply, 1)) != 1) {
      LOG(ERROR) << "Failed to read from chroot pipe: " << errno;
      return false;
    }

    if (reply != kChrootMeSuccess) {
      LOG(ERROR) << "Error code reply from chroot helper";
      return false;
    }

    SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);

    // Previously, we required that the binary be non-readable. This causes the
    // kernel to mark the process as non-dumpable at startup. The thinking was
    // that, although we were putting the renderers into a PID namespace (with
    // the SUID sandbox), they would nonetheless be in the /same/ PID
    // namespace. So they could ptrace each other unless they were non-dumpable.
    //
    // If the binary was readable, then there would be a window between process
    // startup and the point where we set the non-dumpable flag in which a
    // compromised renderer could ptrace attach.
    //
    // However, now that we have a zygote model, only the (trusted) zygote
    // exists at this point and we can set the non-dumpable flag which is
    // inherited by all our renderer children.
    //
    // Note: a non-dumpable process can't be debugged. To debug sandbox-related
    // issues, one can specify --allow-sandbox-debugging to let the process be
    // dumpable.
    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
      prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
      if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
        LOG(ERROR) << "Failed to set non-dumpable flag";
        return false;
      }
    }
  } else {
    SkiaFontConfigUseDirectImplementation();
  }

  return true;
}

bool ZygoteMain(const MainFunctionParams& params) {
  g_am_zygote_or_renderer = true;

  if (!MaybeEnterChroot()) {
    LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
               << errno << ")";
    return false;
  }

  Zygote zygote;
  return zygote.ProcessRequests();
}
<|endoftext|>


<commit_before>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    EVENT SHALL JOE HERMASZEWSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are
    those of the authors and should not be interpreted as representing official
    policies, either expressed or implied, of Joe Hermaszewski.
*/

#include "runtime.hpp"

#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/PassManager.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/ADT/OwningPtr.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/system_error.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#include <joelang/context.hpp>
#include <joelang/config.h>
#include <joelang/types.hpp>
#include <compiler/code_generator.hpp>
#include <compiler/complete_type.hpp>
#include <compiler/type_properties.hpp>

#ifndef JOELANG_RUNTIME_FILENAME
    #error Missing runtime filename
#endif

namespace JoeLang
{
namespace Compiler
{

/// TODO find this automatically
const std::map<Type, Runtime::TypeInformation> Runtime::s_TypeInformationMap =
{
#if defined(ARCH_X86_64)
    {Type::VOID,   {ReturnType::IGNORE, ParamType::IGNORE}},
    {Type::BOOL,   {ReturnType::DEFAULT, ParamType::DEFAULT}},
    {Type::STRING, {ReturnType::DEFAULT, ParamType::EXPAND}}
#elif defined(ARCH_I386)
    {Type::VOID,   {ReturnType::IGNORE, ParamType::IGNORE}},
    {Type::BOOL,   {ReturnType::DEFAULT, ParamType::DEFAULT}},
    {Type::STRING, {ReturnType::INTEGER, ParamType::POINTER}}
#endif
};

const std::map<RuntimeFunction, Runtime::FunctionInfo> Runtime::s_FunctionInfos=
{
    {RuntimeFunction::STRING_EQUAL,    {"String_Equal",
                                        Type::BOOL,   {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_NOTEQUAL, {"String_NotEqual",
                                        Type::BOOL,   {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_CONCAT,   {"String_Concat",
                                        Type::STRING, {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_COPY,     {"String_Copy",
                                        Type::STRING, {Type::STRING}}},
    {RuntimeFunction::STRING_DESTROY,  {"String_Destroy",
                                        Type::VOID,   {Type::STRING}}},
};

Runtime::Runtime( const JoeLang::Context& joelang_context )
    :m_JoeLangContext( joelang_context )
{
    llvm::InitializeNativeTarget();

    llvm::OwningPtr<llvm::MemoryBuffer> buffer;

    llvm::MemoryBuffer::getFile( JOELANG_RUNTIME_FILENAME, buffer );
    if( !buffer )
    {
        m_JoeLangContext.Error( "Couldn't load runtime module" );
        return;
    }
    m_Module = llvm::ParseBitcodeFile ( buffer.get(), m_LLVMContext );
    if( !m_Module )
    {
        m_JoeLangContext.Error( "Couldn't parse runtime module" );
        return;
    }

    if( !FindRuntimeFunctions() )
    {
        m_JoeLangContext.Error( "Error finding functions in runtime" );
        return;
    }

    if( !FindRuntimeTypes() )
    {
        m_JoeLangContext.Error( "Error determining runtime types" );
        return;
    }

    std::string error_string;
    m_ExecutionEngine.reset( llvm::EngineBuilder(m_Module)
                             .setErrorStr(&error_string)
                             .setOptLevel(llvm::CodeGenOpt::Default)
                             .create() );
    if( !m_ExecutionEngine )
        m_JoeLangContext.Error( "Error creating LLVM ExecutionEngine: " +
                                error_string );
}

Runtime::~Runtime()
{
}

const JoeLang::Context& Runtime::GetJoeLangContext() const
{
    return m_JoeLangContext;
}

llvm::LLVMContext& Runtime::GetLLVMContext()
{
    return m_LLVMContext;
}

llvm::Module& Runtime::GetModule()
{
    return *m_Module;
}

CodeGenerator Runtime::CreateCodeGenerator()
{
    return CodeGenerator( *this );
}

llvm::ExecutionEngine& Runtime::GetExecutionEngine()
{
    return *m_ExecutionEngine;
}

llvm::Value* Runtime::CreateRuntimeCall( RuntimeFunction function,
                                         std::vector<llvm::Value*> params,
                                         llvm::IRBuilder<>& builder ) const
{
    const FunctionInfo& info = s_FunctionInfos.at(function);
    assert( params.size() == info.paramTypes.size() &&
            "Calling a function with the wrong number of params" );
    std::vector<ParamValue> param_values;
    param_values.reserve( params.size() );
    for( unsigned i = 0; i < params.size(); ++i )
        param_values.push_back( {params[i], info.paramTypes[i]} );

    return CreateCall( m_Functions.at(function),
                       info.returnType,
                       param_values,
                       builder );
}

//
// Misc
//

llvm::Type* Runtime::GetLLVMType( const CompleteType& type )
{
    llvm::Type* t = GetLLVMType( type.GetBaseType() );

    for( auto extent = type.GetArrayExtents().rbegin();
         extent != type.GetArrayExtents().rend();
         ++extent )
        t = llvm::ArrayType::get( t, *extent );

    return t;
}

llvm::Type* Runtime::GetLLVMType( Type type )
{
    llvm::Type* t;
    if( type == Type::DOUBLE )
        t = llvm::Type::getDoubleTy( m_LLVMContext );
    else if( type == Type::FLOAT )
        t = llvm::Type::getFloatTy( m_LLVMContext );
    else if( type == Type::BOOL )
        t = llvm::Type::getInt1Ty( m_LLVMContext );
    else if( IsIntegral( type ) )
        t = llvm::Type::getIntNTy( m_LLVMContext, SizeOf(type)*8 );
    else if( type == Type::STRING )
        t = m_StringType;
    else if( IsVectorType( type ) )
        t = llvm::VectorType::get( GetLLVMType( GetElementType( type ) ),
                                   GetVectorSize( type ) );
    else if( type == Type::VOID )
        t = llvm::Type::getVoidTy( m_LLVMContext );
    else
    {
        assert( false && "Trying to get the llvm::Type of an unhandled Type" );
        return nullptr;
    }

    return t;
}

llvm::Value* Runtime::CreateCall( llvm::Function* function,
                                  Type return_type,
                                  const std::vector<ParamValue>& param_types,
                                  llvm::IRBuilder<>& builder ) const
{
    std::vector<llvm::Value*> params;

    for( auto param_type : param_types )
    {
        ParamType pass_type = s_TypeInformationMap.at(param_type.type).passType;
        switch( pass_type )
        {
        case ParamType::DEFAULT:
        {
            params.push_back( param_type.value );
            break;
        }
        case ParamType::EXPAND:
        {
            assert( llvm::isa<llvm::StructType>( param_type.value->getType() )&&
                    "Can't expand a non-struct type" );
            for( unsigned i = 0;
                 i < llvm::cast<llvm::StructType>(
                                 param_type.value->getType())->getNumElements();
                 ++i )
            {
                params.push_back( builder.CreateExtractValue(
                                                   param_type.value,
                                                   std::vector<unsigned>{i} ) );
            }
            break;
        }
        case ParamType::POINTER:
        {
            // Store it and send pointer
            llvm::Value* ptr = builder.CreateAlloca( m_StringType );
            builder.CreateStore( param_type.value, ptr );
            params.push_back( ptr );
            break;
        }
        case ParamType::IGNORE:
        {
            break;
        }
        }
    }

    llvm::Value* call = builder.CreateCall( function, params );

    switch( s_TypeInformationMap.at(return_type).returnType )
    {
    case ReturnType::DEFAULT:
    case ReturnType::IGNORE:
        return call;
    case ReturnType::POINTER:
        assert( false && "Complete me" );
        return nullptr;
    case ReturnType::INTEGER:
        // The function returns an integer big enough to hold the struct
        // Store the int
        llvm::Type* int_type = function->getReturnType();
        /// TODO types other than string
        llvm::Type* ptr_type = llvm::PointerType::get( m_StringType,
                                                       0 );
        llvm::Value* int_ptr = builder.CreateAlloca( int_type );
        builder.CreateStore( call, int_ptr );
        llvm::Value* string_ptr = builder.CreateBitCast( int_ptr,
                                                         ptr_type );
        return builder.CreateLoad( string_ptr );
    }

    assert( false && "How did you get here?" );
    return nullptr;
}

bool Runtime::FindRuntimeFunctions()
{
    for( const auto& function_info : s_FunctionInfos )
    {
        m_Functions[function_info.first] =
                     m_Module->getFunction( function_info.second.name );
        if( !m_Functions[function_info.first] )
            return false;
    }
    return true;
}

bool Runtime::FindRuntimeTypes()
{
#if defined( ARCH_X86_64 )
    m_StringType = llvm::cast<llvm::StructType>(
             m_Functions[RuntimeFunction::STRING_CONCAT]->getReturnType() );

    assert( m_StringType->isLayoutIdentical( llvm::cast<llvm::StructType>(
             m_Functions[RuntimeFunction::STRING_CONCAT]->getReturnType() ) ) );
#elif defined( ARCH_I386 )
    m_StringType = m_RuntimeModule->getTypeByName( "struct.jl_string" );
#else
    llvm::Type* size_type = GetLLVMType( Type::U32 );
    llvm::Type* char_ptr_type = llvm::Type::getInt8PtrTy( m_LLVMContext );
    m_StringType = llvm::StructType::create( std::vector<llvm::Type*>
                                               {size_type, char_ptr_type} );
#endif
    if( !m_StringType )
        return false;
    return true;
}

void Runtime::InitializeOptimizers()
{
    m_LLVMFunctionPassManager.reset(
                                    new llvm::FunctionPassManager( m_Module ) );
    m_LLVMModulePassManager.reset( new llvm::PassManager() );

    llvm::PassManagerBuilder pass_manager_builder;
    pass_manager_builder.OptLevel = 3;
    pass_manager_builder.Inliner = llvm::createFunctionInliningPass();
    pass_manager_builder.LoopVectorize = true;
    pass_manager_builder.BBVectorize = true;
    pass_manager_builder.SLPVectorize = true;
    pass_manager_builder.populateFunctionPassManager(
                                                   *m_LLVMFunctionPassManager );
    pass_manager_builder.populateModulePassManager(
                                                   *m_LLVMModulePassManager );

    m_LLVMFunctionPassManager->doInitialization();
}

void Runtime::OptimizeFunction( llvm::Function& function )
{
    m_LLVMFunctionPassManager->run( function );
}

void Runtime::OptimizeModule()
{
    m_LLVMModulePassManager->run( *m_Module );
}

} // namespace Compiler
} // namespace JoeLang

<commit_msg>[+] Calling llvm_shutdown()<commit_after>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    EVENT SHALL JOE HERMASZEWSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are
    those of the authors and should not be interpreted as representing official
    policies, either expressed or implied, of Joe Hermaszewski.
*/

#include "runtime.hpp"

#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/PassManager.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/ADT/OwningPtr.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/system_error.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#include <joelang/context.hpp>
#include <joelang/config.h>
#include <joelang/types.hpp>
#include <compiler/code_generator.hpp>
#include <compiler/complete_type.hpp>
#include <compiler/type_properties.hpp>

#ifndef JOELANG_RUNTIME_FILENAME
    #error Missing runtime filename
#endif

namespace JoeLang
{
namespace Compiler
{

/// TODO find this automatically
const std::map<Type, Runtime::TypeInformation> Runtime::s_TypeInformationMap =
{
#if defined(ARCH_X86_64)
    {Type::VOID,   {ReturnType::IGNORE, ParamType::IGNORE}},
    {Type::BOOL,   {ReturnType::DEFAULT, ParamType::DEFAULT}},
    {Type::STRING, {ReturnType::DEFAULT, ParamType::EXPAND}}
#elif defined(ARCH_I386)
    {Type::VOID,   {ReturnType::IGNORE, ParamType::IGNORE}},
    {Type::BOOL,   {ReturnType::DEFAULT, ParamType::DEFAULT}},
    {Type::STRING, {ReturnType::INTEGER, ParamType::POINTER}}
#endif
};

const std::map<RuntimeFunction, Runtime::FunctionInfo> Runtime::s_FunctionInfos=
{
    {RuntimeFunction::STRING_EQUAL,    {"String_Equal",
                                        Type::BOOL,   {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_NOTEQUAL, {"String_NotEqual",
                                        Type::BOOL,   {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_CONCAT,   {"String_Concat",
                                        Type::STRING, {Type::STRING,
                                                       Type::STRING}}},
    {RuntimeFunction::STRING_COPY,     {"String_Copy",
                                        Type::STRING, {Type::STRING}}},
    {RuntimeFunction::STRING_DESTROY,  {"String_Destroy",
                                        Type::VOID,   {Type::STRING}}},
};

Runtime::Runtime( const JoeLang::Context& joelang_context )
    :m_JoeLangContext( joelang_context )
{
    llvm::InitializeNativeTarget();

    llvm::OwningPtr<llvm::MemoryBuffer> buffer;

    llvm::MemoryBuffer::getFile( JOELANG_RUNTIME_FILENAME, buffer );
    if( !buffer )
    {
        m_JoeLangContext.Error( "Couldn't load runtime module" );
        return;
    }
    m_Module = llvm::ParseBitcodeFile ( buffer.get(), m_LLVMContext );
    if( !m_Module )
    {
        m_JoeLangContext.Error( "Couldn't parse runtime module" );
        return;
    }

    if( !FindRuntimeFunctions() )
    {
        m_JoeLangContext.Error( "Error finding functions in runtime" );
        return;
    }

    if( !FindRuntimeTypes() )
    {
        m_JoeLangContext.Error( "Error determining runtime types" );
        return;
    }

    std::string error_string;
    m_ExecutionEngine.reset( llvm::EngineBuilder(m_Module)
                             .setErrorStr(&error_string)
                             .setOptLevel(llvm::CodeGenOpt::Default)
                             .create() );
    if( !m_ExecutionEngine )
        m_JoeLangContext.Error( "Error creating LLVM ExecutionEngine: " +
                                error_string );
}

Runtime::~Runtime()
{
    llvm::llvm_shutdown();
}

const JoeLang::Context& Runtime::GetJoeLangContext() const
{
    return m_JoeLangContext;
}

llvm::LLVMContext& Runtime::GetLLVMContext()
{
    return m_LLVMContext;
}

llvm::Module& Runtime::GetModule()
{
    return *m_Module;
}

CodeGenerator Runtime::CreateCodeGenerator()
{
    return CodeGenerator( *this );
}

llvm::ExecutionEngine& Runtime::GetExecutionEngine()
{
    return *m_ExecutionEngine;
}

llvm::Value* Runtime::CreateRuntimeCall( RuntimeFunction function,
                                         std::vector<llvm::Value*> params,
                                         llvm::IRBuilder<>& builder ) const
{
    const FunctionInfo& info = s_FunctionInfos.at(function);
    assert( params.size() == info.paramTypes.size() &&
            "Calling a function with the wrong number of params" );
    std::vector<ParamValue> param_values;
    param_values.reserve( params.size() );
    for( unsigned i = 0; i < params.size(); ++i )
        param_values.push_back( {params[i], info.paramTypes[i]} );

    return CreateCall( m_Functions.at(function),
                       info.returnType,
                       param_values,
                       builder );
}

//
// Misc
//

llvm::Type* Runtime::GetLLVMType( const CompleteType& type )
{
    llvm::Type* t = GetLLVMType( type.GetBaseType() );

    for( auto extent = type.GetArrayExtents().rbegin();
         extent != type.GetArrayExtents().rend();
         ++extent )
        t = llvm::ArrayType::get( t, *extent );

    return t;
}

llvm::Type* Runtime::GetLLVMType( Type type )
{
    llvm::Type* t;
    if( type == Type::DOUBLE )
        t = llvm::Type::getDoubleTy( m_LLVMContext );
    else if( type == Type::FLOAT )
        t = llvm::Type::getFloatTy( m_LLVMContext );
    else if( type == Type::BOOL )
        t = llvm::Type::getInt1Ty( m_LLVMContext );
    else if( IsIntegral( type ) )
        t = llvm::Type::getIntNTy( m_LLVMContext, SizeOf(type)*8 );
    else if( type == Type::STRING )
        t = m_StringType;
    else if( IsVectorType( type ) )
        t = llvm::VectorType::get( GetLLVMType( GetElementType( type ) ),
                                   GetVectorSize( type ) );
    else if( type == Type::VOID )
        t = llvm::Type::getVoidTy( m_LLVMContext );
    else
    {
        assert( false && "Trying to get the llvm::Type of an unhandled Type" );
        return nullptr;
    }

    return t;
}

llvm::Value* Runtime::CreateCall( llvm::Function* function,
                                  Type return_type,
                                  const std::vector<ParamValue>& param_types,
                                  llvm::IRBuilder<>& builder ) const
{
    std::vector<llvm::Value*> params;

    for( auto param_type : param_types )
    {
        ParamType pass_type = s_TypeInformationMap.at(param_type.type).passType;
        switch( pass_type )
        {
        case ParamType::DEFAULT:
        {
            params.push_back( param_type.value );
            break;
        }
        case ParamType::EXPAND:
        {
            assert( llvm::isa<llvm::StructType>( param_type.value->getType() )&&
                    "Can't expand a non-struct type" );
            for( unsigned i = 0;
                 i < llvm::cast<llvm::StructType>(
                                 param_type.value->getType())->getNumElements();
                 ++i )
            {
                params.push_back( builder.CreateExtractValue(
                                                   param_type.value,
                                                   std::vector<unsigned>{i} ) );
            }
            break;
        }
        case ParamType::POINTER:
        {
            // Store it and send pointer
            llvm::Value* ptr = builder.CreateAlloca( m_StringType );
            builder.CreateStore( param_type.value, ptr );
            params.push_back( ptr );
            break;
        }
        case ParamType::IGNORE:
        {
            break;
        }
        }
    }

    llvm::Value* call = builder.CreateCall( function, params );

    switch( s_TypeInformationMap.at(return_type).returnType )
    {
    case ReturnType::DEFAULT:
    case ReturnType::IGNORE:
        return call;
    case ReturnType::POINTER:
        assert( false && "Complete me" );
        return nullptr;
    case ReturnType::INTEGER:
        // The function returns an integer big enough to hold the struct
        // Store the int
        llvm::Type* int_type = function->getReturnType();
        /// TODO types other than string
        llvm::Type* ptr_type = llvm::PointerType::get( m_StringType,
                                                       0 );
        llvm::Value* int_ptr = builder.CreateAlloca( int_type );
        builder.CreateStore( call, int_ptr );
        llvm::Value* string_ptr = builder.CreateBitCast( int_ptr,
                                                         ptr_type );
        return builder.CreateLoad( string_ptr );
    }

    assert( false && "How did you get here?" );
    return nullptr;
}

bool Runtime::FindRuntimeFunctions()
{
    for( const auto& function_info : s_FunctionInfos )
    {
        m_Functions[function_info.first] =
                     m_Module->getFunction( function_info.second.name );
        if( !m_Functions[function_info.first] )
            return false;
    }
    return true;
}

bool Runtime::FindRuntimeTypes()
{
#if defined( ARCH_X86_64 )
    m_StringType = llvm::cast<llvm::StructType>(
             m_Functions[RuntimeFunction::STRING_CONCAT]->getReturnType() );

    assert( m_StringType->isLayoutIdentical( llvm::cast<llvm::StructType>(
             m_Functions[RuntimeFunction::STRING_CONCAT]->getReturnType() ) ) );
#elif defined( ARCH_I386 )
    m_StringType = m_RuntimeModule->getTypeByName( "struct.jl_string" );
#else
    llvm::Type* size_type = GetLLVMType( Type::U32 );
    llvm::Type* char_ptr_type = llvm::Type::getInt8PtrTy( m_LLVMContext );
    m_StringType = llvm::StructType::create( std::vector<llvm::Type*>
                                               {size_type, char_ptr_type} );
#endif
    if( !m_StringType )
        return false;
    return true;
}

void Runtime::InitializeOptimizers()
{
    m_LLVMFunctionPassManager.reset(
                                    new llvm::FunctionPassManager( m_Module ) );
    m_LLVMModulePassManager.reset( new llvm::PassManager() );

    llvm::PassManagerBuilder pass_manager_builder;
    pass_manager_builder.OptLevel = 3;
    pass_manager_builder.Inliner = llvm::createFunctionInliningPass();
    pass_manager_builder.LoopVectorize = true;
    pass_manager_builder.BBVectorize = true;
    pass_manager_builder.SLPVectorize = true;
    pass_manager_builder.populateFunctionPassManager(
                                                   *m_LLVMFunctionPassManager );
    pass_manager_builder.populateModulePassManager(
                                                   *m_LLVMModulePassManager );

    m_LLVMFunctionPassManager->doInitialization();
}

void Runtime::OptimizeFunction( llvm::Function& function )
{
    m_LLVMFunctionPassManager->run( function );
}

void Runtime::OptimizeModule()
{
    m_LLVMModulePassManager->run( *m_Module );
}

} // namespace Compiler
} // namespace JoeLang

<|endoftext|>


<commit_before>// Copyright 2011 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/// \file state.hpp
/// Provides the state wrapper class for the Lua C state.

#if !defined(LUTOK_STATE_HPP)
#define LUTOK_STATE_HPP

#include <string>
#include <tr1/memory>

namespace lutok {

class c_gate;
class debug;
class state;

/// The type of a C++ function that can be bound into Lua.
///
/// Functions of this type are free to raise exceptions.  These will not
/// propagate into the Lua C API.  However, any such exceptions will be reported
/// as a Lua error and their type will be lost.
typedef int (*cxx_function)(state&);

/// A RAII model for the Lua state.
///
/// This class holds the state of the Lua interpreter during its existence and
/// provides wrappers around several Lua library functions that operate on such
/// state.
///
/// These wrapper functions differ from the C versions in that they use the
/// implicit state hold by the class, they use C++ types where appropriate and
/// they use exceptions to report errors.
///
/// The wrappers intend to be as lightweight as possible but, in some
/// situations, they are pretty complex because they need to do extra work to
/// capture the errors reported by the Lua C API.  We prefer having fine-grained
/// error control rather than efficiency, so this is OK.
class state {
    struct impl;
    std::tr1::shared_ptr< impl > _pimpl;

    void* new_userdata_voidp(const size_t);
    void* to_userdata_voidp(const int);

    friend class state_c_gate;
    explicit state(void*);
    void* raw_state(void);

public:
    state(void);
    ~state(void);

    void close(void);
    void get_global(const std::string&);
    void get_table(const int = -2);
    int get_top(void);
    bool is_boolean(const int = -1);
    bool is_function(const int = -1);
    bool is_nil(const int = -1);
    bool is_number(const int = -1);
    bool is_string(const int = -1);
    bool is_table(const int = -1);
    bool is_userdata(const int = -1);
    void load_file(const std::string&);
    void load_string(const std::string&);
    void new_table(void);
    template< typename Type > Type* new_userdata(void);
    bool next(const int = -2);
    void open_base(void);
    void open_string(void);
    void open_table(void);
    void pcall(const int, const int, const int);
    void pop(const int);
    void push_boolean(const bool);
    void push_cxx_closure(cxx_function, const int);
    void push_cxx_function(cxx_function);
    void push_integer(const int);
    void push_nil(void);
    void push_string(const std::string&);
    void set_global(const std::string&);
    void set_metatable(const int = -2);
    void set_table(const int = -3);
    bool to_boolean(const int = -1);
    long to_integer(const int = -1);
    template< typename Type > Type* to_userdata(const int = -1);
    std::string to_string(const int = -1);
    int upvalue_index(const int);
};

}  // namespace lutok

#endif  // !defined(LUTOK_STATE_HPP)
<commit_msg>Remove invalid and useless forward declaration<commit_after>// Copyright 2011 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/// \file state.hpp
/// Provides the state wrapper class for the Lua C state.

#if !defined(LUTOK_STATE_HPP)
#define LUTOK_STATE_HPP

#include <string>
#include <tr1/memory>

namespace lutok {

class debug;
class state;

/// The type of a C++ function that can be bound into Lua.
///
/// Functions of this type are free to raise exceptions.  These will not
/// propagate into the Lua C API.  However, any such exceptions will be reported
/// as a Lua error and their type will be lost.
typedef int (*cxx_function)(state&);

/// A RAII model for the Lua state.
///
/// This class holds the state of the Lua interpreter during its existence and
/// provides wrappers around several Lua library functions that operate on such
/// state.
///
/// These wrapper functions differ from the C versions in that they use the
/// implicit state hold by the class, they use C++ types where appropriate and
/// they use exceptions to report errors.
///
/// The wrappers intend to be as lightweight as possible but, in some
/// situations, they are pretty complex because they need to do extra work to
/// capture the errors reported by the Lua C API.  We prefer having fine-grained
/// error control rather than efficiency, so this is OK.
class state {
    struct impl;
    std::tr1::shared_ptr< impl > _pimpl;

    void* new_userdata_voidp(const size_t);
    void* to_userdata_voidp(const int);

    friend class state_c_gate;
    explicit state(void*);
    void* raw_state(void);

public:
    state(void);
    ~state(void);

    void close(void);
    void get_global(const std::string&);
    void get_table(const int = -2);
    int get_top(void);
    bool is_boolean(const int = -1);
    bool is_function(const int = -1);
    bool is_nil(const int = -1);
    bool is_number(const int = -1);
    bool is_string(const int = -1);
    bool is_table(const int = -1);
    bool is_userdata(const int = -1);
    void load_file(const std::string&);
    void load_string(const std::string&);
    void new_table(void);
    template< typename Type > Type* new_userdata(void);
    bool next(const int = -2);
    void open_base(void);
    void open_string(void);
    void open_table(void);
    void pcall(const int, const int, const int);
    void pop(const int);
    void push_boolean(const bool);
    void push_cxx_closure(cxx_function, const int);
    void push_cxx_function(cxx_function);
    void push_integer(const int);
    void push_nil(void);
    void push_string(const std::string&);
    void set_global(const std::string&);
    void set_metatable(const int = -2);
    void set_table(const int = -3);
    bool to_boolean(const int = -1);
    long to_integer(const int = -1);
    template< typename Type > Type* to_userdata(const int = -1);
    std::string to_string(const int = -1);
    int upvalue_index(const int);
};

}  // namespace lutok

#endif  // !defined(LUTOK_STATE_HPP)
<|endoftext|>