<commit_before>/**
 * Copyright (c) 2013, Timothy Stack
 *
 * 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 Timothy Stack 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 REGENTS 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 REGENTS 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 lnav_util.cc
 *
 * Dumping ground for useful functions with no other home.
 */

#include "config.h"

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>

#include <sqlite3.h>

#include "auto_fd.hh"
#include "lnav_util.hh"

std::string hash_string(const std::string &str)
{
    byte_array<SHA_DIGEST_LENGTH> hash;
    SHA_CTX context;

    SHA_Init(&context);
    SHA_Update(&context, str.c_str(), str.length());
    SHA_Final(hash.out(), &context);

    return hash.to_string();
}

std::string time_ago(time_t last_time)
{
    time_t      delta, current_time = time(NULL);
    const char *fmt;
    char        buffer[64];
    int         amount;

    delta = current_time - last_time;
    if (delta < 0) {
        return "in the future";
    }
    else if (delta < 60) {
        return "just now";
    }
    else if (delta < (60 * 2)) {
        return "one minute ago";
    }
    else if (delta < (60 * 60)) {
        fmt    = "%d minutes ago";
        amount = delta / 60;
    }
    else if (delta < (2 * 60 * 60)) {
        return "one hour ago";
    }
    else if (delta < (24 * 60 * 60)) {
        fmt    = "%d hours ago";
        amount = delta / (60 * 60);
    }
    else if (delta < (2 * 24 * 60 * 60)) {
        return "one day ago";
    }
    else if (delta < (365 * 24 * 60 * 60)) {
        fmt    = "%d days ago";
        amount = delta / (24 * 60 * 60);
    }
    else {
        return "over a year ago";
    }

    snprintf(buffer, sizeof(buffer), fmt, amount);

    return std::string(buffer);
}

/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem)
{
    sqlite3_close((sqlite3 *)mem);
}

std::string get_current_dir(void)
{
    char        cwd[FILENAME_MAX];
    std::string retval = ".";

    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        perror("getcwd");
    }
    else {
        retval = std::string(cwd);
    }

    if (retval != "/") {
        retval += "/";
    }

    return retval;
}

bool change_to_parent_dir(void)
{
    bool retval = false;
    char cwd[3] = "";

    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        /* perror("getcwd"); */
    }
    if (strcmp(cwd, "/") != 0) {
        if (chdir("..") == -1) {
            perror("chdir('..')");
        }
        else {
            retval = true;
        }
    }

    return retval;
}

file_format_t detect_file_format(const std::string &filename)
{
    file_format_t retval = FF_UNKNOWN;
    auto_fd       fd;

    if ((fd = open(filename.c_str(), O_RDONLY)) != -1) {
        char buffer[32];
        int  rc;

        if ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
            if (rc > 16 &&
                strncmp(buffer, "SQLite format 3", 16) == 0) {
                retval = FF_SQLITE_DB;
            }
        }
    }

    return retval;
}

static time_t BAD_DATE = -1;

time_t tm2sec(const struct tm *t)
{
    int       year;
    time_t    days;
    const int dayoffset[12] =
    { 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 };

    year = t->tm_year;

    if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) {
        return BAD_DATE;
    }

    /* shift new year to 1st March in order to make leap year calc easy */

    if (t->tm_mon < 2) {
        year--;
    }

    /* Find number of days since 1st March 1900 (in the Gregorian calendar). */

    days  = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
    days += dayoffset[t->tm_mon] + t->tm_mday - 1;
    days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */

    days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;

    if (days < 0) {
        return BAD_DATE;
    }                          /* must have overflowed */
    else {
        if (t->tm_zone) {
            days -= t->tm_gmtoff;
        }
        return days;
    }                          /* must be a valid time */
}

bool next_format(const char *fmt[], int &index, int &locked_index)
{
    bool retval = true;

    if (locked_index == -1) {
        index += 1;
        if (fmt[index] == NULL) {
            retval = false;
        }
    }
    else if (index == locked_index) {
        retval = false;
    }
    else {
        index = locked_index;
    }

    return retval;
}

static const char *time_fmt_with_zone = "%a %b %d %H:%M:%S ";

const char *std_time_fmt[] = {
    "%Y-%m-%d %H:%M:%S",
    "%Y-%m-%d %H:%M",
    "%Y-%m-%dT%H:%M:%S",
    "%Y-%m-%dT%H:%M:%SZ",
    "%Y/%m/%d %H:%M:%S",
    "%Y/%m/%d %H:%M",

    "%a %b %d %H:%M:%S %Y",
    "%a %b %d %H:%M:%S %Z %Y",
    time_fmt_with_zone,

    "%d/%b/%Y:%H:%M:%S %z",

    "%b %d %H:%M:%S",

    NULL,
};

const char *date_time_scanner::scan(const char *time_dest,
                                    const char *time_fmt[],
                                    struct tm *tm_out,
                                    struct timeval &tv_out)
{
    int  curr_time_fmt = -1;
    bool found         = false;
    const char *retval = NULL;

    if (!time_fmt) {
        time_fmt = std_time_fmt;
    }

    while (next_format(time_fmt,
                       curr_time_fmt,
                       this->dts_fmt_lock)) {
        *tm_out = this->dts_base_tm;
        if ((retval = strptime(time_dest,
                               time_fmt[curr_time_fmt],
                               tm_out)) != NULL) {
            if (time_fmt[curr_time_fmt] == time_fmt_with_zone) {
                int lpc;

                for (lpc = 0; retval[lpc] && retval[lpc] != ' '; lpc++) {

                }
                if (retval[lpc] == ' ' &&
                    sscanf(&retval[lpc], "%d", &tm_out->tm_year) == 1) {
                    lpc += 1;
                    for (; retval[lpc] && isnumber(retval[lpc]); lpc++) {

                    }
                    retval = &retval[lpc];
                }
            }

            if (tm_out->tm_year < 70) {
                tm_out->tm_year = 80;
            }
            tv_out.tv_sec = tm2sec(tm_out);
            tv_out.tv_usec = 0;

            this->dts_fmt_lock = curr_time_fmt;
            this->dts_fmt_len  = retval - time_dest;

            /* Try to pull out the milli/micro-second value. */
            if (retval[0] == '.' || retval[0] == ',') {
                int sub_seconds = 0, sub_len = 0;

                if (sscanf(retval + 1, "%d%n", &sub_seconds, &sub_len) == 1) {
                    switch (sub_len) {
                    case 3:
                        tv_out.tv_usec = sub_seconds * 100;
                        this->dts_fmt_len += 1 + sub_len;
                        break;
                    case 6:
                        tv_out.tv_usec = sub_seconds;
                        this->dts_fmt_len += 1 + sub_len;
                        break;
                    }
                }
            }

            found = true;
            break;
        }
    }

    if (!found) {
        retval = NULL;
    }

    return retval;
}
<commit_msg>use isdigit<commit_after>/**
 * Copyright (c) 2013, Timothy Stack
 *
 * 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 Timothy Stack 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 REGENTS 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 REGENTS 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 lnav_util.cc
 *
 * Dumping ground for useful functions with no other home.
 */

#include "config.h"

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>

#include <sqlite3.h>

#include "auto_fd.hh"
#include "lnav_util.hh"

std::string hash_string(const std::string &str)
{
    byte_array<SHA_DIGEST_LENGTH> hash;
    SHA_CTX context;

    SHA_Init(&context);
    SHA_Update(&context, str.c_str(), str.length());
    SHA_Final(hash.out(), &context);

    return hash.to_string();
}

std::string time_ago(time_t last_time)
{
    time_t      delta, current_time = time(NULL);
    const char *fmt;
    char        buffer[64];
    int         amount;

    delta = current_time - last_time;
    if (delta < 0) {
        return "in the future";
    }
    else if (delta < 60) {
        return "just now";
    }
    else if (delta < (60 * 2)) {
        return "one minute ago";
    }
    else if (delta < (60 * 60)) {
        fmt    = "%d minutes ago";
        amount = delta / 60;
    }
    else if (delta < (2 * 60 * 60)) {
        return "one hour ago";
    }
    else if (delta < (24 * 60 * 60)) {
        fmt    = "%d hours ago";
        amount = delta / (60 * 60);
    }
    else if (delta < (2 * 24 * 60 * 60)) {
        return "one day ago";
    }
    else if (delta < (365 * 24 * 60 * 60)) {
        fmt    = "%d days ago";
        amount = delta / (24 * 60 * 60);
    }
    else {
        return "over a year ago";
    }

    snprintf(buffer, sizeof(buffer), fmt, amount);

    return std::string(buffer);
}

/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem)
{
    sqlite3_close((sqlite3 *)mem);
}

std::string get_current_dir(void)
{
    char        cwd[FILENAME_MAX];
    std::string retval = ".";

    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        perror("getcwd");
    }
    else {
        retval = std::string(cwd);
    }

    if (retval != "/") {
        retval += "/";
    }

    return retval;
}

