<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ReturnSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ReturnSynthesizer::ReturnSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()) {
  }

  // pin the vtable here.
  ReturnSynthesizer::~ReturnSynthesizer()
  { }

  void ReturnSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    FunctionDecl* FD = getTransaction()->getWrapperFD();

    int foundAtPos = -1;
    Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                         /*omitDS*/false,
                                                         m_Sema);
    if (lastExpr) {
      QualType RetTy = lastExpr->getType();
      if (!RetTy->isVoidType()) {
        // Change the void function's return type
        // We can't PushDeclContext, because we don't have scope.
        Sema::ContextRAII pushedDC(*m_Sema, FD);
        FunctionProtoType::ExtProtoInfo EPI;
        QualType FnTy = m_Context->getFunctionType(RetTy,
                                                   /* ArgArray = */0,
                                                   /* NumArgs = */0, EPI);
        FD->setType(FnTy);
        CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
        assert(CS && "Missing body?");
        // Change it to a return stmt (Avoid dealloc/alloc of all el.)
        *(CS->body_begin() + foundAtPos)
          = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(),
                                    lastExpr).take();
      }
    } else if (foundAtPos >= 0) {
      // check for non-void return statement
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      Stmt* CSS = *(CS->body_begin() + foundAtPos);
      if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) {
        if (Expr* RetV = RS->getRetValue()) {
          QualType RetTy = RetV->getType();
          // Any return statement will have been "healed" by Sema
          // to correspond to the original void return type of the
          // wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
          // Remove that.
          if (RetTy->isVoidType()) {
            ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV);
            if (VoidCast) {
              RS->setRetValue(VoidCast->getSubExpr());
              RetTy = VoidCast->getSubExpr()->getType();
            }
          }

          if (!RetTy->isVoidType()) {
            Sema::ContextRAII pushedDC(*m_Sema, FD);
            FunctionProtoType::ExtProtoInfo EPI;
            QualType FnTy = m_Context->getFunctionType(RetTy,
                                                       /* ArgArray = */0,
                                                       /* NumArgs = */0,
                                                       EPI);
            FD->setType(FnTy);
          } // not returning void
        } // have return value
      } // is a return statement
    } // have a statement
  }
} // end namespace cling
<commit_msg>When we cannot copy the result we shouldn't try. Fixes savannah bug #99000<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ReturnSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ReturnSynthesizer::ReturnSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()) {
  }

  // pin the vtable here.
  ReturnSynthesizer::~ReturnSynthesizer()
  { }

  void ReturnSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    FunctionDecl* FD = getTransaction()->getWrapperFD();

    int foundAtPos = -1;
    Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                         /*omitDS*/false,
                                                         m_Sema);
    if (lastExpr) {
      QualType RetTy = lastExpr->getType();
      if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) {
        // Change the void function's return type
        // We can't PushDeclContext, because we don't have scope.
        Sema::ContextRAII pushedDC(*m_Sema, FD);
        FunctionProtoType::ExtProtoInfo EPI;
        QualType FnTy = m_Context->getFunctionType(RetTy,
                                                   /* ArgArray = */0,
                                                   /* NumArgs = */0, EPI);
        FD->setType(FnTy);
        CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
        assert(CS && "Missing body?");
        // Change it to a return stmt (Avoid dealloc/alloc of all el.)
        *(CS->body_begin() + foundAtPos)
          = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(),
                                    lastExpr).take();
      }
    } else if (foundAtPos >= 0) {
      // check for non-void return statement
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      Stmt* CSS = *(CS->body_begin() + foundAtPos);
      if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) {
        if (Expr* RetV = RS->getRetValue()) {
          QualType RetTy = RetV->getType();
          // Any return statement will have been "healed" by Sema
          // to correspond to the original void return type of the
          // wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
          // Remove that.
          if (RetTy->isVoidType()) {
            ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV);
            if (VoidCast) {
              RS->setRetValue(VoidCast->getSubExpr());
              RetTy = VoidCast->getSubExpr()->getType();
            }
          }

          if (!RetTy->isVoidType()) {
            Sema::ContextRAII pushedDC(*m_Sema, FD);
            FunctionProtoType::ExtProtoInfo EPI;
            QualType FnTy = m_Context->getFunctionType(RetTy,
                                                       /* ArgArray = */0,
                                                       /* NumArgs = */0,
                                                       EPI);
            FD->setType(FnTy);
          } // not returning void
        } // have return value
      } // is a return statement
    } // have a statement
  }
} // end namespace cling
<|endoftext|>


<commit_before>#include "optionsdialog.h"
#include "ui_optionsdialog.h"

#include "bitcoinunits.h"
#include "monitoreddatamapper.h"
#include "netbase.h"
#include "optionsmodel.h"

#include <QDir>
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>

OptionsDialog::OptionsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OptionsDialog),
    model(0),
    mapper(0),
    fRestartWarningDisplayed_Proxy(false),
    fRestartWarningDisplayed_Lang(false),
    fProxyIpValid(true)
{
    ui->setupUi(this);

    /* Network elements init */
#ifndef USE_UPNP
    ui->mapPortUpnp->setEnabled(false);
#endif

    ui->proxyIp->setEnabled(false);
    ui->proxyPort->setEnabled(false);
    ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));

    ui->socksVersion->setEnabled(false);
    ui->socksVersion->addItem("5", 5);
    ui->socksVersion->addItem("4", 4);
    ui->socksVersion->setCurrentIndex(0);

    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy()));

    ui->proxyIp->installEventFilter(this);

    /* Window elements init */
#ifdef Q_OS_MAC
    ui->tabWindow->setVisible(false);
#endif

    /* Display elements init */
    QDir translations(":translations");
    ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
    foreach(const QString &langStr, translations.entryList())
    {
        QLocale locale(langStr);

        /** check if the locale name consists of 2 parts (language_country) */
        if(langStr.contains("_"))
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
        else
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language (locale name)", e.g. "German (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
    }

    ui->unit->setModel(new BitcoinUnits(this));

    /* Widget-to-option mapper */
    mapper = new MonitoredDataMapper(this);
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
    mapper->setOrientation(Qt::Vertical);

    /* enable apply button when data modified */
    connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton()));
    /* disable apply button when new data loaded */
    connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton()));
    /* setup/change UI elements when proxy IP is invalid/valid */
    connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool)));
}

OptionsDialog::~OptionsDialog()
{
    delete ui;
}

void OptionsDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if(model)
    {
        connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

        mapper->setModel(model);
        setMapper();
        mapper->toFirst();
    }

    /* update the display unit, to not use the default ("B") */
    updateDisplayUnit();

    /* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */
    connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang()));

    /* disable apply button after settings are loaded as there is nothing to save */
    disableApplyButton();
}

void OptionsDialog::setMapper()
{
    /* Main */
    mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
    mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);

    /* Network */
    mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);

    mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
    mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
    mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
    mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);

    /* Window */
#ifndef Q_OS_MAC
    mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
    mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif

    /* Display */
    mapper->addMapping(ui->lang, OptionsModel::Language);
    mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
    mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
}

void OptionsDialog::enableApplyButton()
{
    ui->applyButton->setEnabled(true);
}

void OptionsDialog::disableApplyButton()
{
    ui->applyButton->setEnabled(false);
}

void OptionsDialog::enableSaveButtons()
{
    /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */
    if(fProxyIpValid)
        setSaveButtonState(true);
}

void OptionsDialog::disableSaveButtons()
{
    setSaveButtonState(false);
}

void OptionsDialog::setSaveButtonState(bool fState)
{
    ui->applyButton->setEnabled(fState);
    ui->okButton->setEnabled(fState);
}

void OptionsDialog::on_resetButton_clicked()
{
    if(model)
    {
        // confirmation dialog
        QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
            tr("Some settings may require a client restart to take effect.") + "

" + tr("Do you want to proceed?"),
            QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);

        if(btnRetVal == QMessageBox::Cancel)
            return;

        disableApplyButton();

        /* disable restart warning messages display */
        fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = true;

        /* reset all options and save the default values (QSettings) */
        model->Reset();
        mapper->toFirst();
        mapper->submit();

        /* re-enable restart warning messages display */
        fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = false;
    }
}

void OptionsDialog::on_okButton_clicked()
{
    mapper->submit();
    accept();
}

void OptionsDialog::on_cancelButton_clicked()
{
    reject();
}

void OptionsDialog::on_applyButton_clicked()
{
    mapper->submit();
    disableApplyButton();
}

void OptionsDialog::showRestartWarning_Proxy()
{
    if(!fRestartWarningDisplayed_Proxy)
    {
        QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting " + FIRSTCASE_NAME + "."), QMessageBox::Ok);
        fRestartWarningDisplayed_Proxy = true;
    }
}

void OptionsDialog::showRestartWarning_Lang()
{
    if(!fRestartWarningDisplayed_Lang)
    {
        QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting " + FIRSTCASE_NAME + "."), QMessageBox::Ok);
        fRestartWarningDisplayed_Lang = true;
    }
}

void OptionsDialog::updateDisplayUnit()
{
    if(model)
    {
        /* Update transactionFee with the current unit */
        ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
    }
}