bool change_to_parent_dir(void)
{
    bool retval = false;
    char cwd[3] = "";

    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        /* perror("getcwd"); */
    }
    if (strcmp(cwd, "/") != 0) {
        if (chdir("..") == -1) {
            perror("chdir('..')");
        }
        else {
            retval = true;
        }
    }

    return retval;
}

file_format_t detect_file_format(const std::string &filename)
{
    file_format_t retval = FF_UNKNOWN;
    auto_fd       fd;

    if ((fd = open(filename.c_str(), O_RDONLY)) != -1) {
        char buffer[32];
        int  rc;

        if ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
            if (rc > 16 &&
                strncmp(buffer, "SQLite format 3", 16) == 0) {
                retval = FF_SQLITE_DB;
            }
        }
    }

    return retval;
}

static time_t BAD_DATE = -1;

time_t tm2sec(const struct tm *t)
{
    int       year;
    time_t    days;
    const int dayoffset[12] =
    { 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 };

    year = t->tm_year;

    if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) {
        return BAD_DATE;
    }

    /* shift new year to 1st March in order to make leap year calc easy */

    if (t->tm_mon < 2) {
        year--;
    }

    /* Find number of days since 1st March 1900 (in the Gregorian calendar). */

    days  = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
    days += dayoffset[t->tm_mon] + t->tm_mday - 1;
    days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */

    days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;

    if (days < 0) {
        return BAD_DATE;
    }                          /* must have overflowed */
    else {
        if (t->tm_zone) {
            days -= t->tm_gmtoff;
        }
        return days;
    }                          /* must be a valid time */
}

bool next_format(const char *fmt[], int &index, int &locked_index)
{
    bool retval = true;

    if (locked_index == -1) {
        index += 1;
        if (fmt[index] == NULL) {
            retval = false;
        }
    }
    else if (index == locked_index) {
        retval = false;
    }
    else {
        index = locked_index;
    }

    return retval;
}

static const char *time_fmt_with_zone = "%a %b %d %H:%M:%S ";

const char *std_time_fmt[] = {
    "%Y-%m-%d %H:%M:%S",
    "%Y-%m-%d %H:%M",
    "%Y-%m-%dT%H:%M:%S",
    "%Y-%m-%dT%H:%M:%SZ",
    "%Y/%m/%d %H:%M:%S",
    "%Y/%m/%d %H:%M",

    "%a %b %d %H:%M:%S %Y",
    "%a %b %d %H:%M:%S %Z %Y",
    time_fmt_with_zone,

    "%d/%b/%Y:%H:%M:%S %z",

    "%b %d %H:%M:%S",

    NULL,
};

const char *date_time_scanner::scan(const char *time_dest,
                                    const char *time_fmt[],
                                    struct tm *tm_out,
                                    struct timeval &tv_out)
{
    int  curr_time_fmt = -1;
    bool found         = false;
    const char *retval = NULL;

    if (!time_fmt) {
        time_fmt = std_time_fmt;
    }

    while (next_format(time_fmt,
                       curr_time_fmt,
                       this->dts_fmt_lock)) {
        *tm_out = this->dts_base_tm;
        if ((retval = strptime(time_dest,
                               time_fmt[curr_time_fmt],
                               tm_out)) != NULL) {
            if (time_fmt[curr_time_fmt] == time_fmt_with_zone) {
                int lpc;

                for (lpc = 0; retval[lpc] && retval[lpc] != ' '; lpc++) {

                }
                if (retval[lpc] == ' ' &&
                    sscanf(&retval[lpc], "%d", &tm_out->tm_year) == 1) {
                    lpc += 1;
                    for (; retval[lpc] && isdigit(retval[lpc]); lpc++) {

                    }
                    retval = &retval[lpc];
                }
            }

            if (tm_out->tm_year < 70) {
                tm_out->tm_year = 80;
            }
            tv_out.tv_sec = tm2sec(tm_out);
            tv_out.tv_usec = 0;

            this->dts_fmt_lock = curr_time_fmt;
            this->dts_fmt_len  = retval - time_dest;

            /* Try to pull out the milli/micro-second value. */
            if (retval[0] == '.' || retval[0] == ',') {
                int sub_seconds = 0, sub_len = 0;

                if (sscanf(retval + 1, "%d%n", &sub_seconds, &sub_len) == 1) {
                    switch (sub_len) {
                    case 3:
                        tv_out.tv_usec = sub_seconds * 100;
                        this->dts_fmt_len += 1 + sub_len;
                        break;
                    case 6:
                        tv_out.tv_usec = sub_seconds;
                        this->dts_fmt_len += 1 + sub_len;
                        break;
                    }
                }
            }

            found = true;
            break;
        }
    }

    if (!found) {
        retval = NULL;
    }

    return retval;
}
<|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 <string>

#include "base/message_loop.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

class WebCacheManagerBrowserTest : public InProcessBrowserTest {
};

// Regression test for http://crbug.com/12362.  If a renderer crashes and the
// user navigates to another tab and back, the browser doesn't crash.
// TODO(jam): http://crbug.com/15288 disabled because it fails on the build bot.
IN_PROC_BROWSER_TEST_F(WebCacheManagerBrowserTest, DISABLED_CrashOnceOnly) {
  const FilePath kTestDir(FILE_PATH_LITERAL("google"));
  const FilePath kTestFile(FILE_PATH_LITERAL("google.html"));
  GURL url(ui_test_utils::GetTestUrl(kTestDir, kTestFile));

  ui_test_utils::NavigateToURL(browser(), url);

  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* tab = browser()->GetTabContentsAt(0);
  ASSERT_TRUE(tab != NULL);
  base::KillProcess(tab->GetRenderProcessHost()->GetHandle(),
                    base::PROCESS_END_KILLED_BY_USER, true);

  browser()->SelectTabContentsAt(0, true);
  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  browser()->SelectTabContentsAt(0, true);
  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  // We would have crashed at the above line with the bug.

  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();
  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();
  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();

  ui_test_utils::NavigateToURL(browser(), url);

  EXPECT_EQ(
      WebCacheManager::GetInstance()->active_renderers_.size(), 1U);
  EXPECT_EQ(
      WebCacheManager::GetInstance()->inactive_renderers_.size(), 0U);
  EXPECT_EQ(
      WebCacheManager::GetInstance()->stats_.size(), 1U);
}
<commit_msg>TTF: Re-enable WebCacheManagerBrowserTest.CrashOnceOnly by marking it flaky.<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 <string>

#include "base/message_loop.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

class WebCacheManagerBrowserTest : public InProcessBrowserTest {
};

// Regression test for http://crbug.com/12362.  If a renderer crashes and the
// user navigates to another tab and back, the browser doesn't crash.
// Flaky, http://crbug.com/15288.
IN_PROC_BROWSER_TEST_F(WebCacheManagerBrowserTest, FLAKY_CrashOnceOnly) {
  const FilePath kTestDir(FILE_PATH_LITERAL("google"));
  const FilePath kTestFile(FILE_PATH_LITERAL("google.html"));
  GURL url(ui_test_utils::GetTestUrl(kTestDir, kTestFile));

  ui_test_utils::NavigateToURL(browser(), url);

  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* tab = browser()->GetTabContentsAt(0);
  ASSERT_TRUE(tab != NULL);
  base::KillProcess(tab->GetRenderProcessHost()->GetHandle(),
                    base::PROCESS_END_KILLED_BY_USER, true);

  browser()->SelectTabContentsAt(0, true);
  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  browser()->SelectTabContentsAt(0, true);
  browser()->NewTab();
  ui_test_utils::NavigateToURL(browser(), url);

  // We would have crashed at the above line with the bug.

  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();
  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();
  browser()->SelectTabContentsAt(0, true);
  browser()->CloseTab();

  ui_test_utils::NavigateToURL(browser(), url);

  EXPECT_EQ(
      WebCacheManager::GetInstance()->active_renderers_.size(), 1U);
  EXPECT_EQ(
      WebCacheManager::GetInstance()->inactive_renderers_.size(), 0U);
  EXPECT_EQ(
      WebCacheManager::GetInstance()->stats_.size(), 1U);
}
<|endoftext|>


<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation; either version 2.1 of the License,               *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#include <ios>
#include <sstream>

#include "cppa/exception.hpp"
#include "cppa/detail/fd_util.hpp"

#if defined(CPPA_LINUX) || defined(CPPA_MACOS)

#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

namespace cppa { namespace detail { namespace fd_util {

void throw_io_failure(const char* what, bool add_errno_failure) {
    if (add_errno_failure) {
        std::ostringstream oss;
        oss << what << ": " << strerror(errno)
            << " [errno: " << errno << "]";
        throw std::ios_base::failure(oss.str());
    }
    throw std::ios_base::failure(what);
}

int rd_flags(native_socket_type fd) {
    auto flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        throw_io_failure("unable to read socket flags");
    }
    return flags;
}

bool nonblocking(native_socket_type fd) {
    return (rd_flags(fd) & O_NONBLOCK) != 0;
}

void nonblocking(native_socket_type fd, bool new_value) {
    auto rf = rd_flags(fd);
    auto wf = new_value ? (rf | O_NONBLOCK) : (rf & (~(O_NONBLOCK)));
    if (fcntl(fd, F_SETFL, wf) < 0) {
        throw_io_failure("unable to set file descriptor flags");
    }
}

bool tcp_nodelay(native_socket_type fd) {
    int flag;
    auto len = static_cast<socklen_t>(sizeof(flag));
    if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
        throw_io_failure("unable to read TCP_NODELAY socket option");
    }
    return flag != 0;
}

void tcp_nodelay(native_socket_type fd, bool new_value) {
    int flag = new_value ? 1 : 0;
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0) {
        throw_io_failure("unable to set TCP_NODELAY");
    }
}

void handle_write_result(ssize_t result, bool is_nonblocking_io) {
    if (result < 0) {
        if (is_nonblocking_io) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                return; // don't throw, just try again
            }
        }
        throw_io_failure("cannot write to file descriptor");
    }
}

void handle_read_result(ssize_t result, bool is_nonblocking_io) {
    handle_write_result(result, is_nonblocking_io);
    if (result == 0) {
        throw_io_failure("cannot read from closed socket / file handle");
    }
}

} } } // namespace cppa::detail::fd_util

#else

#endif
<commit_msg>improved error messages in fd_util<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation; either version 2.1 of the License,               *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#include <ios>
#include <sstream>

#include "cppa/exception.hpp"
#include "cppa/detail/fd_util.hpp"

#if defined(CPPA_LINUX) || defined(CPPA_MACOS)

#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

namespace cppa { namespace detail { namespace fd_util {

void throw_io_failure(const char* what, bool add_errno_failure) {
    if (add_errno_failure) {
        std::ostringstream oss;
        oss << what << ": " << strerror(errno)
            << " [errno: " << errno << "]";
        throw std::ios_base::failure(oss.str());
    }
    throw std::ios_base::failure(what);
}

int rd_flags(native_socket_type fd) {
    auto flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) throw_io_failure("unable to read socket flags");
    return flags;
}

bool nonblocking(native_socket_type fd) {
    return (rd_flags(fd) & O_NONBLOCK) != 0;
}

void nonblocking(native_socket_type fd, bool new_value) {
    auto rf = rd_flags(fd);
    auto wf = new_value ? (rf | O_NONBLOCK) : (rf & (~(O_NONBLOCK)));
    if (fcntl(fd, F_SETFL, wf) < 0) {
        throw_io_failure("unable to set file descriptor flags");
    }
}

bool tcp_nodelay(native_socket_type fd) {
    int flag;
    auto len = static_cast<socklen_t>(sizeof(flag));
    if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
        throw_io_failure("unable to read TCP_NODELAY socket option");
    }
    return flag != 0;
}

void tcp_nodelay(native_socket_type fd, bool new_value) {
    int flag = new_value ? 1 : 0;
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0) {
        throw_io_failure("unable to set TCP_NODELAY");
    }
}

void handle_io_result(ssize_t res, bool is_nonblock, const char* msg) {
    if (res < 0) {
        // don't throw for 'failed' non-blocking IO
        if (is_nonblock && (errno == EAGAIN || errno == EWOULDBLOCK)) { }
        else throw_io_failure(msg);
    }
}

void handle_write_result(ssize_t res, bool is_nonblock) {
    handle_io_result(res, is_nonblock, "cannot write to file descriptor");
}

void handle_read_result(ssize_t res, bool is_nonblock) {
    handle_io_result(res, is_nonblock, "cannot read from file descriptor");
    if (res == 0) throw_io_failure("cannot read from closed file descriptor");
}

} } } // namespace cppa::detail::fd_util

#else

#endif
<|endoftext|>


<commit_before>/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve.

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. */

#include "ParamUtil.h"

#include <fenv.h>
#include <stdio.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <limits>

#include <google/protobuf/text_format.h>
#include <paddle/utils/Version.h>

#include "paddle/utils/PythonUtil.h"
#include "paddle/utils/Stat.h"
#include "paddle/utils/Util.h"
#include "paddle/utils/GlobalConstants.h"

#include "paddle/gserver/gradientmachines/NeuralNetwork.h"
#include "paddle/gserver/layers/ValidationLayer.h"
#include "TesterConfig.h"

namespace paddle {

ParameterUtil::ParameterUtil(
    const std::shared_ptr<TrainerConfigHelper> &config,
    std::unique_ptr<ParameterUtilConfig> &&intconfig,
    const GradientMachinePtr &gradientMachine,
    const std::shared_ptr<ParameterUpdater> &parameterUpdater) {
  config_ = config;
  intConfig_ = std::move(intconfig);
  gserver_ = gradientMachine;
  pUpdater_ = parameterUpdater;
}

bool ParameterUtil::loadParameters(int passId, bool local, bool remote) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  snprintf(buf, kBufLen, "pass-%05d", passId);
  std::string doneFile = path::join(config_->getSaveDir(), buf, "done");
  if (!fileExist(doneFile.c_str())) return false;
  loadParametersWithPath(path::join(config_->getSaveDir(), buf), local, remote);
  return true;
}

void ParameterUtil::loadParametersWithPath(const std::string& dir,
                                    bool local, bool remote) {
  if (local) {
    gserver_->loadParameters(dir);
  }
  if (remote && pUpdater_) {
    pUpdater_->loadParametersRemote(dir);
  }
}

void ParameterUtil::saveParametersOnePass(int passId, int passInnerId) {
  pUpdater_->apply();
  saveParameters(passId, passInnerId);
  if (intConfig_->save_only_one_ && passId >= intConfig_->saving_period_) {
    deleteParameters(passId - intConfig_->saving_period_);
  }
  pUpdater_->restore();
}

void ParameterUtil::saveParameters(int passId, int passInnerId) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  if (passInnerId > 0) {
    snprintf(buf, kBufLen, "pass-%05d-%03d", passId, passInnerId);
  } else {
    snprintf(buf, kBufLen, "pass-%05d", passId);
  }

  std::string basePath = config_->getSaveDir();
  mkDirRecursively(basePath.c_str());

  std::string saveDir = path::join(basePath, buf);
  mkDir(saveDir.c_str());
  if (!intConfig_->load_save_param_pserver_) {
    pUpdater_->getParametersRemote(true /*full parameter*/,
                                  true /*after apply*/);
  }

  gserver_->saveParameters(saveDir);
  if (intConfig_->load_save_param_pserver_) {
    pUpdater_->saveParametersRemote(saveDir);
  }
  std::string doneFile = path::join(saveDir, "done");
  touchFile(doneFile.c_str());
  std::ofstream out(doneFile);
  version::printVersion(out);
  out.close();
  VLOG(1) << "save dir " << saveDir;
  saveConfigWithPath(saveDir);
}

void ParameterUtil::deleteParameters(int passId, int passInnerId) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  const std::string& saveDir = config_->getSaveDir();
  if (passInnerId > 0) {
    snprintf(buf, kBufLen, "%s/pass-%05d-%03d", saveDir.c_str(), passId,
             passInnerId);
  } else {
    snprintf(buf, kBufLen, "%s/pass-%05d", saveDir.c_str(), passId);
  }
  mkDir(saveDir.c_str());
  LOG(INFO) << "delete dir " << buf;
  rmDir(buf);
}