void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState)
{
    // this is used in a check before re-enabling the save buttons
    fProxyIpValid = fState;

    if(fProxyIpValid)
    {
        enableSaveButtons();
        ui->statusLabel->clear();
    }
    else
    {
        disableSaveButtons();
        object->setValid(fProxyIpValid);
        ui->statusLabel->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
    }
}

bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
    if(event->type() == QEvent::FocusOut)
    {
        if(object == ui->proxyIp)
        {
            CService addr;
            /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */
            emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr));
        }
    }
    return QDialog::eventFilter(object, event);
}
<commit_msg>Update optionsdialog.cpp<commit_after>#include "optionsdialog.h"
#include "ui_optionsdialog.h"

#include "bitcoinunits.h"
#include "monitoreddatamapper.h"
#include "netbase.h"
#include "optionsmodel.h"

#include <QDir>
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>

OptionsDialog::OptionsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OptionsDialog),
    model(0),
    mapper(0),
    fRestartWarningDisplayed_Proxy(false),
    fRestartWarningDisplayed_Lang(false),
    fProxyIpValid(true)
{
    ui->setupUi(this);

    /* Network elements init */
#ifndef USE_UPNP
    ui->mapPortUpnp->setEnabled(false);
#endif

    ui->proxyIp->setEnabled(false);
    ui->proxyPort->setEnabled(false);
    ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));

    ui->socksVersion->setEnabled(false);
    ui->socksVersion->addItem("5", 5);
    ui->socksVersion->addItem("4", 4);
    ui->socksVersion->setCurrentIndex(0);

    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy()));

    ui->proxyIp->installEventFilter(this);

    /* Window elements init */
#ifdef Q_OS_MAC
    ui->tabWindow->setVisible(false);
#endif

    /* Display elements init */
    QDir translations(":translations");
    ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
    foreach(const QString &langStr, translations.entryList())
    {
        QLocale locale(langStr);

        /** check if the locale name consists of 2 parts (language_country) */
        if(langStr.contains("_"))
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
        else
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language (locale name)", e.g. "German (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
    }

    ui->unit->setModel(new BitcoinUnits(this));

    /* Widget-to-option mapper */
    mapper = new MonitoredDataMapper(this);
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
    mapper->setOrientation(Qt::Vertical);

    /* enable apply button when data modified */
    connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton()));
    /* disable apply button when new data loaded */
    connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton()));
    /* setup/change UI elements when proxy IP is invalid/valid */
    connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool)));
}

OptionsDialog::~OptionsDialog()
{
    delete ui;
}

void OptionsDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if(model)
    {
        connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

        mapper->setModel(model);
        setMapper();
        mapper->toFirst();
    }

    /* update the display unit, to not use the default ("B") */
    updateDisplayUnit();

    /* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */
    connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang()));

    /* disable apply button after settings are loaded as there is nothing to save */
    disableApplyButton();
}

void OptionsDialog::setMapper()
{
    /* Main */
    mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
    mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);

    /* Network */
    mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);

    mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
    mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
    mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
    mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);

    /* Window */
#ifndef Q_OS_MAC
    mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
    mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif

    /* Display */
    mapper->addMapping(ui->lang, OptionsModel::Language);
    mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
    mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
}

void OptionsDialog::enableApplyButton()
{
    ui->applyButton->setEnabled(true);
}

void OptionsDialog::disableApplyButton()
{
    ui->applyButton->setEnabled(false);
}

void OptionsDialog::enableSaveButtons()
{
    /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */
    if(fProxyIpValid)
        setSaveButtonState(true);
}

void OptionsDialog::disableSaveButtons()
{
    setSaveButtonState(false);
}

void OptionsDialog::setSaveButtonState(bool fState)
{
    ui->applyButton->setEnabled(fState);
    ui->okButton->setEnabled(fState);
}

void OptionsDialog::on_resetButton_clicked()
{
    if(model)
    {
        // confirmation dialog
        QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
            tr("Some settings may require a client restart to take effect.") + "

" + tr("Do you want to proceed?"),
            QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);

        if(btnRetVal == QMessageBox::Cancel)
            return;

        disableApplyButton();

        /* disable restart warning messages display */
        fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = true;

        /* reset all options and save the default values (QSettings) */
        model->Reset();
        mapper->toFirst();
        mapper->submit();

        /* re-enable restart warning messages display */
        fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = false;
    }
}

void OptionsDialog::on_okButton_clicked()
{
    mapper->submit();
    accept();
}

void OptionsDialog::on_cancelButton_clicked()
{
    reject();
}

void OptionsDialog::on_applyButton_clicked()
{
    mapper->submit();
    disableApplyButton();
}

void OptionsDialog::showRestartWarning_Proxy()
{
    if(!fRestartWarningDisplayed_Proxy)
    {
        QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting ."), QMessageBox::Ok);
        fRestartWarningDisplayed_Proxy = true;
    }
}

void OptionsDialog::showRestartWarning_Lang()
{
    if(!fRestartWarningDisplayed_Lang)
    {
        QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting ."), QMessageBox::Ok);
        fRestartWarningDisplayed_Lang = true;
    }
}

void OptionsDialog::updateDisplayUnit()
{
    if(model)
    {
        /* Update transactionFee with the current unit */
        ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
    }
}

void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState)
{
    // this is used in a check before re-enabling the save buttons
    fProxyIpValid = fState;

    if(fProxyIpValid)
    {
        enableSaveButtons();
        ui->statusLabel->clear();
    }
    else
    {
        disableSaveButtons();
        object->setValid(fProxyIpValid);
        ui->statusLabel->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
    }
}

bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
    if(event->type() == QEvent::FocusOut)
    {
        if(object == ui->proxyIp)
        {
            CService addr;
            /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */
            emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr));
        }
    }
    return QDialog::eventFilter(object, event);
}
<|endoftext|>


<commit_before>#include "rdb_protocol/func.hpp"

#include "rdb_protocol/env.hpp"
#include "rdb_protocol/pb_utils.hpp"
#include "rdb_protocol/ql2.pb.h"

#pragma GCC diagnostic ignored "-Wshadow"