void ParameterUtil::saveConfigWithPath(const std::string& path) {
  std::string src;
  // save config in some path
  if (!intConfig_->config_.empty()) {
    src = intConfig_->config_;
  } else {
    bool ok;
    src = config_->getConfigName(&ok);
    if (!ok) {
      return;
    }
  }
  copyFileToPath(src, path);

  // save other import config file name to path.txt
  std::string ss = path::join(path, "path.txt");
  std::ofstream os(ss);
  std::string fileName = path::basename(src);
  CHECK(os.write(fileName.c_str(), fileName.length()))
      << "Fail to write config file name " << ss;
  VLOG(1) << "fileName " << fileName;
  os.close();

  // copy other import config files
  for (int i = 0; i < config_->getConfig().config_files_size(); ++i) {
    copyFileToPath(config_->getConfig().config_files(i), path);
  }
}

}  // namespace paddle
<commit_msg>Make Paddle --save_dir support a directory name  (#277)<commit_after>/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve.

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. */

#include "ParamUtil.h"

#include <fenv.h>
#include <stdio.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <limits>

#include <google/protobuf/text_format.h>
#include <paddle/utils/Version.h>

#include "paddle/utils/PythonUtil.h"
#include "paddle/utils/Stat.h"
#include "paddle/utils/Util.h"
#include "paddle/utils/GlobalConstants.h"

#include "paddle/gserver/gradientmachines/NeuralNetwork.h"
#include "paddle/gserver/layers/ValidationLayer.h"
#include "TesterConfig.h"

namespace paddle {

ParameterUtil::ParameterUtil(
    const std::shared_ptr<TrainerConfigHelper> &config,
    std::unique_ptr<ParameterUtilConfig> &&intconfig,
    const GradientMachinePtr &gradientMachine,
    const std::shared_ptr<ParameterUpdater> &parameterUpdater) {
  config_ = config;
  intConfig_ = std::move(intconfig);
  gserver_ = gradientMachine;
  pUpdater_ = parameterUpdater;
}

bool ParameterUtil::loadParameters(int passId, bool local, bool remote) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  snprintf(buf, kBufLen, "pass-%05d", passId);
  std::string doneFile = path::join(config_->getSaveDir(), buf, "done");
  if (!fileExist(doneFile.c_str())) return false;
  loadParametersWithPath(path::join(config_->getSaveDir(), buf), local, remote);
  return true;
}

void ParameterUtil::loadParametersWithPath(const std::string& dir,
                                    bool local, bool remote) {
  if (local) {
    gserver_->loadParameters(dir);
  }
  if (remote && pUpdater_) {
    pUpdater_->loadParametersRemote(dir);
  }
}

void ParameterUtil::saveParametersOnePass(int passId, int passInnerId) {
  pUpdater_->apply();
  saveParameters(passId, passInnerId);
  if (intConfig_->save_only_one_ && passId >= intConfig_->saving_period_) {
    deleteParameters(passId - intConfig_->saving_period_);
  }
  pUpdater_->restore();
}

void ParameterUtil::saveParameters(int passId, int passInnerId) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  if (passInnerId > 0) {
    snprintf(buf, kBufLen, "pass-%05d-%03d", passId, passInnerId);
  } else {
    snprintf(buf, kBufLen, "pass-%05d", passId);
  }

  std::string basePath = config_->getSaveDir();
  if (basePath.find('/') == std::string::npos) {
    basePath = "./" + basePath;
  }
  mkDirRecursively(basePath.c_str());

  std::string saveDir = path::join(basePath, buf);
  mkDir(saveDir.c_str());
  if (!intConfig_->load_save_param_pserver_) {
    pUpdater_->getParametersRemote(true /*full parameter*/,
                                  true /*after apply*/);
  }

  gserver_->saveParameters(saveDir);
  if (intConfig_->load_save_param_pserver_) {
    pUpdater_->saveParametersRemote(saveDir);
  }
  std::string doneFile = path::join(saveDir, "done");
  touchFile(doneFile.c_str());
  std::ofstream out(doneFile);
  version::printVersion(out);
  out.close();
  VLOG(1) << "save dir " << saveDir;
  saveConfigWithPath(saveDir);
}

void ParameterUtil::deleteParameters(int passId, int passInnerId) {
  constexpr int kBufLen = 100;
  char buf[kBufLen];
  const std::string& saveDir = config_->getSaveDir();
  if (passInnerId > 0) {
    snprintf(buf, kBufLen, "%s/pass-%05d-%03d", saveDir.c_str(), passId,
             passInnerId);
  } else {
    snprintf(buf, kBufLen, "%s/pass-%05d", saveDir.c_str(), passId);
  }
  mkDir(saveDir.c_str());
  LOG(INFO) << "delete dir " << buf;
  rmDir(buf);
}

void ParameterUtil::saveConfigWithPath(const std::string& path) {
  std::string src;
  // save config in some path
  if (!intConfig_->config_.empty()) {
    src = intConfig_->config_;
  } else {
    bool ok;
    src = config_->getConfigName(&ok);
    if (!ok) {
      return;
    }
  }
  copyFileToPath(src, path);

  // save other import config file name to path.txt
  std::string ss = path::join(path, "path.txt");
  std::ofstream os(ss);
  std::string fileName = path::basename(src);
  CHECK(os.write(fileName.c_str(), fileName.length()))
      << "Fail to write config file name " << ss;
  VLOG(1) << "fileName " << fileName;
  os.close();

  // copy other import config files
  for (int i = 0; i < config_->getConfig().config_files_size(); ++i) {
    copyFileToPath(config_->getConfig().config_files(i), path);
  }
}

}  // namespace paddle
<|endoftext|>


<commit_before>#include <assert.h>
#include <cstdio>

#include <set>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Bitcode/ReaderWriter.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include "llvm/LLVMDependenceGraph.h"
#include "llvm/PointsTo.h"
#include "llvm/ReachingDefs.h"
#include "llvm/DefUse.h"
#include "llvm/Slicer.h"
#include "DG2Dot.h"
#include "Utils.h"

using namespace dg;
using llvm::errs;

static std::ostream& printLLVMVal(std::ostream& os, const llvm::Value *val)
{
    if (!val) {
        os << "(null)";
        return os;
    }

    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    if (llvm::isa<llvm::Function>(val)) {
        ro << "FUNC " << val->getName().data();
    } else if (llvm::isa<llvm::BasicBlock>(val)) {
        ro << "label " << val->getName().data();
    } else {
        ro << *val;
    }

    ro.flush();

    // break the string if it is too long
    std::string str = ostr.str();
    if (str.length() > 100) {
        str.resize(40);
    }

    // escape the "
    size_t pos = 0;
    while ((pos = str.find('"', pos)) != std::string::npos) {
        str.replace(pos, 1, "\\\"");
        // we replaced one char with two, so we must shift after the new "
        pos += 2;
    }

    os << str;

    return os;
}

static std::ostream& operator<<(std::ostream& os, const analysis::Offset& off)
{
    if (off.offset == UNKNOWN_OFFSET)
        os << "UNKNOWN";
    else
        os << off.offset;
}

static bool debug_def = false;
static bool debug_ptr = false;

static bool checkNode(std::ostream& os, LLVMNode *node)
{
    bool err = false;
    const llvm::Value *val = node->getKey();

    if (!val) {
        os << "\\nERR: no value in node";
        return true;
    }

    if (!node->getBBlock()
        && !llvm::isa<llvm::Function>(val)
        && !llvm::isa<llvm::GlobalVariable>(val)) {
        err = true;
        os << "\\nERR: no BB";
    }

    if (debug_ptr) {
        const analysis::PointsToSetT& ptsto = node->getPointsTo();
        if (ptsto.empty() && val->getType()->isPointerTy()) {
            os << "\\lERR: pointer without pointsto set";
            err = true;
        } else
            os << "\\l -- points-to info --";

        for (auto it : ptsto) {
            os << "\\l[";
            if (it.isUnknown())
                os << "unknown";
            else if (it.obj->isUnknown())
                os << "unknown mem";
            else if (it.obj->isNull())
                os << "nullptr";
            else
                printLLVMVal(os, it.obj->node->getKey());
            os << "] + " << it.offset;
        }

        analysis::MemoryObj *mo = node->getMemoryObj();
        if (mo) {
            for (auto it : mo->pointsTo) {
                for(auto it2 : it.second) {
                    os << "\\lmem: [" << it.first << "] -> [";
                    if (it2.isUnknown())
                        os << "unknown";
                    else if (it2.obj->isUnknown())
                        os << "unknown mem";
                    else if (it2.obj->isNull())
                        os << "nullptr";
                    else
                        printLLVMVal(os, it2.obj->node->getKey());
                    os << "] + " << it2.offset;
                }
            }
        }
    }

    if (debug_def) {
        analysis::DefMap *df = node->getData<analysis::DefMap>();
        if (df) {
            os << "\\l -- reaching defs info --";
            for (auto it : df->getDefs()) {
                for (auto v : it.second) {
                    os << "\\l: [";
                    if (it.first.obj->isUnknown())
                        os << "[unknown";
                    else
                        printLLVMVal(os, it.first.obj->node->getKey());
                    os << "] + " << it.first.offset << " @ ";
                    printLLVMVal(os, v->getKey());
                }
            }
        }
    }

    return err;
}

static const char *slicing_criterion;
static bool mark_only = false;
static const char *dump_func_only = nullptr;

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    llvm::Module *M;
    const char *module = NULL;

    using namespace debug;
    uint32_t opts = PRINT_CFG | PRINT_DD | PRINT_CD;

    // parse options
    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "-no-control") == 0) {
            opts &= ~PRINT_CD;
        } else if (strcmp(argv[i], "-no-data") == 0) {
            opts &= ~PRINT_DD;
        } else if (strcmp(argv[i], "-nocfg") == 0) {
            opts &= ~PRINT_CFG;
        } else if (strcmp(argv[i], "-call") == 0) {
            opts |= PRINT_CALL;
        } else if (strcmp(argv[i], "-cfgall") == 0) {
            opts |= PRINT_CFG;
            opts |= PRINT_REV_CFG;
        } else if (strcmp(argv[i], "-func") == 0) {
            dump_func_only = argv[++i];
        } else if (strcmp(argv[i], "-def") == 0) {
            debug_def = true;
        } else if (strcmp(argv[i], "-ptr") == 0) {
            debug_ptr = true;
        } else if (strcmp(argv[i], "-slice") == 0) {
            slicing_criterion = argv[++i];
        } else if (strcmp(argv[i], "-mark") == 0) {
            mark_only = true;
            slicing_criterion = argv[++i];
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::ParseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    debug::TimeMeasure tm;

    LLVMDependenceGraph d;
    d.build(M);

    analysis::LLVMPointsToAnalysis PTA(&d);

    tm.start();
    PTA.run();
    tm.stop();
    tm.report("INFO: Points-to analysis took");

    std::set<LLVMNode *> callsites;
    if (slicing_criterion) {
        const char *sc[] = {
            slicing_criterion,
            "klee_assume",
            NULL
        };

        tm.start();
        d.getCallSites(sc, &callsites);
        tm.stop();
        tm.report("INFO: Finding slicing criterions took");
    }

    analysis::LLVMReachingDefsAnalysis RDA(&d);
    tm.start();
    RDA.run();  // compute reaching definitions
    tm.stop();
    tm.report("INFO: Reaching defs analysis took");

    analysis::LLVMDefUseAnalysis DUA(&d);
    tm.start();
    DUA.run(); // add def-use edges according that
    tm.stop();
    tm.report("INFO: Adding Def-Use edges took");

    tm.start();
    // add post-dominator frontiers
    d.computePostDominators(true);
    tm.stop();
    tm.report("INFO: computing post-dominator frontiers took");

    if (slicing_criterion) {
        LLVMSlicer slicer;
        tm.start();

        if (strcmp(slicing_criterion, "ret") == 0) {
            if (mark_only)
                slicer.mark(d.getExit());
            else
                slicer.slice(&d, d.getExit());
        } else {
            if (callsites.empty()) {
                errs() << "ERR: slicing criterion not found: "
                       << slicing_criterion << "\n";
                exit(1);
            }

            uint32_t slid = 0;
            for (LLVMNode *start : callsites)
                slid = slicer.mark(start, slid);

            if (!mark_only)
               slicer.slice(&d, nullptr, slid);
        }

        // there's overhead but nevermind
        tm.stop();
        tm.report("INFO: Slicing took");

        if (!mark_only) {
            std::string fl(module);
            fl.append(".sliced");
            std::ofstream ofs(fl);
            llvm::raw_os_ostream output(ofs);

            auto st = slicer.getStatistics();
            errs() << "INFO: Sliced away " << st.second
                   << " from " << st.first << " nodes\n";

            llvm::WriteBitcodeToFile(M, output);
        }
    }

    debug::DG2Dot<LLVMNode> dump(&d, opts);

    dump.printKey = printLLVMVal;
    dump.checkNode = checkNode;
    const std::map<const llvm::Value *,
                   LLVMDependenceGraph *>& CF = getConstructedFunctions();

    dump.start();
    for (auto F : CF) {
        if (dump_func_only && !F.first->getName().equals(dump_func_only))
            continue;

        dump.dumpSubgraphStart(F.second, F.first->getName().data());

        for (auto B : F.second->getConstructedBlocks()) {
            dump.dumpBBlock(B.second);
        }

        for (auto B : F.second->getConstructedBlocks()) {
            dump.dumpBBlockEdges(B.second);
        }

        dump.dumpSubgraphEnd(F.second);
    }

    dump.end();

    return 0;
}
<commit_msg>llvm-dg-dump: add -postdom option<commit_after>#include <assert.h>
#include <cstdio>

#include <set>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Bitcode/ReaderWriter.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include "llvm/LLVMDependenceGraph.h"
#include "llvm/PointsTo.h"
#include "llvm/ReachingDefs.h"
#include "llvm/DefUse.h"
#include "llvm/Slicer.h"
#include "DG2Dot.h"
#include "Utils.h"

using namespace dg;
using llvm::errs;

static std::ostream& printLLVMVal(std::ostream& os, const llvm::Value *val)
{
    if (!val) {
        os << "(null)";
        return os;
    }

    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    if (llvm::isa<llvm::Function>(val)) {
        ro << "FUNC " << val->getName().data();
    } else if (llvm::isa<llvm::BasicBlock>(val)) {
        ro << "label " << val->getName().data();
    } else {
        ro << *val;
    }

    ro.flush();

    // break the string if it is too long
    std::string str = ostr.str();
    if (str.length() > 100) {
        str.resize(40);
    }

    // escape the "
    size_t pos = 0;
    while ((pos = str.find('"', pos)) != std::string::npos) {
        str.replace(pos, 1, "\\\"");
        // we replaced one char with two, so we must shift after the new "
        pos += 2;
    }

    os << str;

    return os;
}

static std::ostream& operator<<(std::ostream& os, const analysis::Offset& off)
{
    if (off.offset == UNKNOWN_OFFSET)
        os << "UNKNOWN";
    else
        os << off.offset;
}

static bool debug_def = false;
static bool debug_ptr = false;

static bool checkNode(std::ostream& os, LLVMNode *node)
{
    bool err = false;
    const llvm::Value *val = node->getKey();

    if (!val) {
        os << "\\nERR: no value in node";
        return true;
    }

    if (!node->getBBlock()
        && !llvm::isa<llvm::Function>(val)
        && !llvm::isa<llvm::GlobalVariable>(val)) {
        err = true;
        os << "\\nERR: no BB";
    }

    if (debug_ptr) {
        const analysis::PointsToSetT& ptsto = node->getPointsTo();
        if (ptsto.empty() && val->getType()->isPointerTy()) {
            os << "\\lERR: pointer without pointsto set";
            err = true;
        } else
            os << "\\l -- points-to info --";

        for (auto it : ptsto) {
            os << "\\l[";
            if (it.isUnknown())
                os << "unknown";
            else if (it.obj->isUnknown())
                os << "unknown mem";
            else if (it.obj->isNull())
                os << "nullptr";
            else
                printLLVMVal(os, it.obj->node->getKey());
            os << "] + " << it.offset;
        }

        analysis::MemoryObj *mo = node->getMemoryObj();
        if (mo) {
            for (auto it : mo->pointsTo) {
                for(auto it2 : it.second) {
                    os << "\\lmem: [" << it.first << "] -> [";
                    if (it2.isUnknown())
                        os << "unknown";
                    else if (it2.obj->isUnknown())
                        os << "unknown mem";
                    else if (it2.obj->isNull())
                        os << "nullptr";
                    else
                        printLLVMVal(os, it2.obj->node->getKey());
                    os << "] + " << it2.offset;
                }
            }
        }
    }

    if (debug_def) {
        analysis::DefMap *df = node->getData<analysis::DefMap>();
        if (df) {
            os << "\\l -- reaching defs info --";
            for (auto it : df->getDefs()) {
                for (auto v : it.second) {
                    os << "\\l: [";
                    if (it.first.obj->isUnknown())
                        os << "[unknown";
                    else
                        printLLVMVal(os, it.first.obj->node->getKey());
                    os << "] + " << it.first.offset << " @ ";
                    printLLVMVal(os, v->getKey());
                }
            }
        }
    }

    return err;
}