namespace ql {

func_t::func_t(env_t *env, js::id_t id, term_t *parent)
    : pb_rcheckable_t(parent), body(0), source(0),
      js_parent(parent), js_env(env), js_id(id) { }

func_t::func_t(env_t *env, const Term *_source)
    : pb_rcheckable_t(_source), body(0), source(_source),
      js_parent(0), js_env(0), js_id(js::INVALID_ID) {
    const Term *t = _source;
    r_sanity_check(t->type() == Term_TermType_FUNC);
    rcheck(t->optargs_size() == 0, "FUNC takes no optional arguments.");
    rcheck(t->args_size() == 2, strprintf("Func takes exactly two arguments (got %d)",
                                          t->args_size()));

    std::vector<int> args;
    const Term *vars = &t->args(0);
    if (vars->type() == Term_TermType_DATUM) {
        const Datum *d = &vars->datum();
        rcheck(d->type() == Datum_DatumType_R_ARRAY,
               "CLIENT ERROR: FUNC variables must be a literal *array* of numbers.");
        for (int i = 0; i < d->r_array_size(); ++i) {
            const Datum *dnum = &d->r_array(i);
            rcheck(dnum->type() == Datum_DatumType_R_NUM,
                   "CLIENT ERROR: FUNC variables must be a literal array of *numbers*.");
            args.push_back(dnum->r_num());
        }
    } else if (vars->type() == Term_TermType_MAKE_ARRAY) {
        for (int i = 0; i < vars->args_size(); ++i) {
            const Term *arg = &vars->args(i);
            rcheck(arg->type() == Term_TermType_DATUM,
                   "CLIENT ERROR: FUNC variables must be a *literal* array of numbers.");
            const Datum *dnum = &arg->datum();
            rcheck(dnum->type() == Datum_DatumType_R_NUM,
                   "CLIENT ERROR: FUNC variables must be a literal array of *numbers*.");
            args.push_back(dnum->r_num());
        }
    } else {
        rfail("CLIENT ERROR: FUNC variables must be a *literal array of numbers*.");
    }

    guarantee(argptrs.size() == 0);
    argptrs.reserve(args.size()); // NECESSARY FOR POINTERS TO REMAIN VALID
    for (size_t i = 0; i < args.size(); ++i) {
        argptrs.push_back(0);
        env->push_var(args[i], &argptrs[i]);
    }
    if (args.size() == 1 && env_t::var_allows_implicit(args[0])) {
        env->push_implicit(&argptrs[0]);
    }

    if (args.size()) guarantee(env->top_var(args[0], this) == &argptrs[0]);

    const Term *body_source = &t->args(1);
    body = env->new_term(body_source);

    for (size_t i = 0; i < args.size(); ++i) {
        env->pop_var(args[i]);
    }
    if (args.size() == 1 && env_t::var_allows_implicit(args[0])) {
        env->pop_implicit();
    }

    env->dump_scope(&scope);
}

val_t *func_t::call(const std::vector<const datum_t *> &args) {
    try {
        if (js_parent != 0) {
            r_sanity_check(!body && !source && js_env);
            // Convert datum args to cJSON args for the JS runner
            std::vector<boost::shared_ptr<scoped_cJSON_t> > json_args;
            for (auto arg_iter = args.begin(); arg_it != args.end(); ++arg_iter) {
                json_args.push_back((*arg_iter)->as_json());
            }

            boost::shared_ptr<js::runner_t> js = js_env->get_js_runner();
            js::js_result_t result = js->call(js_id, json_args);

            return boost::apply_visitor(js_result_visitor_t(js_env, js_parent), result);
        } else {
            r_sanity_check(body && source && !js_env);
            rcheck(args.size() == argptrs.size() || argptrs.size() == 0,
                   strprintf("Expected %zu argument(s) but found %zu.",
                             argptrs.size(), args.size()));
            for (size_t i = 0; i < argptrs.size(); ++i) {
                r_sanity_check(args[i]);
                argptrs[i] = args[i];
            }
            return body->eval(false);
            //                ^^^^^ don't use cached value
        }
    } catch (const datum_exc_t &e) {
        rfail("%s", e.what());
        unreachable();
    }
}

val_t *func_t::call() {
    std::vector<const datum_t *> args;
    return call(args);
}

val_t *func_t::call(const datum_t *arg) {
    std::vector<const datum_t *> args;
    args.push_back(arg);
    return call(args);
}

val_t *func_t::call(const datum_t *arg1, const datum_t *arg2) {
    std::vector<const datum_t *> args;
    args.push_back(arg1);
    args.push_back(arg2);
    return call(args);
}

void func_t::dump_scope(std::map<int64_t, Datum> *out) const {
    r_sanity_check(body && source && !js_env && !js_parent);
    for (std::map<int64_t, const datum_t **>::const_iterator
             it = scope.begin(); it != scope.end(); ++it) {
        if (!*it->second) continue;
        (*it->second)->write_to_protobuf(&(*out)[it->first]);
    }
}
bool func_t::is_deterministic() const {
    return body ? body->is_deterministic() : false;
}

wire_func_t::wire_func_t() { }
wire_func_t::wire_func_t(env_t *env, func_t *func) : source(*func->source) {
    if (env) {
        cached_funcs[env] = func;
    }

    func->dump_scope(&scope);
}
wire_func_t::wire_func_t(const Term &_source, std::map<int64_t, Datum> *_scope)
    : source(_source) {
    if (_scope) scope = *_scope;
}

func_t *wire_func_t::compile(env_t *env) {
    if (cached_funcs.count(env) == 0) {
        env->push_scope(&scope);
        cached_funcs[env] = env->new_func(&source);
        env->pop_scope();
    }
    return cached_funcs[env];
}

func_term_t::func_term_t(env_t *env, const Term *term)
    : term_t(env, term), func(env->new_func(term)) { }
val_t *func_term_t::eval_impl() {
    return new_val(func);
}
bool func_term_t::is_deterministic_impl() const {
    return func->is_deterministic();
}

bool func_t::filter_call(env_t *env, const datum_t *arg) {
    const datum_t *d = call(arg)->as_datum();
    if (d->get_type() == datum_t::R_OBJECT) {
        func_t *f2 = new_filter_func(env, d, this);
        d = f2->call(arg)->as_datum();
    }
    if (d->get_type() == datum_t::R_BOOL) return d->as_bool();
    rfail("FILTER must be passed either an OBJECT or a predicate (got %s).",
          d->get_type_name());
}

func_t *func_t::new_filter_func(env_t *env, const datum_t *obj,
                                const pb_rcheckable_t *bt_src) {
    env_wrapper_t<Term> *twrap = env->add_ptr(new env_wrapper_t<Term>());
    int x = env->gensym();
    Term *t = pb::set_func(&twrap->t, x);
    pb::set(t, Term_TermType_ALL, 0, 0);
    for (std::map<const std::string, const datum_t *>::const_iterator
             it = obj->as_object().begin(); it != obj->as_object().end(); ++it) {
        std::string key = it->first;
        const datum_t *val = it->second;

        Term *arg = t->add_args();
        N2(EQ,
           N2(GETATTR, pb::set_var(arg, x), pb::set_str(arg, key)),
           val->write_to_protobuf(pb::set_datum(arg)));
    }
    bt_src->propagate(&twrap->t);
    return env->add_ptr(new func_t(env, &twrap->t));
}

func_t *func_t::new_identity_func(env_t *env, const datum_t *obj,
                                  const pb_rcheckable_t *bt_src) {
    env_wrapper_t<Term> *twrap = env->add_ptr(new env_wrapper_t<Term>());
    Term *arg = &twrap->t;
        N2(FUNC, N0(MAKE_ARRAY), NDATUM(obj));
    bt_src->propagate(&twrap->t);
    return env->add_ptr(new func_t(env, &twrap->t));
}

} // namespace ql
<commit_msg>Replaced arg_it with arg_iter, silly.<commit_after>#include "rdb_protocol/func.hpp"

#include "rdb_protocol/env.hpp"
#include "rdb_protocol/pb_utils.hpp"
#include "rdb_protocol/ql2.pb.h"

#pragma GCC diagnostic ignored "-Wshadow"

namespace ql {

func_t::func_t(env_t *env, js::id_t id, term_t *parent)
    : pb_rcheckable_t(parent), body(0), source(0),
      js_parent(parent), js_env(env), js_id(id) { }

func_t::func_t(env_t *env, const Term *_source)
    : pb_rcheckable_t(_source), body(0), source(_source),
      js_parent(0), js_env(0), js_id(js::INVALID_ID) {
    const Term *t = _source;
    r_sanity_check(t->type() == Term_TermType_FUNC);
    rcheck(t->optargs_size() == 0, "FUNC takes no optional arguments.");
    rcheck(t->args_size() == 2, strprintf("Func takes exactly two arguments (got %d)",
                                          t->args_size()));

    std::vector<int> args;
    const Term *vars = &t->args(0);
    if (vars->type() == Term_TermType_DATUM) {
        const Datum *d = &vars->datum();
        rcheck(d->type() == Datum_DatumType_R_ARRAY,
               "CLIENT ERROR: FUNC variables must be a literal *array* of numbers.");
        for (int i = 0; i < d->r_array_size(); ++i) {
            const Datum *dnum = &d->r_array(i);
            rcheck(dnum->type() == Datum_DatumType_R_NUM,
                   "CLIENT ERROR: FUNC variables must be a literal array of *numbers*.");
            args.push_back(dnum->r_num());
        }
    } else if (vars->type() == Term_TermType_MAKE_ARRAY) {
        for (int i = 0; i < vars->args_size(); ++i) {
            const Term *arg = &vars->args(i);
            rcheck(arg->type() == Term_TermType_DATUM,
                   "CLIENT ERROR: FUNC variables must be a *literal* array of numbers.");
            const Datum *dnum = &arg->datum();
            rcheck(dnum->type() == Datum_DatumType_R_NUM,
                   "CLIENT ERROR: FUNC variables must be a literal array of *numbers*.");
            args.push_back(dnum->r_num());
        }
    } else {
        rfail("CLIENT ERROR: FUNC variables must be a *literal array of numbers*.");
    }

    guarantee(argptrs.size() == 0);
    argptrs.reserve(args.size()); // NECESSARY FOR POINTERS TO REMAIN VALID
    for (size_t i = 0; i < args.size(); ++i) {
        argptrs.push_back(0);
        env->push_var(args[i], &argptrs[i]);
    }
    if (args.size() == 1 && env_t::var_allows_implicit(args[0])) {
        env->push_implicit(&argptrs[0]);
    }

    if (args.size()) guarantee(env->top_var(args[0], this) == &argptrs[0]);

    const Term *body_source = &t->args(1);
    body = env->new_term(body_source);

    for (size_t i = 0; i < args.size(); ++i) {
        env->pop_var(args[i]);
    }
    if (args.size() == 1 && env_t::var_allows_implicit(args[0])) {
        env->pop_implicit();
    }

    env->dump_scope(&scope);
}

val_t *func_t::call(const std::vector<const datum_t *> &args) {
    try {
        if (js_parent != 0) {
            r_sanity_check(!body && !source && js_env);
            // Convert datum args to cJSON args for the JS runner
            std::vector<boost::shared_ptr<scoped_cJSON_t> > json_args;
            for (auto arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
                json_args.push_back((*arg_iter)->as_json());
            }

            boost::shared_ptr<js::runner_t> js = js_env->get_js_runner();
            js::js_result_t result = js->call(js_id, json_args);

            return boost::apply_visitor(js_result_visitor_t(js_env, js_parent), result);
        } else {
            r_sanity_check(body && source && !js_env);
            rcheck(args.size() == argptrs.size() || argptrs.size() == 0,
                   strprintf("Expected %zu argument(s) but found %zu.",
                             argptrs.size(), args.size()));
            for (size_t i = 0; i < argptrs.size(); ++i) {
                r_sanity_check(args[i]);
                argptrs[i] = args[i];
            }
            return body->eval(false);
            //                ^^^^^ don't use cached value
        }
    } catch (const datum_exc_t &e) {
        rfail("%s", e.what());
        unreachable();
    }
}

val_t *func_t::call() {
    std::vector<const datum_t *> args;
    return call(args);
}

val_t *func_t::call(const datum_t *arg) {
    std::vector<const datum_t *> args;
    args.push_back(arg);
    return call(args);
}

val_t *func_t::call(const datum_t *arg1, const datum_t *arg2) {
    std::vector<const datum_t *> args;
    args.push_back(arg1);
    args.push_back(arg2);
    return call(args);
}

void func_t::dump_scope(std::map<int64_t, Datum> *out) const {
    r_sanity_check(body && source && !js_env && !js_parent);
    for (std::map<int64_t, const datum_t **>::const_iterator
             it = scope.begin(); it != scope.end(); ++it) {
        if (!*it->second) continue;
        (*it->second)->write_to_protobuf(&(*out)[it->first]);
    }
}
bool func_t::is_deterministic() const {
    return body ? body->is_deterministic() : false;
}

wire_func_t::wire_func_t() { }
wire_func_t::wire_func_t(env_t *env, func_t *func) : source(*func->source) {
    if (env) {
        cached_funcs[env] = func;
    }

    func->dump_scope(&scope);
}
wire_func_t::wire_func_t(const Term &_source, std::map<int64_t, Datum> *_scope)
    : source(_source) {
    if (_scope) scope = *_scope;
}

func_t *wire_func_t::compile(env_t *env) {
    if (cached_funcs.count(env) == 0) {
        env->push_scope(&scope);
        cached_funcs[env] = env->new_func(&source);
        env->pop_scope();
    }
    return cached_funcs[env];
}

func_term_t::func_term_t(env_t *env, const Term *term)
    : term_t(env, term), func(env->new_func(term)) { }
val_t *func_term_t::eval_impl() {
    return new_val(func);
}
bool func_term_t::is_deterministic_impl() const {
    return func->is_deterministic();
}

bool func_t::filter_call(env_t *env, const datum_t *arg) {
    const datum_t *d = call(arg)->as_datum();
    if (d->get_type() == datum_t::R_OBJECT) {
        func_t *f2 = new_filter_func(env, d, this);
        d = f2->call(arg)->as_datum();
    }
    if (d->get_type() == datum_t::R_BOOL) return d->as_bool();
    rfail("FILTER must be passed either an OBJECT or a predicate (got %s).",
          d->get_type_name());
}

func_t *func_t::new_filter_func(env_t *env, const datum_t *obj,
                                const pb_rcheckable_t *bt_src) {
    env_wrapper_t<Term> *twrap = env->add_ptr(new env_wrapper_t<Term>());
    int x = env->gensym();
    Term *t = pb::set_func(&twrap->t, x);
    pb::set(t, Term_TermType_ALL, 0, 0);
    for (std::map<const std::string, const datum_t *>::const_iterator
             it = obj->as_object().begin(); it != obj->as_object().end(); ++it) {
        std::string key = it->first;
        const datum_t *val = it->second;

        Term *arg = t->add_args();
        N2(EQ,
           N2(GETATTR, pb::set_var(arg, x), pb::set_str(arg, key)),
           val->write_to_protobuf(pb::set_datum(arg)));
    }
    bt_src->propagate(&twrap->t);
    return env->add_ptr(new func_t(env, &twrap->t));
}

func_t *func_t::new_identity_func(env_t *env, const datum_t *obj,
                                  const pb_rcheckable_t *bt_src) {
    env_wrapper_t<Term> *twrap = env->add_ptr(new env_wrapper_t<Term>());
    Term *arg = &twrap->t;
        N2(FUNC, N0(MAKE_ARRAY), NDATUM(obj));
    bt_src->propagate(&twrap->t);
    return env->add_ptr(new func_t(env, &twrap->t));
}

} // namespace ql
<|endoftext|>