static const char *slicing_criterion;
static bool mark_only = false;
static const char *dump_func_only = nullptr;

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    llvm::Module *M;
    const char *module = NULL;

    using namespace debug;
    uint32_t opts = PRINT_CFG | PRINT_DD | PRINT_CD;

    // parse options
    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "-no-control") == 0) {
            opts &= ~PRINT_CD;
        } else if (strcmp(argv[i], "-no-data") == 0) {
            opts &= ~PRINT_DD;
        } else if (strcmp(argv[i], "-nocfg") == 0) {
            opts &= ~PRINT_CFG;
        } else if (strcmp(argv[i], "-call") == 0) {
            opts |= PRINT_CALL;
        } else if (strcmp(argv[i], "-postdom") == 0) {
            opts |= PRINT_POSTDOM;
        } else if (strcmp(argv[i], "-cfgall") == 0) {
            opts |= PRINT_CFG;
            opts |= PRINT_REV_CFG;
        } else if (strcmp(argv[i], "-func") == 0) {
            dump_func_only = argv[++i];
        } else if (strcmp(argv[i], "-def") == 0) {
            debug_def = true;
        } else if (strcmp(argv[i], "-ptr") == 0) {
            debug_ptr = true;
        } else if (strcmp(argv[i], "-slice") == 0) {
            slicing_criterion = argv[++i];
        } else if (strcmp(argv[i], "-mark") == 0) {
            mark_only = true;
            slicing_criterion = argv[++i];
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::ParseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    debug::TimeMeasure tm;

    LLVMDependenceGraph d;
    d.build(M);

    analysis::LLVMPointsToAnalysis PTA(&d);

    tm.start();
    PTA.run();
    tm.stop();
    tm.report("INFO: Points-to analysis took");

    std::set<LLVMNode *> callsites;
    if (slicing_criterion) {
        const char *sc[] = {
            slicing_criterion,
            "klee_assume",
            NULL
        };

        tm.start();
        d.getCallSites(sc, &callsites);
        tm.stop();
        tm.report("INFO: Finding slicing criterions took");
    }

    analysis::LLVMReachingDefsAnalysis RDA(&d);
    tm.start();
    RDA.run();  // compute reaching definitions
    tm.stop();
    tm.report("INFO: Reaching defs analysis took");

    analysis::LLVMDefUseAnalysis DUA(&d);
    tm.start();
    DUA.run(); // add def-use edges according that
    tm.stop();
    tm.report("INFO: Adding Def-Use edges took");

    tm.start();
    // add post-dominator frontiers
    d.computePostDominators(true);
    tm.stop();
    tm.report("INFO: computing post-dominator frontiers took");

    if (slicing_criterion) {
        LLVMSlicer slicer;
        tm.start();

        if (strcmp(slicing_criterion, "ret") == 0) {
            if (mark_only)
                slicer.mark(d.getExit());
            else
                slicer.slice(&d, d.getExit());
        } else {
            if (callsites.empty()) {
                errs() << "ERR: slicing criterion not found: "
                       << slicing_criterion << "\n";
                exit(1);
            }

            uint32_t slid = 0;
            for (LLVMNode *start : callsites)
                slid = slicer.mark(start, slid);

            if (!mark_only)
               slicer.slice(&d, nullptr, slid);
        }

        // there's overhead but nevermind
        tm.stop();
        tm.report("INFO: Slicing took");

        if (!mark_only) {
            std::string fl(module);
            fl.append(".sliced");
            std::ofstream ofs(fl);
            llvm::raw_os_ostream output(ofs);

            auto st = slicer.getStatistics();
            errs() << "INFO: Sliced away " << st.second
                   << " from " << st.first << " nodes\n";

            llvm::WriteBitcodeToFile(M, output);
        }
    }

    debug::DG2Dot<LLVMNode> dump(&d, opts);

    dump.printKey = printLLVMVal;
    dump.checkNode = checkNode;
    const std::map<const llvm::Value *,
                   LLVMDependenceGraph *>& CF = getConstructedFunctions();

    dump.start();
    for (auto F : CF) {
        if (dump_func_only && !F.first->getName().equals(dump_func_only))
            continue;

        dump.dumpSubgraphStart(F.second, F.first->getName().data());

        for (auto B : F.second->getConstructedBlocks()) {
            dump.dumpBBlock(B.second);
        }

        for (auto B : F.second->getConstructedBlocks()) {
            dump.dumpBBlockEdges(B.second);
        }

        dump.dumpSubgraphEnd(F.second);
    }

    dump.end();

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include "gtest/gtest.h"

#include <hspp/Managers/GameAgent.hpp>
#include <hspp/Tasks/PlayerTasks/GameEndTask.hpp>

using namespace Hearthstonepp;
using namespace PlayerTasks;

TEST(GameEndTask, GetTaskID)
{
    const GameEndTask gameEnd;
    EXPECT_EQ(gameEnd.GetTaskID(), +TaskID::GAME_END);
}

TEST(GameEndTask, Run)
{
    GameEndTask gameEnd;
    GameAgent agent(CardClass::ROGUE, CardClass::DRUID, PlayerType::PLAYER1);

    agent.GetPlayer1().SetID(100);

    MetaData result = gameEnd.Run(agent.GetPlayer1());
    EXPECT_EQ(result, MetaData::GAME_END);

    TaskMeta meta;
    result = gameEnd.Run(agent.GetPlayer1(), meta);
    EXPECT_EQ(result, MetaData::GAME_END);
    EXPECT_EQ(meta.GetID(), +TaskID::GAME_END);
    EXPECT_EQ(meta.GetStatus(), MetaData::GAME_END);
    EXPECT_EQ(meta.GetUserID(), agent.GetPlayer1().GetID());
}
<commit_msg>refactor: Replace GameAgent to Game<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include "gtest/gtest.h"

#include <hspp/Game/Game.hpp>
#include <hspp/Tasks/PlayerTasks/GameEndTask.hpp>

using namespace Hearthstonepp;
using namespace PlayerTasks;

TEST(GameEndTask, GetTaskID)
{
    const GameEndTask gameEnd;
    EXPECT_EQ(gameEnd.GetTaskID(), +TaskID::GAME_END);
}

TEST(GameEndTask, Run)
{
    GameEndTask gameEnd;
    Game game(CardClass::ROGUE, CardClass::DRUID, PlayerType::PLAYER1);

    game.GetPlayer1().SetID(100);

    MetaData result = gameEnd.Run(game.GetPlayer1());
    EXPECT_EQ(result, MetaData::GAME_END);
}
<|endoftext|>


<commit_before>#include "MipsExecutor.h"

CMipsExecutor::CMipsExecutor(CMIPS& context, uint32 maxAddress)
: m_context(context)
, m_subTableCount(0)
#ifdef DEBUGGER_INCLUDED
, m_breakpointsDisabledOnce(false)
#endif
{
	if(maxAddress < 0x10000)
	{
		maxAddress = 0x10000;
	}
	assert((maxAddress & 0xFFFF) == 0);
	if(maxAddress == 0)
	{
		m_subTableCount = 0x10000;
	}
	else
	{
		m_subTableCount = maxAddress / 0x10000;
	}
	m_blockTable = new CBasicBlock**[m_subTableCount];
	memset(m_blockTable, 0, sizeof(CBasicBlock**) * m_subTableCount);
}

CMipsExecutor::~CMipsExecutor()
{
	for(unsigned int i = 0; i < m_subTableCount; i++)
	{
		CBasicBlock** subTable = m_blockTable[i];
		if(subTable != NULL)
		{
			delete [] subTable;
		}
	}
	delete [] m_blockTable;
}

void CMipsExecutor::Reset()
{
	ClearActiveBlocks();
}

void CMipsExecutor::ClearActiveBlocks()
{
	for(unsigned int i = 0; i < m_subTableCount; i++)
	{
		CBasicBlock** subTable = m_blockTable[i];
		if(subTable != NULL)
		{
			for(uint32 lo = 0; lo < 0x10000; lo += 4)
			{
				auto block = subTable[lo / 4];
				if(block != nullptr)
				{
					//We reset the values here because the block might
					//still be held by another object (ie.: VuExecutor)
					block->ClearReferers();
					block->SetLinkedBlock(0, nullptr);
					block->SetLinkedBlock(1, nullptr);
				}
			}
			delete [] subTable;
			m_blockTable[i] = NULL;
		}
	}

	m_blocks.clear();
}

void CMipsExecutor::ClearActiveBlocksInRange(uint32 start, uint32 end)
{
	uint32 hiStart = start >> 16;
	uint32 hiEnd = end >> 16;

	std::set<CBasicBlock*> blocksToDelete;

	for(uint32 hi = hiStart; hi <= hiEnd; hi++)
	{
		CBasicBlock** table = m_blockTable[hi];
		if(table == nullptr) continue;

		for(uint32 lo = 0; lo < 0x10000; lo += 4)
		{
			uint32 tableAddress = (hi << 16) | lo;
			if(tableAddress < start) continue;
			if(tableAddress >= end) continue;
			CBasicBlock* block = table[lo / 4];
			if(block == nullptr) continue;
			table[lo / 4] = nullptr;
			blocksToDelete.insert(block);
		}
	}

	if(!blocksToDelete.empty())
	{
		//TODO: Actually delete the blocks, because remove_if only rearranges items leaving us a new end iterator
		m_blocks.remove_if([&] (const BasicBlockPtr& block) { return blocksToDelete.find(block.get()) != std::end(blocksToDelete); });
	}
}

int CMipsExecutor::Execute(int cycles)
{
	CBasicBlock* block(nullptr);
	while(cycles > 0)
	{
		uint32 address = m_context.m_pAddrTranslator(&m_context, m_context.m_State.nPC);
		if(!block || address != block->GetBeginAddress())
		{
			block = FindBlockStartingAt(address);
			if(block == NULL)
			{
				//We need to partition the space and compile the blocks
				PartitionFunction(address);
				block = FindBlockStartingAt(address);
				if(block == NULL)
				{
					throw std::runtime_error("Couldn't create block starting at address.");
				}
			}
			if(!block->IsCompiled())
			{
				block->Compile();
			}
		}
		else if(block != NULL)
		{
			block->SetSelfLoopCount(block->GetSelfLoopCount() + 1);
		}

#ifdef DEBUGGER_INCLUDED
		if(!m_breakpointsDisabledOnce && MustBreak()) break;
		m_breakpointsDisabledOnce = false;
#endif
		cycles -= block->Execute();
		if(m_context.m_State.nHasException) break;
	}
	return cycles;
}

#ifdef DEBUGGER_INCLUDED

bool CMipsExecutor::MustBreak() const
{
	uint32 currentPc = m_context.m_pAddrTranslator(&m_context, m_context.m_State.nPC);
	CBasicBlock* block = FindBlockAt(currentPc);
	for(auto breakPointIterator(m_context.m_breakpoints.begin());
		breakPointIterator != m_context.m_breakpoints.end(); breakPointIterator++)
	{
		uint32 breakPointAddress = *breakPointIterator;
		if(currentPc == breakPointAddress) return true;
		if(block != NULL)
		{
			if(breakPointAddress >= block->GetBeginAddress() && breakPointAddress <= block->GetEndAddress()) return true;
		}
	}
	return false;
}

void CMipsExecutor::DisableBreakpointsOnce()
{
	m_breakpointsDisabledOnce = true;
}

#endif

CBasicBlock* CMipsExecutor::FindBlockAt(uint32 address) const
{
	uint32 hiAddress = address >> 16;
	uint32 loAddress = address & 0xFFFF;
	assert(hiAddress < m_subTableCount);
	CBasicBlock**& subTable = m_blockTable[hiAddress];
	if(subTable == NULL) return NULL;
	CBasicBlock* result = subTable[loAddress / 4];
	return result;
}

CBasicBlock* CMipsExecutor::FindBlockStartingAt(uint32 address) const
{
	uint32 hiAddress = address >> 16;
	uint32 loAddress = address & 0xFFFF;
	assert(hiAddress < m_subTableCount);
	CBasicBlock**& subTable = m_blockTable[hiAddress];
	if(subTable == NULL) return NULL;
	CBasicBlock* result = subTable[loAddress / 4];
	if((address != 0) && (FindBlockAt(address - 4) == result))
	{
		return NULL;
	}
	return result;
}

void CMipsExecutor::CreateBlock(uint32 start, uint32 end)
{
	{
		CBasicBlock* block = FindBlockAt(start);
		if(block)
		{
			//If the block starts and ends at the same place, block already exists and doesn't need
			//to be re-created
			uint32 otherBegin = block->GetBeginAddress();
			uint32 otherEnd = block->GetEndAddress();
			if((otherBegin == start) && (otherEnd == end))
			{
				return;
			}
			if(otherEnd == end)
			{
				//Repartition the existing block if end of both blocks are the same
				DeleteBlock(block);
				CreateBlock(otherBegin, start - 4);
				assert(FindBlockAt(start) == NULL);
			}
			else if(otherBegin == start)
			{
				DeleteBlock(block);
				CreateBlock(end + 4, otherEnd);
				assert(FindBlockAt(end) == NULL);
			}
			else
			{
				//Delete the currently existing block otherwise
				printf("MipsExecutor: Warning. Deleting block at %0.8X.\r\n", block->GetEndAddress());
				DeleteBlock(block);
			}
		}
	}
	assert(FindBlockAt(end) == NULL);
	{
		BasicBlockPtr block = BlockFactory(m_context, start, end);
		for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
		{
			uint32 hiAddress = address >> 16;
			uint32 loAddress = address & 0xFFFF;
			assert(hiAddress < m_subTableCount);
			CBasicBlock**& subTable = m_blockTable[hiAddress];
			if(subTable == NULL)
			{
				const uint32 subTableSize = 0x10000 / 4;
				subTable = new CBasicBlock*[subTableSize];
				memset(subTable, 0, sizeof(CBasicBlock*) * subTableSize);
			}
			assert(subTable[loAddress / 4] == NULL);
			subTable[loAddress / 4] = block.get();
		}
		m_blocks.push_back(std::move(block));
	}
}

void CMipsExecutor::DeleteBlock(CBasicBlock* block)
{
	for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
	{
		uint32 hiAddress = address >> 16;
		uint32 loAddress = address & 0xFFFF;
		assert(hiAddress < m_subTableCount);
		CBasicBlock**& subTable = m_blockTable[hiAddress];
		assert(subTable != NULL);
		assert(subTable[loAddress / 4] != NULL);
		subTable[loAddress / 4] = NULL;
	}

	//Remove block from our lists
	auto blockIterator = std::find_if(std::begin(m_blocks), std::end(m_blocks), [&] (const BasicBlockPtr& blockPtr) { return blockPtr.get() == block; });
	assert(blockIterator != std::end(m_blocks));
	m_blocks.erase(blockIterator);
}

CMipsExecutor::BasicBlockPtr CMipsExecutor::BlockFactory(CMIPS& context, uint32 start, uint32 end)
{
	return std::make_shared<CBasicBlock>(context, start, end);
}

void CMipsExecutor::PartitionFunction(uint32 functionAddress)
{
	typedef std::set<uint32> PartitionPointSet;
	uint32 endAddress = 0;
	PartitionPointSet partitionPoints;

	//Insert begin point
	partitionPoints.insert(functionAddress);

	//Find the end
	for(uint32 address = functionAddress; ; address += 4)
	{
		//Probably going too far...
		if((address - functionAddress) > 0x10000)
		{
			printf("MipsExecutor: Warning. Found no JR after a big distance.\r\n");
			endAddress = address;
			partitionPoints.insert(endAddress);
			break;
		}
		uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
		if(opcode == 0x03E00008)
		{
			//+4 for delay slot
			endAddress = address + 4;
			partitionPoints.insert(endAddress + 4);
			break;
		}
	}

	//Find partition points within the function
	for(uint32 address = functionAddress; address <= endAddress; address += 4)
	{
		uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
		MIPS_BRANCH_TYPE branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
		if(branchType == MIPS_BRANCH_NORMAL)
		{
			partitionPoints.insert(address + 8);
			uint32 target = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
			if(target > functionAddress && target < endAddress)
			{
				partitionPoints.insert(target);
			}
		}
		else if(branchType == MIPS_BRANCH_NODELAY)
		{
			partitionPoints.insert(address + 4);
		}
		//Check if there's a block already exising that this address
		if(address != endAddress)
		{
			CBasicBlock* possibleBlock = FindBlockStartingAt(address);
			if(possibleBlock)
			{
				//assert(possibleBlock->GetEndAddress() <= endAddress);
				//Add its beginning and end in the partition points
				partitionPoints.insert(possibleBlock->GetBeginAddress());
				partitionPoints.insert(possibleBlock->GetEndAddress() + 4);
			}
		}
	}

	//Check if blocks are too big
	{
		uint32 currentPoint = -1;
		for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
			pointIterator != partitionPoints.end(); pointIterator++)
		{
			if(currentPoint != -1)
			{
				uint32 startPos = currentPoint;
				uint32 endPos = *pointIterator;
				uint32 distance = (endPos - startPos);
				if(distance > 0x400)
				{
					uint32 middlePos = ((endPos + startPos) / 2) & ~0x03;
					pointIterator = partitionPoints.insert(middlePos).first;
					pointIterator--;
					continue;
				}
			}
			currentPoint = *pointIterator;
		}
	}

	//Create blocks
	{
		uint32 currentPoint = -1;
		for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
			pointIterator != partitionPoints.end(); pointIterator++)
		{
			if(currentPoint != -1)
			{
				CreateBlock(currentPoint, *pointIterator - 4);
			}
			currentPoint = *pointIterator;
		}
	}
}
<commit_msg>Revert "Fixed blocks still being linked to old blocks after ClearActiveBlocks is called."<commit_after>#include "MipsExecutor.h"

CMipsExecutor::CMipsExecutor(CMIPS& context, uint32 maxAddress)
: m_context(context)
, m_subTableCount(0)
#ifdef DEBUGGER_INCLUDED
, m_breakpointsDisabledOnce(false)
#endif
{
	if(maxAddress < 0x10000)
	{
		maxAddress = 0x10000;
	}
	assert((maxAddress & 0xFFFF) == 0);
	if(maxAddress == 0)
	{
		m_subTableCount = 0x10000;
	}
	else
	{
		m_subTableCount = maxAddress / 0x10000;
	}
	m_blockTable = new CBasicBlock**[m_subTableCount];
	memset(m_blockTable, 0, sizeof(CBasicBlock**) * m_subTableCount);
}

CMipsExecutor::~CMipsExecutor()
{
	for(unsigned int i = 0; i < m_subTableCount; i++)
	{
		CBasicBlock** subTable = m_blockTable[i];
		if(subTable != NULL)
		{
			delete [] subTable;
		}
	}
	delete [] m_blockTable;
}

void CMipsExecutor::Reset()
{
	ClearActiveBlocks();
}

void CMipsExecutor::ClearActiveBlocks()
{
	for(unsigned int i = 0; i < m_subTableCount; i++)
	{
		CBasicBlock** subTable = m_blockTable[i];
		if(subTable != NULL)
		{
			delete [] subTable;
			m_blockTable[i] = NULL;
		}
	}

	m_blocks.clear();
}