<commit_before>//===- lib/Runtimes/Tracer/WrapCstdlib_h.cpp ------------------------------===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#include "SimpleWrapper.hpp"
#include "Tracer.hpp"

#include "seec/Runtimes/MangleFunction.h"
#include "seec/Trace/TraceThreadListener.hpp"
#include "seec/Trace/TraceThreadMemCheck.hpp"
#include "seec/Util/Maybe.hpp"
#include "seec/Util/ScopeExit.hpp"

#include "llvm/Support/CallSite.h"

#include <cstdlib>
#include <stack>

namespace seec {

/// \brief Stop all other threads and write trace information.
///
/// This prepares us to safely terminate the process.
///
void stopThreadsAndWriteTrace() {
  auto &ProcessEnv = seec::trace::getProcessEnvironment();
  auto &ProcessListener = ProcessEnv.getProcessListener();

  auto &ThreadEnv = seec::trace::getThreadEnvironment();
  auto &ThreadListener = ThreadEnv.getThreadListener();

  // Interact with the thread listener's notification system.
  ThreadListener.enterNotification();

  // Stop all of the other threads.
  auto const &SupportSyncExit = ThreadListener.getSupportSynchronizedExit();
  SupportSyncExit.getSynchronizedExit().stopAll();

  // TODO: Write an event for this Instruction.

  // Write out the trace information (if tracing is enabled).
  auto const TraceEnabled = ProcessListener.traceEnabled();

  if (TraceEnabled) {
    ProcessListener.traceWrite();
    ProcessListener.traceFlush();
    ProcessListener.traceClose();

    for (auto const ThreadListenerPtr : ProcessListener.getThreadListeners()) {
      ThreadListenerPtr->traceWrite();
      ThreadListenerPtr->traceFlush();
      ThreadListenerPtr->traceClose();
    }
  }
}

/// Functions to call during exit().
static std::stack<void (*)()> AtExitFunctions;

/// Controls access to AtExitFunctions.
static std::mutex AtExitFunctionsMutex;

/// Functions to call during quick_exit().
static std::stack<void (*)()> AtQuickExitFunctions;

/// Controls access to AtQuickExitFunctions.
static std::mutex AtQuickExitFunctionsMutex;

/// \brief Implement a checking bsearch.
///
class BinarySearchImpl {
  /// The thread performing the sort.
  seec::trace::TraceThreadListener &ThreadListener;

  /// The memory checker.
  seec::trace::CStdLibChecker Checker;

  /// Pointer to the key.
  char const * const Key;

  /// Pointer to the start of the array.
  char const * const Array;

  /// Number of elements in the array.
  std::size_t const ElementCount;

  /// Size of each element.
  std::size_t const ElementSize;

  /// Comparison function.
  int (* const Compare)(char const *, char const *);

  /// \brief Acquire memory lock and ensure that memory is accessible.
  ///
  bool acquireMemory()
  {
    ThreadListener.enterNotification();
    ThreadListener.acquireGlobalMemoryReadLock();
    ThreadListener.acquireDynamicMemoryLock();

    // We check for "copy", because it doesn't require initialization, and
    // doesn't require read permission. We don't need the entire array to be
    // initialized, because the initialization that is *required* will be
    // checked in the comparison function.

    return Checker.checkMemoryExistsAndAccessibleForParameter
                   (0,
                    reinterpret_cast<uintptr_t>(Key),
                    ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Copy)
           &&
           Checker.checkMemoryExistsAndAccessibleForParameter
                   (1,
                    reinterpret_cast<uintptr_t>(Array),
                    ElementCount * ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Copy);
  }

  /// \brief Release memory lock.
  ///
  void releaseMemory()
  {
    ThreadListener.exitPostNotification();
  }

  /// \brief Get a pointer to an element in the array.
  ///
  char const *getElement(std::size_t Index) {
    assert(Index < ElementCount);

    return Array + (Index * ElementSize);
  }

  /// \brief Perform the binary search.
  char const *bsearch() {
    if (!ElementCount)
      return nullptr;

    std::size_t Min = 0;
    std::size_t Max = ElementCount - 1;

    while (Min <= Max) {
      std::size_t const Mid = Min + ((Max - Min) / 2);

      // Compare the midpoint with the key.
      releaseMemory();

      auto const Comparison = Compare(getElement(Mid), Key);

      if (!acquireMemory())
        return nullptr;

      if (Comparison < 0) // Mid-point is less than Key
        Min = Mid + 1;
      else if (Comparison > 0) { // Mid-point is greater than Key
        if (Mid == 0)
          return nullptr;

        Max = Mid - 1;
      }
      else // Mid-point is equal to Key
        return getElement(Mid);
    }

    return nullptr;
  }

public:
  /// \brief Constructor.
  ///
  BinarySearchImpl(seec::trace::ThreadEnvironment &WithThread,
                   char const * const ForKey,
                   char const * const ForArray,
                   std::size_t const WithElementCount,
                   std::size_t const WithElementSize,
                   int (* const WithCompare)(char const *, char const *))
  : ThreadListener(WithThread.getThreadListener()),
    Checker(WithThread.getThreadListener(),
            WithThread.getInstructionIndex(),
            seec::runtime_errors::format_selects::CStdFunction::bsearch),
    Key(ForKey),
    Array(ForArray),
    ElementCount(WithElementCount),
    ElementSize(WithElementSize),
    Compare(WithCompare)
  {}

  /// \brief Perform the quicksort.
  ///
  void *operator()()
  {
    acquireMemory();

    auto const Result = bsearch();

    releaseMemory();

    // const_cast due to the C standard.
    return const_cast<char *>(Result);
  }
};

/// \brief Implement a recording quicksort.
///
class QuickSortImpl {
  /// The process.
  seec::trace::TraceProcessListener &ProcessListener;

  /// The thread performing the sort.
  seec::trace::TraceThreadListener &ThreadListener;

  /// The memory checker.
  seec::trace::CStdLibChecker Checker;

  /// Pointer to the start of the array.
  char * const Array;

  /// Number of elements in the array.
  std::size_t const ElementCount;

  /// Size of each element.
  std::size_t const ElementSize;

  /// Comparison function.
  int (* const Compare)(char const *, char const *);

  /// \brief Acquire memory lock and ensure that memory is accessible.
  ///
  bool acquireMemory()
  {
    ThreadListener.enterNotification();
    ThreadListener.acquireGlobalMemoryWriteLock();
    ThreadListener.acquireDynamicMemoryLock();

    return Checker.checkMemoryExistsAndAccessibleForParameter
                   (0,
                    reinterpret_cast<uintptr_t>(Array),
                    ElementCount * ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Write);
  }

  /// \brief Release memory lock.
  ///
  void releaseMemory()
  {
    ThreadListener.exitPostNotification();
  }

  /// \brief Get a pointer to an element in the array.
  ///
  char *getElement(std::size_t Index) {
    assert(Index < ElementCount);

    return Array + (Index * ElementSize);
  }

  /// \brief Swap two elements in the array.
  ///
  void swap(std::size_t IndexA, std::size_t IndexB) {
    assert((IndexA < ElementCount) && (IndexB < ElementCount));

    if (IndexA == IndexB)
      return;

    auto const ElemA = getElement(IndexA);
    auto const ElemB = getElement(IndexB);

    char TempValue[ElementSize];

    memcpy(TempValue, ElemA,     ElementSize);
    memcpy(ElemA,     ElemB,     ElementSize);
    memcpy(ElemB,     TempValue, ElementSize);

    // Copy all in-memory pointer object tracking, in case the elements we are
    // moving are pointers (or contain pointers).
    auto const AddrOfA = reinterpret_cast<uintptr_t>(ElemA);
    auto const AddrOfB = reinterpret_cast<uintptr_t>(ElemB);
    auto const AddrOfT = reinterpret_cast<uintptr_t>(TempValue);
    ProcessListener.copyInMemoryPointerObjects(AddrOfA, AddrOfT, ElementSize);
    ProcessListener.copyInMemoryPointerObjects(AddrOfB, AddrOfA, ElementSize);
    ProcessListener.copyInMemoryPointerObjects(AddrOfT, AddrOfB, ElementSize);
    ProcessListener.clearInMemoryPointerObjects(MemoryArea(AddrOfT,
                                                           ElementSize));

    // Create a new thread time for this "step" of the sort, and record the
    // updated memory states.
    ThreadListener.incrementThreadTime();
    ThreadListener.recordUntypedState(ElemA, ElementSize);
    ThreadListener.recordUntypedState(ElemB, ElementSize);
  }

  /// \brief Partition.
  ///
  seec::Maybe<std::size_t>
  partition(std::size_t const Left,
            std::size_t const Right,
            std::size_t const Pivot)
  {
    // Move the pivot to the end.
    swap(Pivot, Right);

    // Shift all elements "less than" the pivot to the left side.
    std::size_t StoreIndex = Left;

    for (std::size_t i = Left; i < Right; ++i) {
      // Release memory so that the compare function can access it.
      releaseMemory();

      // Compare the current element to the pivot.
      auto const Comparison = Compare(getElement(i), getElement(Right));

      // Lock memory and ensure that the compare function hasn't deallocated it.
      if (!acquireMemory())
        return seec::Maybe<std::size_t>();

      if (Comparison < 0) {
        swap(i, StoreIndex);
        ++StoreIndex;
      }
    }

    // Move pivot to its final place.
    swap(StoreIndex, Right);

    // Return final index of pivot.
    return StoreIndex;
  }

  /// \brief Quicksort.
  ///
  /// \return true iff sorting should continue (no errors occurred).
  ///
  bool quicksort(std::size_t Left, std::size_t Right)
  {
    if (Left >= Right)
      return true;

    // Divide using naive "halfway" partition.
    auto const MaybePivotIndex = partition(Left,
                                           Right,
                                           Left + ((Right - Left) / 2));

    if (!MaybePivotIndex.assigned())
      return false;

    auto const PivotIndex = MaybePivotIndex.get<std::size_t>();

    // Recursively sort the left side (if there is one).
    if (PivotIndex != 0 && !quicksort(Left, PivotIndex - 1))
      return false;

    // Sort the right area.
    return quicksort(PivotIndex + 1, Right);
  }

public:
  /// \brief Constructor.
  ///
  QuickSortImpl(seec::trace::ThreadEnvironment &WithThread,
                char * const ForArray,
                std::size_t const WithElementCount,
                std::size_t const WithElementSize,
                int (* const WithCompare)(char const *, char const *))
  : ProcessListener(WithThread.getProcessEnvironment().getProcessListener()),
    ThreadListener(WithThread.getThreadListener()),
    Checker(WithThread.getThreadListener(),
            WithThread.getInstructionIndex(),
            seec::runtime_errors::format_selects::CStdFunction::qsort),
    Array(ForArray),
    ElementCount(WithElementCount),
    ElementSize(WithElementSize),
    Compare(WithCompare)
  {}

  /// \brief Perform the quicksort.
  ///
  void operator()()
  {
    acquireMemory();
    quicksort(0, ElementCount - 1);
    releaseMemory();
  }
};

} // namespace seec

extern "C" {

//===----------------------------------------------------------------------===//
// abort
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(abort)
()
{
  seec::stopThreadsAndWriteTrace();
  std::abort();
}

//===----------------------------------------------------------------------===//
// exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(exit)
(int exit_code)
{
  // Call intercepted atexit() registered functions.
  {
    std::lock_guard<std::mutex> Lock (seec::AtExitFunctionsMutex);

    while (!seec::AtExitFunctions.empty()) {
      auto Fn = seec::AtExitFunctions.top();
      seec::AtExitFunctions.pop();
      (*Fn)();
    }
  }

  seec::stopThreadsAndWriteTrace();
  std::exit(exit_code);
}

//===----------------------------------------------------------------------===//
// quick_exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(quick_exit)
(int exit_code)
{
  // Call intercepted at_quick_exit() registered functions.
  {
    std::lock_guard<std::mutex> Lock (seec::AtQuickExitFunctionsMutex);

    while (!seec::AtQuickExitFunctions.empty()) {
      auto Fn = seec::AtQuickExitFunctions.top();
      seec::AtQuickExitFunctions.pop();
      (*Fn)();
    }
  }

  seec::stopThreadsAndWriteTrace();
  std::_Exit(exit_code);
}

//===----------------------------------------------------------------------===//
// _Exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(_Exit)
(int exit_code)
{
  seec::stopThreadsAndWriteTrace();
  std::_Exit(exit_code);
}

//===----------------------------------------------------------------------===//
// atexit
//===----------------------------------------------------------------------===//

int
SEEC_MANGLE_FUNCTION(atexit)
(void (*func)())
{
  std::lock_guard<std::mutex> Lock (seec::AtExitFunctionsMutex);

  seec::AtExitFunctions.push(func);

  return 0;
}

//===----------------------------------------------------------------------===//
// at_quick_exit
//===----------------------------------------------------------------------===//

int
SEEC_MANGLE_FUNCTION(at_quick_exit)
(void (*func)())
{
  std::lock_guard<std::mutex> Lock (seec::AtQuickExitFunctionsMutex);

  seec::AtQuickExitFunctions.push(func);

  return 0;
}

//===----------------------------------------------------------------------===//
// qsort
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(qsort)
(char *Array,
 std::size_t ElementCount,
 std::size_t ElementSize,
 int (*Compare)(char const *, char const *)
 )
{
  seec::QuickSortImpl(seec::trace::getThreadEnvironment(),
                      Array, ElementCount, ElementSize, Compare)();
}

//===----------------------------------------------------------------------===//
// bsearch
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(bsearch)
(char const *Key,
 char const *Array,
 std::size_t ElementCount,
 std::size_t ElementSize,
 int (*Compare)(char const *, char const *)
 )
{
  seec::BinarySearchImpl(seec::trace::getThreadEnvironment(),
                         Key, Array, ElementCount, ElementSize, Compare)();
}

} // extern "C"
<commit_msg>Don't close the trace before calling std::exit(), because this will prevent archiving.<commit_after>//===- lib/Runtimes/Tracer/WrapCstdlib_h.cpp ------------------------------===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#include "SimpleWrapper.hpp"
#include "Tracer.hpp"

#include "seec/Runtimes/MangleFunction.h"
#include "seec/Trace/TraceThreadListener.hpp"
#include "seec/Trace/TraceThreadMemCheck.hpp"
#include "seec/Util/Maybe.hpp"
#include "seec/Util/ScopeExit.hpp"

#include "llvm/Support/CallSite.h"

#include <cstdlib>
#include <stack>