void CMipsExecutor::ClearActiveBlocksInRange(uint32 start, uint32 end)
{
	uint32 hiStart = start >> 16;
	uint32 hiEnd = end >> 16;

	std::set<CBasicBlock*> blocksToDelete;

	for(uint32 hi = hiStart; hi <= hiEnd; hi++)
	{
		CBasicBlock** table = m_blockTable[hi];
		if(table == nullptr) continue;

		for(uint32 lo = 0; lo < 0x10000; lo += 4)
		{
			uint32 tableAddress = (hi << 16) | lo;
			if(tableAddress < start) continue;
			if(tableAddress >= end) continue;
			CBasicBlock* block = table[lo / 4];
			if(block == nullptr) continue;
			table[lo / 4] = nullptr;
			blocksToDelete.insert(block);
		}
	}

	if(!blocksToDelete.empty())
	{
		//TODO: Actually delete the blocks, because remove_if only rearranges items leaving us a new end iterator
		m_blocks.remove_if([&] (const BasicBlockPtr& block) { return blocksToDelete.find(block.get()) != std::end(blocksToDelete); });
	}
}

int CMipsExecutor::Execute(int cycles)
{
	CBasicBlock* block(nullptr);
	while(cycles > 0)
	{
		uint32 address = m_context.m_pAddrTranslator(&m_context, m_context.m_State.nPC);
		if(!block || address != block->GetBeginAddress())
		{
			block = FindBlockStartingAt(address);
			if(block == NULL)
			{
				//We need to partition the space and compile the blocks
				PartitionFunction(address);
				block = FindBlockStartingAt(address);
				if(block == NULL)
				{
					throw std::runtime_error("Couldn't create block starting at address.");
				}
			}
			if(!block->IsCompiled())
			{
				block->Compile();
			}
		}
		else if(block != NULL)
		{
			block->SetSelfLoopCount(block->GetSelfLoopCount() + 1);
		}

#ifdef DEBUGGER_INCLUDED
		if(!m_breakpointsDisabledOnce && MustBreak()) break;
		m_breakpointsDisabledOnce = false;
#endif
		cycles -= block->Execute();
		if(m_context.m_State.nHasException) break;
	}
	return cycles;
}

#ifdef DEBUGGER_INCLUDED

bool CMipsExecutor::MustBreak() const
{
	uint32 currentPc = m_context.m_pAddrTranslator(&m_context, m_context.m_State.nPC);
	CBasicBlock* block = FindBlockAt(currentPc);
	for(auto breakPointIterator(m_context.m_breakpoints.begin());
		breakPointIterator != m_context.m_breakpoints.end(); breakPointIterator++)
	{
		uint32 breakPointAddress = *breakPointIterator;
		if(currentPc == breakPointAddress) return true;
		if(block != NULL)
		{
			if(breakPointAddress >= block->GetBeginAddress() && breakPointAddress <= block->GetEndAddress()) return true;
		}
	}
	return false;
}

void CMipsExecutor::DisableBreakpointsOnce()
{
	m_breakpointsDisabledOnce = true;
}

#endif

CBasicBlock* CMipsExecutor::FindBlockAt(uint32 address) const
{
	uint32 hiAddress = address >> 16;
	uint32 loAddress = address & 0xFFFF;
	assert(hiAddress < m_subTableCount);
	CBasicBlock**& subTable = m_blockTable[hiAddress];
	if(subTable == NULL) return NULL;
	CBasicBlock* result = subTable[loAddress / 4];
	return result;
}

CBasicBlock* CMipsExecutor::FindBlockStartingAt(uint32 address) const
{
	uint32 hiAddress = address >> 16;
	uint32 loAddress = address & 0xFFFF;
	assert(hiAddress < m_subTableCount);
	CBasicBlock**& subTable = m_blockTable[hiAddress];
	if(subTable == NULL) return NULL;
	CBasicBlock* result = subTable[loAddress / 4];
	if((address != 0) && (FindBlockAt(address - 4) == result))
	{
		return NULL;
	}
	return result;
}

void CMipsExecutor::CreateBlock(uint32 start, uint32 end)
{
	{
		CBasicBlock* block = FindBlockAt(start);
		if(block)
		{
			//If the block starts and ends at the same place, block already exists and doesn't need
			//to be re-created
			uint32 otherBegin = block->GetBeginAddress();
			uint32 otherEnd = block->GetEndAddress();
			if((otherBegin == start) && (otherEnd == end))
			{
				return;
			}
			if(otherEnd == end)
			{
				//Repartition the existing block if end of both blocks are the same
				DeleteBlock(block);
				CreateBlock(otherBegin, start - 4);
				assert(FindBlockAt(start) == NULL);
			}
			else if(otherBegin == start)
			{
				DeleteBlock(block);
				CreateBlock(end + 4, otherEnd);
				assert(FindBlockAt(end) == NULL);
			}
			else
			{
				//Delete the currently existing block otherwise
				printf("MipsExecutor: Warning. Deleting block at %0.8X.\r\n", block->GetEndAddress());
				DeleteBlock(block);
			}
		}
	}
	assert(FindBlockAt(end) == NULL);
	{
		BasicBlockPtr block = BlockFactory(m_context, start, end);
		for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
		{
			uint32 hiAddress = address >> 16;
			uint32 loAddress = address & 0xFFFF;
			assert(hiAddress < m_subTableCount);
			CBasicBlock**& subTable = m_blockTable[hiAddress];
			if(subTable == NULL)
			{
				const uint32 subTableSize = 0x10000 / 4;
				subTable = new CBasicBlock*[subTableSize];
				memset(subTable, 0, sizeof(CBasicBlock*) * subTableSize);
			}
			assert(subTable[loAddress / 4] == NULL);
			subTable[loAddress / 4] = block.get();
		}
		m_blocks.push_back(std::move(block));
	}
}

void CMipsExecutor::DeleteBlock(CBasicBlock* block)
{
	for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
	{
		uint32 hiAddress = address >> 16;
		uint32 loAddress = address & 0xFFFF;
		assert(hiAddress < m_subTableCount);
		CBasicBlock**& subTable = m_blockTable[hiAddress];
		assert(subTable != NULL);
		assert(subTable[loAddress / 4] != NULL);
		subTable[loAddress / 4] = NULL;
	}

	//Remove block from our lists
	auto blockIterator = std::find_if(std::begin(m_blocks), std::end(m_blocks), [&] (const BasicBlockPtr& blockPtr) { return blockPtr.get() == block; });
	assert(blockIterator != std::end(m_blocks));
	m_blocks.erase(blockIterator);
}

CMipsExecutor::BasicBlockPtr CMipsExecutor::BlockFactory(CMIPS& context, uint32 start, uint32 end)
{
	return std::make_shared<CBasicBlock>(context, start, end);
}

void CMipsExecutor::PartitionFunction(uint32 functionAddress)
{
	typedef std::set<uint32> PartitionPointSet;
	uint32 endAddress = 0;
	PartitionPointSet partitionPoints;

	//Insert begin point
	partitionPoints.insert(functionAddress);

	//Find the end
	for(uint32 address = functionAddress; ; address += 4)
	{
		//Probably going too far...
		if((address - functionAddress) > 0x10000)
		{
			printf("MipsExecutor: Warning. Found no JR after a big distance.\r\n");
			endAddress = address;
			partitionPoints.insert(endAddress);
			break;
		}
		uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
		if(opcode == 0x03E00008)
		{
			//+4 for delay slot
			endAddress = address + 4;
			partitionPoints.insert(endAddress + 4);
			break;
		}
	}

	//Find partition points within the function
	for(uint32 address = functionAddress; address <= endAddress; address += 4)
	{
		uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
		MIPS_BRANCH_TYPE branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
		if(branchType == MIPS_BRANCH_NORMAL)
		{
			partitionPoints.insert(address + 8);
			uint32 target = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
			if(target > functionAddress && target < endAddress)
			{
				partitionPoints.insert(target);
			}
		}
		else if(branchType == MIPS_BRANCH_NODELAY)
		{
			partitionPoints.insert(address + 4);
		}
		//Check if there's a block already exising that this address
		if(address != endAddress)
		{
			CBasicBlock* possibleBlock = FindBlockStartingAt(address);
			if(possibleBlock)
			{
				//assert(possibleBlock->GetEndAddress() <= endAddress);
				//Add its beginning and end in the partition points
				partitionPoints.insert(possibleBlock->GetBeginAddress());
				partitionPoints.insert(possibleBlock->GetEndAddress() + 4);
			}
		}
	}

	//Check if blocks are too big
	{
		uint32 currentPoint = -1;
		for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
			pointIterator != partitionPoints.end(); pointIterator++)
		{
			if(currentPoint != -1)
			{
				uint32 startPos = currentPoint;
				uint32 endPos = *pointIterator;
				uint32 distance = (endPos - startPos);
				if(distance > 0x400)
				{
					uint32 middlePos = ((endPos + startPos) / 2) & ~0x03;
					pointIterator = partitionPoints.insert(middlePos).first;
					pointIterator--;
					continue;
				}
			}
			currentPoint = *pointIterator;
		}
	}

	//Create blocks
	{
		uint32 currentPoint = -1;
		for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
			pointIterator != partitionPoints.end(); pointIterator++)
		{
			if(currentPoint != -1)
			{
				CreateBlock(currentPoint, *pointIterator - 4);
			}
			currentPoint = *pointIterator;
		}
	}
}
<|endoftext|>