namespace seec {

/// \brief Stop all other threads and write trace information.
///
/// This prepares us to safely terminate the process.
///
void stopThreadsAndWriteTrace() {
  auto &ProcessEnv = seec::trace::getProcessEnvironment();
  auto &ProcessListener = ProcessEnv.getProcessListener();

  auto &ThreadEnv = seec::trace::getThreadEnvironment();
  auto &ThreadListener = ThreadEnv.getThreadListener();

  // Interact with the thread listener's notification system.
  ThreadListener.enterNotification();

  // Stop all of the other threads.
  auto const &SupportSyncExit = ThreadListener.getSupportSynchronizedExit();
  SupportSyncExit.getSynchronizedExit().stopAll();

  // TODO: Write an event for this Instruction.

  // Write out the trace information (if tracing is enabled).
  auto const TraceEnabled = ProcessListener.traceEnabled();

  if (TraceEnabled) {
    ProcessListener.traceWrite();
    ProcessListener.traceFlush();

    for (auto const ThreadListenerPtr : ProcessListener.getThreadListeners()) {
      ThreadListenerPtr->traceWrite();
      ThreadListenerPtr->traceFlush();
    }
  }
}

/// Functions to call during exit().
static std::stack<void (*)()> AtExitFunctions;

/// Controls access to AtExitFunctions.
static std::mutex AtExitFunctionsMutex;

/// Functions to call during quick_exit().
static std::stack<void (*)()> AtQuickExitFunctions;

/// Controls access to AtQuickExitFunctions.
static std::mutex AtQuickExitFunctionsMutex;

/// \brief Implement a checking bsearch.
///
class BinarySearchImpl {
  /// The thread performing the sort.
  seec::trace::TraceThreadListener &ThreadListener;

  /// The memory checker.
  seec::trace::CStdLibChecker Checker;

  /// Pointer to the key.
  char const * const Key;

  /// Pointer to the start of the array.
  char const * const Array;

  /// Number of elements in the array.
  std::size_t const ElementCount;

  /// Size of each element.
  std::size_t const ElementSize;

  /// Comparison function.
  int (* const Compare)(char const *, char const *);

  /// \brief Acquire memory lock and ensure that memory is accessible.
  ///
  bool acquireMemory()
  {
    ThreadListener.enterNotification();
    ThreadListener.acquireGlobalMemoryReadLock();
    ThreadListener.acquireDynamicMemoryLock();

    // We check for "copy", because it doesn't require initialization, and
    // doesn't require read permission. We don't need the entire array to be
    // initialized, because the initialization that is *required* will be
    // checked in the comparison function.

    return Checker.checkMemoryExistsAndAccessibleForParameter
                   (0,
                    reinterpret_cast<uintptr_t>(Key),
                    ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Copy)
           &&
           Checker.checkMemoryExistsAndAccessibleForParameter
                   (1,
                    reinterpret_cast<uintptr_t>(Array),
                    ElementCount * ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Copy);
  }

  /// \brief Release memory lock.
  ///
  void releaseMemory()
  {
    ThreadListener.exitPostNotification();
  }

  /// \brief Get a pointer to an element in the array.
  ///
  char const *getElement(std::size_t Index) {
    assert(Index < ElementCount);

    return Array + (Index * ElementSize);
  }

  /// \brief Perform the binary search.
  char const *bsearch() {
    if (!ElementCount)
      return nullptr;

    std::size_t Min = 0;
    std::size_t Max = ElementCount - 1;

    while (Min <= Max) {
      std::size_t const Mid = Min + ((Max - Min) / 2);

      // Compare the midpoint with the key.
      releaseMemory();

      auto const Comparison = Compare(getElement(Mid), Key);

      if (!acquireMemory())
        return nullptr;

      if (Comparison < 0) // Mid-point is less than Key
        Min = Mid + 1;
      else if (Comparison > 0) { // Mid-point is greater than Key
        if (Mid == 0)
          return nullptr;

        Max = Mid - 1;
      }
      else // Mid-point is equal to Key
        return getElement(Mid);
    }

    return nullptr;
  }

public:
  /// \brief Constructor.
  ///
  BinarySearchImpl(seec::trace::ThreadEnvironment &WithThread,
                   char const * const ForKey,
                   char const * const ForArray,
                   std::size_t const WithElementCount,
                   std::size_t const WithElementSize,
                   int (* const WithCompare)(char const *, char const *))
  : ThreadListener(WithThread.getThreadListener()),
    Checker(WithThread.getThreadListener(),
            WithThread.getInstructionIndex(),
            seec::runtime_errors::format_selects::CStdFunction::bsearch),
    Key(ForKey),
    Array(ForArray),
    ElementCount(WithElementCount),
    ElementSize(WithElementSize),
    Compare(WithCompare)
  {}

  /// \brief Perform the quicksort.
  ///
  void *operator()()
  {
    acquireMemory();

    auto const Result = bsearch();

    releaseMemory();

    // const_cast due to the C standard.
    return const_cast<char *>(Result);
  }
};

/// \brief Implement a recording quicksort.
///
class QuickSortImpl {
  /// The process.
  seec::trace::TraceProcessListener &ProcessListener;

  /// The thread performing the sort.
  seec::trace::TraceThreadListener &ThreadListener;

  /// The memory checker.
  seec::trace::CStdLibChecker Checker;

  /// Pointer to the start of the array.
  char * const Array;

  /// Number of elements in the array.
  std::size_t const ElementCount;

  /// Size of each element.
  std::size_t const ElementSize;

  /// Comparison function.
  int (* const Compare)(char const *, char const *);

  /// \brief Acquire memory lock and ensure that memory is accessible.
  ///
  bool acquireMemory()
  {
    ThreadListener.enterNotification();
    ThreadListener.acquireGlobalMemoryWriteLock();
    ThreadListener.acquireDynamicMemoryLock();

    return Checker.checkMemoryExistsAndAccessibleForParameter
                   (0,
                    reinterpret_cast<uintptr_t>(Array),
                    ElementCount * ElementSize,
                    seec::runtime_errors::format_selects::MemoryAccess::Write);
  }

  /// \brief Release memory lock.
  ///
  void releaseMemory()
  {
    ThreadListener.exitPostNotification();
  }

  /// \brief Get a pointer to an element in the array.
  ///
  char *getElement(std::size_t Index) {
    assert(Index < ElementCount);

    return Array + (Index * ElementSize);
  }

  /// \brief Swap two elements in the array.
  ///
  void swap(std::size_t IndexA, std::size_t IndexB) {
    assert((IndexA < ElementCount) && (IndexB < ElementCount));

    if (IndexA == IndexB)
      return;

    auto const ElemA = getElement(IndexA);
    auto const ElemB = getElement(IndexB);

    char TempValue[ElementSize];

    memcpy(TempValue, ElemA,     ElementSize);
    memcpy(ElemA,     ElemB,     ElementSize);
    memcpy(ElemB,     TempValue, ElementSize);

    // Copy all in-memory pointer object tracking, in case the elements we are
    // moving are pointers (or contain pointers).
    auto const AddrOfA = reinterpret_cast<uintptr_t>(ElemA);
    auto const AddrOfB = reinterpret_cast<uintptr_t>(ElemB);
    auto const AddrOfT = reinterpret_cast<uintptr_t>(TempValue);
    ProcessListener.copyInMemoryPointerObjects(AddrOfA, AddrOfT, ElementSize);
    ProcessListener.copyInMemoryPointerObjects(AddrOfB, AddrOfA, ElementSize);
    ProcessListener.copyInMemoryPointerObjects(AddrOfT, AddrOfB, ElementSize);
    ProcessListener.clearInMemoryPointerObjects(MemoryArea(AddrOfT,
                                                           ElementSize));

    // Create a new thread time for this "step" of the sort, and record the
    // updated memory states.
    ThreadListener.incrementThreadTime();
    ThreadListener.recordUntypedState(ElemA, ElementSize);
    ThreadListener.recordUntypedState(ElemB, ElementSize);
  }

  /// \brief Partition.
  ///
  seec::Maybe<std::size_t>
  partition(std::size_t const Left,
            std::size_t const Right,
            std::size_t const Pivot)
  {
    // Move the pivot to the end.
    swap(Pivot, Right);

    // Shift all elements "less than" the pivot to the left side.
    std::size_t StoreIndex = Left;

    for (std::size_t i = Left; i < Right; ++i) {
      // Release memory so that the compare function can access it.
      releaseMemory();

      // Compare the current element to the pivot.
      auto const Comparison = Compare(getElement(i), getElement(Right));

      // Lock memory and ensure that the compare function hasn't deallocated it.
      if (!acquireMemory())
        return seec::Maybe<std::size_t>();

      if (Comparison < 0) {
        swap(i, StoreIndex);
        ++StoreIndex;
      }
    }

    // Move pivot to its final place.
    swap(StoreIndex, Right);

    // Return final index of pivot.
    return StoreIndex;
  }

  /// \brief Quicksort.
  ///
  /// \return true iff sorting should continue (no errors occurred).
  ///
  bool quicksort(std::size_t Left, std::size_t Right)
  {
    if (Left >= Right)
      return true;

    // Divide using naive "halfway" partition.
    auto const MaybePivotIndex = partition(Left,
                                           Right,
                                           Left + ((Right - Left) / 2));

    if (!MaybePivotIndex.assigned())
      return false;

    auto const PivotIndex = MaybePivotIndex.get<std::size_t>();

    // Recursively sort the left side (if there is one).
    if (PivotIndex != 0 && !quicksort(Left, PivotIndex - 1))
      return false;

    // Sort the right area.
    return quicksort(PivotIndex + 1, Right);
  }

public:
  /// \brief Constructor.
  ///
  QuickSortImpl(seec::trace::ThreadEnvironment &WithThread,
                char * const ForArray,
                std::size_t const WithElementCount,
                std::size_t const WithElementSize,
                int (* const WithCompare)(char const *, char const *))
  : ProcessListener(WithThread.getProcessEnvironment().getProcessListener()),
    ThreadListener(WithThread.getThreadListener()),
    Checker(WithThread.getThreadListener(),
            WithThread.getInstructionIndex(),
            seec::runtime_errors::format_selects::CStdFunction::qsort),
    Array(ForArray),
    ElementCount(WithElementCount),
    ElementSize(WithElementSize),
    Compare(WithCompare)
  {}

  /// \brief Perform the quicksort.
  ///
  void operator()()
  {
    acquireMemory();
    quicksort(0, ElementCount - 1);
    releaseMemory();
  }
};

} // namespace seec

extern "C" {

//===----------------------------------------------------------------------===//
// abort
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(abort)
()
{
  seec::stopThreadsAndWriteTrace();
  std::abort();
}

//===----------------------------------------------------------------------===//
// exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(exit)
(int exit_code)
{
  // Call intercepted atexit() registered functions.
  {
    std::lock_guard<std::mutex> Lock (seec::AtExitFunctionsMutex);

    while (!seec::AtExitFunctions.empty()) {
      auto Fn = seec::AtExitFunctions.top();
      seec::AtExitFunctions.pop();
      (*Fn)();
    }
  }

  seec::stopThreadsAndWriteTrace();
  std::exit(exit_code);
}

//===----------------------------------------------------------------------===//
// quick_exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(quick_exit)
(int exit_code)
{
  // Call intercepted at_quick_exit() registered functions.
  {
    std::lock_guard<std::mutex> Lock (seec::AtQuickExitFunctionsMutex);

    while (!seec::AtQuickExitFunctions.empty()) {
      auto Fn = seec::AtQuickExitFunctions.top();
      seec::AtQuickExitFunctions.pop();
      (*Fn)();
    }
  }

  seec::stopThreadsAndWriteTrace();
  std::_Exit(exit_code);
}

//===----------------------------------------------------------------------===//
// _Exit
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(_Exit)
(int exit_code)
{
  seec::stopThreadsAndWriteTrace();
  std::_Exit(exit_code);
}

//===----------------------------------------------------------------------===//
// atexit
//===----------------------------------------------------------------------===//

int
SEEC_MANGLE_FUNCTION(atexit)
(void (*func)())
{
  std::lock_guard<std::mutex> Lock (seec::AtExitFunctionsMutex);

  seec::AtExitFunctions.push(func);

  return 0;
}

//===----------------------------------------------------------------------===//
// at_quick_exit
//===----------------------------------------------------------------------===//

int
SEEC_MANGLE_FUNCTION(at_quick_exit)
(void (*func)())
{
  std::lock_guard<std::mutex> Lock (seec::AtQuickExitFunctionsMutex);

  seec::AtQuickExitFunctions.push(func);

  return 0;
}

//===----------------------------------------------------------------------===//
// qsort
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(qsort)
(char *Array,
 std::size_t ElementCount,
 std::size_t ElementSize,
 int (*Compare)(char const *, char const *)
 )
{
  seec::QuickSortImpl(seec::trace::getThreadEnvironment(),
                      Array, ElementCount, ElementSize, Compare)();
}

//===----------------------------------------------------------------------===//
// bsearch
//===----------------------------------------------------------------------===//

void
SEEC_MANGLE_FUNCTION(bsearch)
(char const *Key,
 char const *Array,
 std::size_t ElementCount,
 std::size_t ElementSize,
 int (*Compare)(char const *, char const *)
 )
{
  seec::BinarySearchImpl(seec::trace::getThreadEnvironment(),
                         Key, Array, ElementCount, ElementSize, Compare)();
}

} // extern "C"
<|endoftext|>


<commit_before>//===-- PPCCodeEmitter.cpp - JIT Code Emitter for PowerPC32 -------*- C++ -*-=//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PowerPC 32-bit CodeEmitter and associated machinery to
// JIT-compile bytecode to native PowerPC.
//
//===----------------------------------------------------------------------===//

#include "PPCTargetMachine.h"
#include "PPCRelocations.h"
#include "PPC.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetOptions.h"
#include <iostream>
using namespace llvm;

namespace {
  class PPCCodeEmitter : public MachineFunctionPass {
    TargetMachine &TM;
    MachineCodeEmitter &MCE;

    // Tracks which instruction references which BasicBlock
    std::vector<std::pair<MachineBasicBlock*, unsigned*> > BBRefs;
    // Tracks where each BasicBlock starts
    std::map<MachineBasicBlock*, long> BBLocations;

    /// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr
    ///
    int getMachineOpValue(MachineInstr &MI, MachineOperand &MO);

  public:
    PPCCodeEmitter(TargetMachine &T, MachineCodeEmitter &M)
      : TM(T), MCE(M) {}

    const char *getPassName() const { return "PowerPC Machine Code Emitter"; }

    /// runOnMachineFunction - emits the given MachineFunction to memory
    ///
    bool runOnMachineFunction(MachineFunction &MF);

    /// emitBasicBlock - emits the given MachineBasicBlock to memory
    ///
    void emitBasicBlock(MachineBasicBlock &MBB);

    /// emitWord - write a 32-bit word to memory at the current PC
    ///
    void emitWord(unsigned w) { MCE.emitWord(w); }

    /// getValueBit - return the particular bit of Val
    ///
    unsigned getValueBit(int64_t Val, unsigned bit) { return (Val >> bit) & 1; }

    /// getBinaryCodeForInstr - This function, generated by the
    /// CodeEmitterGenerator using TableGen, produces the binary encoding for
    /// machine instructions.
    ///
    unsigned getBinaryCodeForInstr(MachineInstr &MI);
  };
}

/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get
/// machine code emitted.  This uses a MachineCodeEmitter object to handle
/// actually outputting the machine code and resolving things like the address
/// of functions.  This method should returns true if machine code emission is
/// not supported.
///
bool PPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
                                                  MachineCodeEmitter &MCE) {
  // Machine code emitter pass for PowerPC
  PM.add(new PPCCodeEmitter(*this, MCE));
  // Delete machine code for this function after emitting it
  PM.add(createMachineCodeDeleter());
  return false;
}

bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
  assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
          MF.getTarget().getRelocationModel() != Reloc::Static) &&
         "JIT relocation model must be set to static or default!");
  MCE.startFunction(MF);
  MCE.emitConstantPool(MF.getConstantPool());
  for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB)
    emitBasicBlock(*BB);
  MCE.finishFunction(MF);

  // Resolve branches to BasicBlocks for the entire function
  for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) {
    intptr_t Location = BBLocations[BBRefs[i].first];
    unsigned *Ref = BBRefs[i].second;
    DEBUG(std::cerr << "Fixup @ " << (void*)Ref << " to " << (void*)Location
                    << "\n");
    unsigned Instr = *Ref;
    intptr_t BranchTargetDisp = (Location - (intptr_t)Ref) >> 2;

    switch (Instr >> 26) {
    default: assert(0 && "Unknown branch user!");
    case 18:  // This is B or BL
      *Ref |= (BranchTargetDisp & ((1 << 24)-1)) << 2;
      break;
    case 16:  // This is BLT,BLE,BEQ,BGE,BGT,BNE, or other bcx instruction
      *Ref |= (BranchTargetDisp & ((1 << 14)-1)) << 2;
      break;
    }
  }
  BBRefs.clear();
  BBLocations.clear();

  return false;
}

void PPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) {
  BBLocations[&MBB] = MCE.getCurrentPCValue();
  for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){
    MachineInstr &MI = *I;
    unsigned Opcode = MI.getOpcode();
    switch (MI.getOpcode()) {
    default:
      emitWord(getBinaryCodeForInstr(*I));
      break;
    case PPC::IMPLICIT_DEF_GPR:
    case PPC::IMPLICIT_DEF_F8:
    case PPC::IMPLICIT_DEF_F4:
    case PPC::IMPLICIT_DEF_VRRC:
      break; // pseudo opcode, no side effects
    case PPC::MovePCtoLR:
      assert(0 && "CodeEmitter does not support MovePCtoLR instruction");
      break;
    }
  }
}

int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) {

  int rv = 0; // Return value; defaults to 0 for unhandled cases
                  // or things that get fixed up later by the JIT.
  if (MO.isRegister()) {
    rv = PPCRegisterInfo::getRegisterNumbering(MO.getReg());

    // Special encoding for MTCRF and MFOCRF, which uses a bit mask for the
    // register, not the register number directly.
    if ((MI.getOpcode() == PPC::MTCRF || MI.getOpcode() == PPC::MFOCRF) &&
        (MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7)) {
      rv = 0x80 >> rv;
    }
  } else if (MO.isImmediate()) {
    rv = MO.getImmedValue();
  } else if (MO.isGlobalAddress() || MO.isExternalSymbol()) {
    unsigned Reloc = 0;
    if (MI.getOpcode() == PPC::BL)
      Reloc = PPC::reloc_pcrel_bx;
    else {
      switch (MI.getOpcode()) {
      default: MI.dump(); assert(0 && "Unknown instruction for relocation!");
      case PPC::LIS:
        Reloc = PPC::reloc_absolute_high;       // Pointer to symbol
        break;
      case PPC::LA:
      case PPC::LBZ:
      case PPC::LHA:
      case PPC::LHZ:
      case PPC::LWZ:
      case PPC::LFS:
      case PPC::LFD:
      case PPC::STB:
      case PPC::STH:
      case PPC::STW:
      case PPC::STFS:
      case PPC::STFD:
        Reloc = PPC::reloc_absolute_low;
        break;
      }
    }
    if (MO.isGlobalAddress())
      MCE.addRelocation(MachineRelocation(MCE.getCurrentPCOffset(),
                                          Reloc, MO.getGlobal(), 0));
    else
      MCE.addRelocation(MachineRelocation(MCE.getCurrentPCOffset(),
                                          Reloc, MO.getSymbolName(), 0));
  } else if (MO.isMachineBasicBlock()) {
    unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
    BBRefs.push_back(std::make_pair(MO.getMachineBasicBlock(), CurrPC));
  } else if (MO.isConstantPoolIndex()) {
    unsigned index = MO.getConstantPoolIndex();
    unsigned Opcode = MI.getOpcode();
    rv = MCE.getConstantPoolEntryAddress(index);
    if (Opcode == PPC::LIS || Opcode == PPC::ADDIS) {
      // lis wants hi16(addr)
      if ((short)rv < 0) rv += 1 << 16;
      rv >>= 16;
    } else if (Opcode == PPC::LWZ || Opcode == PPC::LA ||
               Opcode == PPC::LI ||
               Opcode == PPC::LFS || Opcode == PPC::LFD) {
      // These load opcodes want lo16(addr)
      rv &= 0xffff;
    } else {
      assert(0 && "Unknown constant pool using instruction!");
    }
  } else {
    std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n";
    abort();
  }

  return rv;
}

#include "PPCGenCodeEmitter.inc"

<commit_msg>Teach the JIT how to relocate LI, this fixes the JIT on Prolangs-C/TimberWolfMC<commit_after>//===-- PPCCodeEmitter.cpp - JIT Code Emitter for PowerPC32 -------*- C++ -*-=//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PowerPC 32-bit CodeEmitter and associated machinery to
// JIT-compile bytecode to native PowerPC.
//
//===----------------------------------------------------------------------===//

#include "PPCTargetMachine.h"
#include "PPCRelocations.h"
#include "PPC.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetOptions.h"
#include <iostream>
using namespace llvm;

namespace {
  class PPCCodeEmitter : public MachineFunctionPass {
    TargetMachine &TM;
    MachineCodeEmitter &MCE;

    // Tracks which instruction references which BasicBlock
    std::vector<std::pair<MachineBasicBlock*, unsigned*> > BBRefs;
    // Tracks where each BasicBlock starts
    std::map<MachineBasicBlock*, long> BBLocations;

    /// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr
    ///
    int getMachineOpValue(MachineInstr &MI, MachineOperand &MO);

  public:
    PPCCodeEmitter(TargetMachine &T, MachineCodeEmitter &M)
      : TM(T), MCE(M) {}

    const char *getPassName() const { return "PowerPC Machine Code Emitter"; }

    /// runOnMachineFunction - emits the given MachineFunction to memory
    ///
    bool runOnMachineFunction(MachineFunction &MF);

    /// emitBasicBlock - emits the given MachineBasicBlock to memory
    ///
    void emitBasicBlock(MachineBasicBlock &MBB);

    /// emitWord - write a 32-bit word to memory at the current PC
    ///
    void emitWord(unsigned w) { MCE.emitWord(w); }

    /// getValueBit - return the particular bit of Val
    ///
    unsigned getValueBit(int64_t Val, unsigned bit) { return (Val >> bit) & 1; }

    /// getBinaryCodeForInstr - This function, generated by the
    /// CodeEmitterGenerator using TableGen, produces the binary encoding for
    /// machine instructions.
    ///
    unsigned getBinaryCodeForInstr(MachineInstr &MI);
  };
}

/// addPassesToEmitMachineCode - Add passes to the specified pass manager to get
/// machine code emitted.  This uses a MachineCodeEmitter object to handle
/// actually outputting the machine code and resolving things like the address
/// of functions.  This method should returns true if machine code emission is
/// not supported.
///
bool PPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
                                                  MachineCodeEmitter &MCE) {
  // Machine code emitter pass for PowerPC
  PM.add(new PPCCodeEmitter(*this, MCE));
  // Delete machine code for this function after emitting it
  PM.add(createMachineCodeDeleter());
  return false;
}

bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
  assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
          MF.getTarget().getRelocationModel() != Reloc::Static) &&
         "JIT relocation model must be set to static or default!");
  MCE.startFunction(MF);
  MCE.emitConstantPool(MF.getConstantPool());
  for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB)
    emitBasicBlock(*BB);
  MCE.finishFunction(MF);

  // Resolve branches to BasicBlocks for the entire function
  for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) {
    intptr_t Location = BBLocations[BBRefs[i].first];
    unsigned *Ref = BBRefs[i].second;
    DEBUG(std::cerr << "Fixup @ " << (void*)Ref << " to " << (void*)Location
                    << "\n");
    unsigned Instr = *Ref;
    intptr_t BranchTargetDisp = (Location - (intptr_t)Ref) >> 2;

    switch (Instr >> 26) {
    default: assert(0 && "Unknown branch user!");
    case 18:  // This is B or BL
      *Ref |= (BranchTargetDisp & ((1 << 24)-1)) << 2;
      break;
    case 16:  // This is BLT,BLE,BEQ,BGE,BGT,BNE, or other bcx instruction
      *Ref |= (BranchTargetDisp & ((1 << 14)-1)) << 2;
      break;
    }
  }
  BBRefs.clear();
  BBLocations.clear();

  return false;
}

void PPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) {
  BBLocations[&MBB] = MCE.getCurrentPCValue();
  for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){
    MachineInstr &MI = *I;
    unsigned Opcode = MI.getOpcode();
    switch (MI.getOpcode()) {
    default:
      emitWord(getBinaryCodeForInstr(*I));
      break;
    case PPC::IMPLICIT_DEF_GPR:
    case PPC::IMPLICIT_DEF_F8:
    case PPC::IMPLICIT_DEF_F4:
    case PPC::IMPLICIT_DEF_VRRC:
      break; // pseudo opcode, no side effects
    case PPC::MovePCtoLR:
      assert(0 && "CodeEmitter does not support MovePCtoLR instruction");
      break;
    }
  }
}

int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) {

  int rv = 0; // Return value; defaults to 0 for unhandled cases
                  // or things that get fixed up later by the JIT.
  if (MO.isRegister()) {
    rv = PPCRegisterInfo::getRegisterNumbering(MO.getReg());

    // Special encoding for MTCRF and MFOCRF, which uses a bit mask for the
    // register, not the register number directly.
    if ((MI.getOpcode() == PPC::MTCRF || MI.getOpcode() == PPC::MFOCRF) &&
        (MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7)) {
      rv = 0x80 >> rv;
    }
  } else if (MO.isImmediate()) {
    rv = MO.getImmedValue();
  } else if (MO.isGlobalAddress() || MO.isExternalSymbol()) {
    unsigned Reloc = 0;
    if (MI.getOpcode() == PPC::BL)
      Reloc = PPC::reloc_pcrel_bx;
    else {
      switch (MI.getOpcode()) {
      default: MI.dump(); assert(0 && "Unknown instruction for relocation!");
      case PPC::LIS:
        Reloc = PPC::reloc_absolute_high;       // Pointer to symbol
        break;
      case PPC::LI:
      case PPC::LA:
      case PPC::LBZ:
      case PPC::LHA:
      case PPC::LHZ:
      case PPC::LWZ:
      case PPC::LFS:
      case PPC::LFD:
      case PPC::STB:
      case PPC::STH:
      case PPC::STW:
      case PPC::STFS:
      case PPC::STFD:
        Reloc = PPC::reloc_absolute_low;
        break;
      }
    }
    if (MO.isGlobalAddress())
      MCE.addRelocation(MachineRelocation(MCE.getCurrentPCOffset(),
                                          Reloc, MO.getGlobal(), 0));
    else
      MCE.addRelocation(MachineRelocation(MCE.getCurrentPCOffset(),
                                          Reloc, MO.getSymbolName(), 0));
  } else if (MO.isMachineBasicBlock()) {
    unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
    BBRefs.push_back(std::make_pair(MO.getMachineBasicBlock(), CurrPC));
  } else if (MO.isConstantPoolIndex()) {
    unsigned index = MO.getConstantPoolIndex();
    unsigned Opcode = MI.getOpcode();
    rv = MCE.getConstantPoolEntryAddress(index);
    if (Opcode == PPC::LIS || Opcode == PPC::ADDIS) {
      // lis wants hi16(addr)
      if ((short)rv < 0) rv += 1 << 16;
      rv >>= 16;
    } else if (Opcode == PPC::LWZ || Opcode == PPC::LA ||
               Opcode == PPC::LI ||
               Opcode == PPC::LFS || Opcode == PPC::LFD) {
      // These load opcodes want lo16(addr)
      rv &= 0xffff;
    } else {
      assert(0 && "Unknown constant pool using instruction!");
    }
  } else {
    std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n";
    abort();
  }

  return rv;
}

#include "PPCGenCodeEmitter.inc"

<|endoftext|>