<commit_before>//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, turning invoke instructions into calls, iff the callee cannot
// throw an exception, and marking functions 'nounwind' if they cannot throw.
// It implements this as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "prune-eh"
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CFG.h"
#include <algorithm>
using namespace llvm;

STATISTIC(NumRemoved, "Number of invokes removed");
STATISTIC(NumUnreach, "Number of noreturn calls optimized");

namespace {
  struct PruneEH : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    PruneEH() : CallGraphSCCPass(ID) {
      initializePruneEHPass(*PassRegistry::getPassRegistry());
    }

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(CallGraphSCC &SCC);

    bool SimplifyFunction(Function *F);
    void DeleteBasicBlock(BasicBlock *BB);
  };
}

char PruneEH::ID = 0;
INITIALIZE_PASS_BEGIN(PruneEH, "prune-eh",
                "Remove unused exception handling info", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_END(PruneEH, "prune-eh",
                "Remove unused exception handling info", false, false)

Pass *llvm::createPruneEHPass() { return new PruneEH(); }

bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
  SmallPtrSet<CallGraphNode *, 8> SCCNodes;
  CallGraph &CG = getAnalysis<CallGraph>();
  bool MadeChange = false;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert(*I);

  // First pass, scan all of the functions in the SCC, simplifying them
  // according to what we know.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    if (Function *F = (*I)->getFunction())
      MadeChange |= SimplifyFunction(F);

  // Next, check to see if any callees might throw or if there are any external
  // functions in this SCC: if so, we cannot prune any functions in this SCC.
  // Definitions that are weak and not declared non-throwing might be
  // overridden at linktime with something that throws, so assume that.
  // If this SCC includes the unwind instruction, we KNOW it throws, so
  // obviously the SCC might throw.
  //
  bool SCCMightUnwind = false, SCCMightReturn = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end();
       (!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) {
    Function *F = (*I)->getFunction();
    if (F == 0) {
      SCCMightUnwind = true;
      SCCMightReturn = true;
    } else if (F->isDeclaration() || F->mayBeOverridden()) {
      SCCMightUnwind |= !F->doesNotThrow();
      SCCMightReturn |= !F->doesNotReturn();
    } else {
      bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow();
      bool CheckReturn = !SCCMightReturn && !F->doesNotReturn();

      if (!CheckUnwind && !CheckReturn)
        continue;

      // Check to see if this function performs an unwind or calls an
      // unwinding function.
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
        if (CheckUnwind && isa<ResumeInst>(BB->getTerminator())) {
          // Uses unwind / resume!
          SCCMightUnwind = true;
        } else if (CheckReturn && isa<ReturnInst>(BB->getTerminator())) {
          SCCMightReturn = true;
        }

        // Invoke instructions don't allow unwinding to continue, so we are
        // only interested in call instructions.
        if (CheckUnwind && !SCCMightUnwind)
          for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
            if (CallInst *CI = dyn_cast<CallInst>(I)) {
              if (CI->doesNotThrow()) {
                // This call cannot throw.
              } else if (Function *Callee = CI->getCalledFunction()) {
                CallGraphNode *CalleeNode = CG[Callee];
                // If the callee is outside our current SCC then we may
                // throw because it might.
                if (!SCCNodes.count(CalleeNode)) {
                  SCCMightUnwind = true;
                  break;
                }
              } else {
                // Indirect call, it might throw.
                SCCMightUnwind = true;
                break;
              }
            }
        if (SCCMightUnwind && SCCMightReturn) break;
      }
    }
  }

  // If the SCC doesn't unwind or doesn't throw, note this fact.
  if (!SCCMightUnwind || !SCCMightReturn)
    for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
      AttrBuilder NewAttributes;

      if (!SCCMightUnwind)
        NewAttributes.addAttribute(Attribute::NoUnwind);
      if (!SCCMightReturn)
        NewAttributes.addAttribute(Attribute::NoReturn);

      Function *F = (*I)->getFunction();
      const AttributeSet &PAL = F->getAttributes();
      const AttributeSet &NPAL =
        PAL.addAttributes(F->getContext(), AttributeSet::FunctionIndex,
                          AttributeSet::get(F->getContext(),
                                            AttributeSet::FunctionIndex,
                                            NewAttributes));
      if (PAL != NPAL) {
        MadeChange = true;
        F->setAttributes(NPAL);
      }
    }

  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    // Convert any invoke instructions to non-throwing functions in this node
    // into call instructions with a branch.  This makes the exception blocks
    // dead.
    if (Function *F = (*I)->getFunction())
      MadeChange |= SimplifyFunction(F);
  }

  return MadeChange;
}

// SimplifyFunction - Given information about callees, simplify the specified
// function if we have invokes to non-unwinding functions or code after calls to
// no-return functions.
bool PruneEH::SimplifyFunction(Function *F) {
  bool MadeChange = false;
  for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
    if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
      if (II->doesNotThrow()) {
        SmallVector<Value*, 8> Args(II->op_begin(), II->op_end() - 3);
        // Insert a call instruction before the invoke.
        CallInst *Call = CallInst::Create(II->getCalledValue(), Args, "", II);
        Call->takeName(II);
        Call->setCallingConv(II->getCallingConv());
        Call->setAttributes(II->getAttributes());
        Call->setDebugLoc(II->getDebugLoc());

        // Anything that used the value produced by the invoke instruction
        // now uses the value produced by the call instruction.  Note that we
        // do this even for void functions and calls with no uses so that the
        // callgraph edge is updated.
        II->replaceAllUsesWith(Call);
        BasicBlock *UnwindBlock = II->getUnwindDest();
        UnwindBlock->removePredecessor(II->getParent());

        // Insert a branch to the normal destination right before the
        // invoke.
        BranchInst::Create(II->getNormalDest(), II);

        // Finally, delete the invoke instruction!
        BB->getInstList().pop_back();

        // If the unwind block is now dead, nuke it.
        if (pred_begin(UnwindBlock) == pred_end(UnwindBlock))
          DeleteBasicBlock(UnwindBlock);  // Delete the new BB.

        ++NumRemoved;
        MadeChange = true;
      }

    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
      if (CallInst *CI = dyn_cast<CallInst>(I++))
        if (CI->doesNotReturn() && !isa<UnreachableInst>(I)) {
          // This call calls a function that cannot return.  Insert an
          // unreachable instruction after it and simplify the code.  Do this
          // by splitting the BB, adding the unreachable, then deleting the
          // new BB.
          BasicBlock *New = BB->splitBasicBlock(I);

          // Remove the uncond branch and add an unreachable.
          BB->getInstList().pop_back();
          new UnreachableInst(BB->getContext(), BB);

          DeleteBasicBlock(New);  // Delete the new BB.
          MadeChange = true;
          ++NumUnreach;
          break;
        }
  }

  return MadeChange;
}

/// DeleteBasicBlock - remove the specified basic block from the program,
/// updating the callgraph to reflect any now-obsolete edges due to calls that
/// exist in the BB.
void PruneEH::DeleteBasicBlock(BasicBlock *BB) {
  assert(pred_begin(BB) == pred_end(BB) && "BB is not dead!");
  CallGraph &CG = getAnalysis<CallGraph>();

  CallGraphNode *CGN = CG[BB->getParent()];
  for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) {
    --I;
    if (CallInst *CI = dyn_cast<CallInst>(I)) {
      if (!isa<IntrinsicInst>(I))
        CGN->removeCallEdgeFor(CI);
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(I))
      CGN->removeCallEdgeFor(II);
    if (!I->use_empty())
      I->replaceAllUsesWith(UndefValue::get(I->getType()));
  }

  // Get the list of successors of this block.
  std::vector<BasicBlock*> Succs(succ_begin(BB), succ_end(BB));

  for (unsigned i = 0, e = Succs.size(); i != e; ++i)
    Succs[i]->removePredecessor(BB);

  BB->eraseFromParent();
}
<commit_msg>PruneEH: Only merge attribute sets when used. No functionality change.<commit_after>//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, turning invoke instructions into calls, iff the callee cannot
// throw an exception, and marking functions 'nounwind' if they cannot throw.
// It implements this as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "prune-eh"
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CFG.h"
#include <algorithm>
using namespace llvm;

STATISTIC(NumRemoved, "Number of invokes removed");
STATISTIC(NumUnreach, "Number of noreturn calls optimized");

namespace {
  struct PruneEH : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    PruneEH() : CallGraphSCCPass(ID) {
      initializePruneEHPass(*PassRegistry::getPassRegistry());
    }

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(CallGraphSCC &SCC);

    bool SimplifyFunction(Function *F);
    void DeleteBasicBlock(BasicBlock *BB);
  };
}

char PruneEH::ID = 0;
INITIALIZE_PASS_BEGIN(PruneEH, "prune-eh",
                "Remove unused exception handling info", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_END(PruneEH, "prune-eh",
                "Remove unused exception handling info", false, false)

Pass *llvm::createPruneEHPass() { return new PruneEH(); }

bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
  SmallPtrSet<CallGraphNode *, 8> SCCNodes;
  CallGraph &CG = getAnalysis<CallGraph>();
  bool MadeChange = false;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert(*I);

  // First pass, scan all of the functions in the SCC, simplifying them
  // according to what we know.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    if (Function *F = (*I)->getFunction())
      MadeChange |= SimplifyFunction(F);

  // Next, check to see if any callees might throw or if there are any external
  // functions in this SCC: if so, we cannot prune any functions in this SCC.
  // Definitions that are weak and not declared non-throwing might be
  // overridden at linktime with something that throws, so assume that.
  // If this SCC includes the unwind instruction, we KNOW it throws, so
  // obviously the SCC might throw.
  //
  bool SCCMightUnwind = false, SCCMightReturn = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end();
       (!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) {
    Function *F = (*I)->getFunction();
    if (F == 0) {
      SCCMightUnwind = true;
      SCCMightReturn = true;
    } else if (F->isDeclaration() || F->mayBeOverridden()) {
      SCCMightUnwind |= !F->doesNotThrow();
      SCCMightReturn |= !F->doesNotReturn();
    } else {
      bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow();
      bool CheckReturn = !SCCMightReturn && !F->doesNotReturn();

      if (!CheckUnwind && !CheckReturn)
        continue;

      // Check to see if this function performs an unwind or calls an
      // unwinding function.
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
        if (CheckUnwind && isa<ResumeInst>(BB->getTerminator())) {
          // Uses unwind / resume!
          SCCMightUnwind = true;
        } else if (CheckReturn && isa<ReturnInst>(BB->getTerminator())) {
          SCCMightReturn = true;
        }

        // Invoke instructions don't allow unwinding to continue, so we are
        // only interested in call instructions.
        if (CheckUnwind && !SCCMightUnwind)
          for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
            if (CallInst *CI = dyn_cast<CallInst>(I)) {
              if (CI->doesNotThrow()) {
                // This call cannot throw.
              } else if (Function *Callee = CI->getCalledFunction()) {
                CallGraphNode *CalleeNode = CG[Callee];
                // If the callee is outside our current SCC then we may
                // throw because it might.
                if (!SCCNodes.count(CalleeNode)) {
                  SCCMightUnwind = true;
                  break;
                }
              } else {
                // Indirect call, it might throw.
                SCCMightUnwind = true;
                break;
              }
            }
        if (SCCMightUnwind && SCCMightReturn) break;
      }
    }
  }

  // If the SCC doesn't unwind or doesn't throw, note this fact.
  if (!SCCMightUnwind || !SCCMightReturn)
    for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
      AttrBuilder NewAttributes;

      if (!SCCMightUnwind)
        NewAttributes.addAttribute(Attribute::NoUnwind);
      if (!SCCMightReturn)
        NewAttributes.addAttribute(Attribute::NoReturn);

      Function *F = (*I)->getFunction();
      const AttributeSet &PAL = F->getAttributes().getFnAttributes();
      const AttributeSet &NPAL = AttributeSet::get(
          F->getContext(), AttributeSet::FunctionIndex, NewAttributes);

      if (PAL != NPAL) {
        MadeChange = true;
        F->addAttributes(AttributeSet::FunctionIndex, NPAL);
      }
    }

  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    // Convert any invoke instructions to non-throwing functions in this node
    // into call instructions with a branch.  This makes the exception blocks
    // dead.
    if (Function *F = (*I)->getFunction())
      MadeChange |= SimplifyFunction(F);
  }

  return MadeChange;
}

// SimplifyFunction - Given information about callees, simplify the specified
// function if we have invokes to non-unwinding functions or code after calls to
// no-return functions.
bool PruneEH::SimplifyFunction(Function *F) {
  bool MadeChange = false;
  for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
    if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
      if (II->doesNotThrow()) {
        SmallVector<Value*, 8> Args(II->op_begin(), II->op_end() - 3);
        // Insert a call instruction before the invoke.
        CallInst *Call = CallInst::Create(II->getCalledValue(), Args, "", II);
        Call->takeName(II);
        Call->setCallingConv(II->getCallingConv());
        Call->setAttributes(II->getAttributes());
        Call->setDebugLoc(II->getDebugLoc());

        // Anything that used the value produced by the invoke instruction
        // now uses the value produced by the call instruction.  Note that we
        // do this even for void functions and calls with no uses so that the
        // callgraph edge is updated.
        II->replaceAllUsesWith(Call);
        BasicBlock *UnwindBlock = II->getUnwindDest();
        UnwindBlock->removePredecessor(II->getParent());

        // Insert a branch to the normal destination right before the
        // invoke.
        BranchInst::Create(II->getNormalDest(), II);

        // Finally, delete the invoke instruction!
        BB->getInstList().pop_back();

        // If the unwind block is now dead, nuke it.
        if (pred_begin(UnwindBlock) == pred_end(UnwindBlock))
          DeleteBasicBlock(UnwindBlock);  // Delete the new BB.

        ++NumRemoved;
        MadeChange = true;
      }

    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
      if (CallInst *CI = dyn_cast<CallInst>(I++))
        if (CI->doesNotReturn() && !isa<UnreachableInst>(I)) {
          // This call calls a function that cannot return.  Insert an
          // unreachable instruction after it and simplify the code.  Do this
          // by splitting the BB, adding the unreachable, then deleting the
          // new BB.
          BasicBlock *New = BB->splitBasicBlock(I);

          // Remove the uncond branch and add an unreachable.
          BB->getInstList().pop_back();
          new UnreachableInst(BB->getContext(), BB);

          DeleteBasicBlock(New);  // Delete the new BB.
          MadeChange = true;
          ++NumUnreach;
          break;
        }
  }

  return MadeChange;
}

/// DeleteBasicBlock - remove the specified basic block from the program,
/// updating the callgraph to reflect any now-obsolete edges due to calls that
/// exist in the BB.
void PruneEH::DeleteBasicBlock(BasicBlock *BB) {
  assert(pred_begin(BB) == pred_end(BB) && "BB is not dead!");
  CallGraph &CG = getAnalysis<CallGraph>();

  CallGraphNode *CGN = CG[BB->getParent()];
  for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) {
    --I;
    if (CallInst *CI = dyn_cast<CallInst>(I)) {
      if (!isa<IntrinsicInst>(I))
        CGN->removeCallEdgeFor(CI);
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(I))
      CGN->removeCallEdgeFor(II);
    if (!I->use_empty())
      I->replaceAllUsesWith(UndefValue::get(I->getType()));
  }

  // Get the list of successors of this block.
  std::vector<BasicBlock*> Succs(succ_begin(BB), succ_end(BB));

  for (unsigned i = 0, e = Succs.size(); i != e; ++i)
    Succs[i]->removePredecessor(BB);

  BB->eraseFromParent();
}
<|endoftext|>


<commit_before>#include "mainwindow.h"

#include <QKeyEvent>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    stackedLayout = new QStackedLayout(this);
    setLayout(stackedLayout);

    setWindowState(Qt::WindowFullScreen);

    QSettings settings;
    if (settings.value("hideCursor", false).toBool())
    {
        setCursor(Qt::BlankCursor);
    }
    else
    {
        settings.setValue("hideCursor", false);
    }

    sheetSelectWidget = new SheetSelectWidget(this);
    stackedLayout->addWidget(sheetSelectWidget);

    connect(sheetSelectWidget, SIGNAL(sheetSelected(QFileInfo)), this, SLOT(sheetSelected(QFileInfo)));
}

void MainWindow::keyPressEvent(QKeyEvent* event)
{
    if (sheetsWidget && (stackedLayout->currentWidget() == sheetsWidget.get()))
    {
        switch (event->key())
        {
        case Qt::Key_Plus:
            sheetsWidget->zoomIn();
            break;

        case Qt::Key_Minus:
            sheetsWidget->zoomOut();
            break;

        case Qt::Key_Up:
            sheetsWidget->moveUp();
            break;

        case Qt::Key_Down:
            sheetsWidget->moveDown();
            break;

        case Qt::Key_Left:
            sheetsWidget->moveLeft();
            break;

        case Qt::Key_Right:
            sheetsWidget->moveRight();
            break;

        case Qt::Key_0:
            sheetsWidget->resetZoomAndOffset();
            break;

        case Qt::Key_PageUp:
        case Qt::Key_1:
            if (!event->isAutoRepeat()) sheetsWidget->previousPagesSet();
            break;

        case Qt::Key_PageDown:
        case Qt::Key_3:
            if (!event->isAutoRepeat()) sheetsWidget->nextPagesSet();
            break;

        case Qt::Key_Meta:
        case Qt::Key_2:
            if (!event->isAutoRepeat()) sheetsWidget->toPreviousMarkedPage();
            break;

        case Qt::Key_Home:
            sheetsWidget->toFirstPage();
            break;

        case Qt::Key_End:
            sheetsWidget->toLastPage();
            break;

        case Qt::Key_F1:
            sheetsWidget->setShownPagesCount(1);
            break;

        case Qt::Key_F2:
            sheetsWidget->setShownPagesCount(2);
            break;

        case Qt::Key_F3:
            sheetsWidget->setShownPagesCount(3);
            break;

        case Qt::Key_F4:
            sheetsWidget->setShownPagesCount(4);
            break;

        case Qt::Key_F5:
            sheetsWidget->setShownPagesCount(5);
            break;

        case Qt::Key_F6:
            sheetsWidget->setShownPagesCount(6);
            break;

        case Qt::Key_F7:
            sheetsWidget->setShownPagesCount(7);
            break;

        case Qt::Key_F8:
            sheetsWidget->setShownPagesCount(8);
            break;

        case Qt::Key_Space:
            stackedLayout->setCurrentWidget(sheetSelectWidget);
            break;

        case Qt::Key_Q:
            close();
            break;

        default: QWidget::keyPressEvent(event);
        }
    }
    else
    {
        QWidget::keyPressEvent(event);
    }
}

void MainWindow::sheetSelected(const QFileInfo& sheetFile)
{
    if (!sheetsWidget || (sheetsWidget->getDocumentFileInfo() != sheetFile))
    {
        if (sheetsWidget)
        {
            stackedLayout->removeWidget(sheetsWidget.get());
        }

        sheetsWidget = std::unique_ptr<SheetsWidget>(new SheetsWidget(this, sheetFile));
        stackedLayout->addWidget(sheetsWidget.get());

        connect(sheetsWidget.get(), SIGNAL(requestShowSheetSelection()), this, SLOT(handleRequestShowSheetSelection()));
        connect(sheetsWidget.get(), SIGNAL(requestExit()), this, SLOT(close()));
    }

    stackedLayout->setCurrentWidget(sheetsWidget.get());
}

void MainWindow::handleRequestShowSheetSelection()
{
    stackedLayout->setCurrentWidget(sheetSelectWidget);
}
<commit_msg>support ctrl+c to kill application (without executing quit command)<commit_after>#include "mainwindow.h"

#include <QApplication>
#include <QKeyEvent>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    stackedLayout = new QStackedLayout(this);
    setLayout(stackedLayout);

    setWindowState(Qt::WindowFullScreen);

    QSettings settings;
    if (settings.value("hideCursor", false).toBool())
    {
        setCursor(Qt::BlankCursor);
    }
    else
    {
        settings.setValue("hideCursor", false);
    }

    sheetSelectWidget = new SheetSelectWidget(this);
    stackedLayout->addWidget(sheetSelectWidget);

    connect(sheetSelectWidget, SIGNAL(sheetSelected(QFileInfo)), this, SLOT(sheetSelected(QFileInfo)));
}

void MainWindow::keyPressEvent(QKeyEvent* event)
{
    if ((event->key() == Qt::Key_C) && (event->modifiers() == Qt::ControlModifier))
    {
        QApplication::quit();
    }

    if (sheetsWidget && (stackedLayout->currentWidget() == sheetsWidget.get()))
    {
        switch (event->key())
        {
        case Qt::Key_Plus:
            sheetsWidget->zoomIn();
            break;

        case Qt::Key_Minus:
            sheetsWidget->zoomOut();
            break;

        case Qt::Key_Up:
            sheetsWidget->moveUp();
            break;

        case Qt::Key_Down:
            sheetsWidget->moveDown();
            break;

        case Qt::Key_Left:
            sheetsWidget->moveLeft();
            break;

        case Qt::Key_Right:
            sheetsWidget->moveRight();
            break;

        case Qt::Key_0:
            sheetsWidget->resetZoomAndOffset();
            break;

        case Qt::Key_PageUp:
        case Qt::Key_1:
            if (!event->isAutoRepeat()) sheetsWidget->previousPagesSet();
            break;

        case Qt::Key_PageDown:
        case Qt::Key_3:
            if (!event->isAutoRepeat()) sheetsWidget->nextPagesSet();
            break;

        case Qt::Key_Meta:
        case Qt::Key_2:
            if (!event->isAutoRepeat()) sheetsWidget->toPreviousMarkedPage();
            break;

        case Qt::Key_Home:
            sheetsWidget->toFirstPage();
            break;

        case Qt::Key_End:
            sheetsWidget->toLastPage();
            break;

        case Qt::Key_F1:
            sheetsWidget->setShownPagesCount(1);
            break;

        case Qt::Key_F2:
            sheetsWidget->setShownPagesCount(2);
            break;

        case Qt::Key_F3:
            sheetsWidget->setShownPagesCount(3);
            break;

        case Qt::Key_F4:
            sheetsWidget->setShownPagesCount(4);
            break;

        case Qt::Key_F5:
            sheetsWidget->setShownPagesCount(5);
            break;

        case Qt::Key_F6:
            sheetsWidget->setShownPagesCount(6);
            break;

        case Qt::Key_F7:
            sheetsWidget->setShownPagesCount(7);
            break;

        case Qt::Key_F8:
            sheetsWidget->setShownPagesCount(8);
            break;

        case Qt::Key_Space:
            stackedLayout->setCurrentWidget(sheetSelectWidget);
            break;

        case Qt::Key_Q:
            close();
            break;

        default:
            QWidget::keyPressEvent(event);
        }
    }
    else
    {
        QWidget::keyPressEvent(event);
    }
}

void MainWindow::sheetSelected(const QFileInfo& sheetFile)
{
    if (!sheetsWidget || (sheetsWidget->getDocumentFileInfo() != sheetFile))
    {
        if (sheetsWidget)
        {
            stackedLayout->removeWidget(sheetsWidget.get());
        }

        sheetsWidget = std::unique_ptr<SheetsWidget>(new SheetsWidget(this, sheetFile));
        stackedLayout->addWidget(sheetsWidget.get());

        connect(sheetsWidget.get(), SIGNAL(requestShowSheetSelection()), this, SLOT(handleRequestShowSheetSelection()));
        connect(sheetsWidget.get(), SIGNAL(requestExit()), this, SLOT(close()));
    }

    stackedLayout->setCurrentWidget(sheetsWidget.get());
}

void MainWindow::handleRequestShowSheetSelection()
{
    stackedLayout->setCurrentWidget(sheetSelectWidget);
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file state.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * State test functions.
 */

#include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <ExtVMFace.h>
#include <Transaction.h>
#include <VM.h>
#include <Instruction.h>
using namespace std;
using namespace json_spirit;
using namespace eth;

namespace eth
{

class FakeExtVM: public ExtVMFace
{
public:
	FakeExtVM()
	{}
	FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
		ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber)
	{}

	u256 store(u256 _n) { return get<3>(addresses[myAddress])[_n]; }
	void setStore(u256 _n, u256 _v) { get<3>(addresses[myAddress])[_n] = _v; }
	void mktx(Transaction& _t)
	{
		if (get<0>(addresses[myAddress]) >= _t.value)
		{
			get<0>(addresses[myAddress]) -= _t.value;
			get<1>(addresses[myAddress])++;
//			get<0>(addresses[_t.receiveAddress]) += _t.value;
			txs.push_back(_t);
		}
	}
	u256 balance(Address _a) { return get<0>(addresses[_a]); }
	void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); }
	u256 txCount(Address _a) { return get<1>(addresses[_a]); }
	u256 extro(Address _a, u256 _pos) { return get<3>(addresses[_a])[_pos]; }
	u256 extroPrice(Address _a) { return get<2>(addresses[_a]); }
	void suicide(Address _a)
	{
		for (auto const& i: get<3>(addresses[myAddress]))
			if (i.second)
				get<0>(addresses[_a]) += fees.m_memoryFee;
		get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
		addresses.erase(myAddress);
	}

	void setTransaction(Address _txSender, u256 _txValue, u256s const& _txData)
	{
		txSender = _txSender;
		txValue = _txValue;
		txData = _txData;
	}
	void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		myAddress = _myAddress;
		set(myAddress, _myBalance, _myNonce, _myData);
	}
	void set(Address _a, u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		get<0>(addresses[_a]) = _myBalance;
		get<1>(addresses[_a]) = _myNonce;
		get<2>(addresses[_a]) = 0;
		for (unsigned i = 0; i < _myData.size(); ++i)
			get<3>(addresses[_a])[i] = _myData[i];
	}

	mObject exportEnv()
	{
		mObject ret;
		ret["previousHash"] = toString(previousBlock.hash);
		ret["previousNonce"] = toString(previousBlock.nonce);
		push(ret, "currentDifficulty", currentBlock.difficulty);
		push(ret, "currentTimestamp", currentBlock.timestamp);
		ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress);
		push(ret, "feeMultiplier", fees.multiplier());
		return ret;
	}

	void importEnv(mObject& _o)
	{
		previousBlock.hash = h256(_o["previousHash"].get_str());
		previousBlock.nonce = h256(_o["previousNonce"].get_str());
		currentBlock.difficulty = toInt(_o["currentDifficulty"]);
		currentBlock.timestamp = toInt(_o["currentTimestamp"]);
		currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
		fees.setMultiplier(toInt(_o["feeMultiplier"]));
	}

	static u256 toInt(mValue const& _v)
	{
		switch (_v.type())
		{
		case str_type: return u256(_v.get_str());
		case int_type: return (u256)_v.get_uint64();
		case bool_type: return (u256)(uint64_t)_v.get_bool();
		case real_type: return (u256)(uint64_t)_v.get_real();
		default: cwarn << "Bad type for scalar: " << _v.type();
		}
		return 0;
	}

	static void push(mObject& o, string const& _n, u256 _v)
	{
		if (_v < (u256)1 << 64)
			o[_n] = (uint64_t)_v;
		else
			o[_n] = toString(_v);
	}

	static void push(mArray& a, u256 _v)
	{
		if (_v < (u256)1 << 64)
			a.push_back((uint64_t)_v);
		else
			a.push_back(toString(_v));
	}

	mObject exportState()
	{
		mObject ret;
		for (auto const& a: addresses)
		{
			mObject o;
			push(o, "balance", get<0>(a.second));
			push(o, "nonce", get<1>(a.second));
			push(o, "extroPrice", get<2>(a.second));

			mObject store;
			string curKey;
			u256 li = 0;
			mArray curVal;
			for (auto const& s: get<3>(a.second))
			{
				if (!li || s.first > li + 8)
				{
					if (li)
						store[curKey] = curVal;
					li = s.first;
					curKey = toString(li);
					curVal = mArray();
				}
				else
					for (; li != s.first; ++li)
						curVal.push_back(0);
				push(curVal, s.second);
				++li;
			}
			if (li)
			{
				store[curKey] = curVal;
				o["store"] = store;
			}
			ret[toString(a.first)] = o;
		}
		return ret;
	}

	void importState(mObject& _o)
	{
		for (auto const& i: _o)
		{
			mObject o = i.second.get_obj();
			auto& a = addresses[Address(i.first)];
			get<0>(a) = toInt(o["balance"]);
			get<1>(a) = toInt(o["nonce"]);
			get<2>(a) = toInt(o["extroPrice"]);
			if (o.count("store"))
				for (auto const& j: o["store"].get_obj())
				{
					u256 adr(j.first);
					for (auto const& k: j.second.get_array())
						get<3>(a)[adr++] = toInt(k);
				}
			if (o.count("code"))
			{
				u256s d = compileLisp(o["code"].get_str());
				for (unsigned i = 0; i < d.size(); ++i)
					get<3>(a)[(u256)i] = d[i];
			}
		}
	}

	mObject exportExec()
	{
		mObject ret;
		ret["address"] = toString(myAddress);
		ret["sender"] = toString(txSender);
		push(ret, "value", txValue);
		mArray d;
		for (auto const& i: txData)
			push(d, i);
		ret["data"] = d;
		return ret;
	}

	void importExec(mObject& _o)
	{
		myAddress = Address(_o["address"].get_str());
		txSender = Address(_o["sender"].get_str());
		txValue = toInt(_o["value"]);
		for (auto const& j: _o["data"].get_array())
			txData.push_back(toInt(j));
	}

	mArray exportTxs()
	{
		mArray ret;
		for (Transaction const& tx: txs)
		{
			mObject o;
			o["destination"] = toString(tx.receiveAddress);
			push(o, "value", tx.value);
			mArray d;
			for (auto const& i: tx.data)
				push(d, i);
			o["data"] = d;
			ret.push_back(o);
		}
		return ret;
	}

	void importTxs(mArray& _txs)
	{
		for (mValue& v: _txs)
		{
			auto tx = v.get_obj();
			Transaction t;
			t.receiveAddress = Address(tx["destination"].get_str());
			t.value = toInt(tx["value"]);
			for (auto const& j: tx["data"].get_array())
				t.data.push_back(toInt(j));
			txs.push_back(t);
		}
	}

	void reset(u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		txs.clear();
		addresses.clear();
		set(myAddress, _myBalance, _myNonce, _myData);
	}

	map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
	Transactions txs;
};

#define CREATE_TESTS 0

template <> class UnitTest<1>
{
public:
	int operator()()
	{
		json_spirit::mValue v;
#if CREATE_TESTS
		string s = asString(contents("../../cpp-ethereum/test/vmtests.json"));
		json_spirit::read_string(s, v);
		bool passed = doTests(v, true);
		cout << json_spirit::write_string(v, true) << endl;
#else
		string s = asString(contents("../../tests/vmtests.json"));
		json_spirit::read_string(s, v);
		bool passed = doTests(v, false);
#endif
		return passed ? 0 : 1;
	}

	bool doTests(json_spirit::mValue& v, bool _fillin)
	{
		bool passed = true;
		for (auto& i: v.get_obj())
		{
			cnote << i.first;
			mObject& o = i.second.get_obj();

			VM vm;
			FakeExtVM fev;
			fev.importEnv(o["env"].get_obj());
			fev.importState(o["pre"].get_obj());

			if (_fillin)
				o["pre"] = mValue(fev.exportState());

			for (auto i: o["exec"].get_array())
			{
				fev.importExec(i.get_obj());
				vm.go(fev);
			}
			if (_fillin)
			{
				o["post"] = mValue(fev.exportState());
				o["txs"] = fev.exportTxs();
			}
			else
			{
				FakeExtVM test;
				test.importState(o["post"].get_obj());
				test.importTxs(o["txs"].get_array());
				if (test.addresses != fev.addresses)
				{
					cwarn << "Test failed: state different.";
					passed = false;
				}
				if (test.txs != fev.txs)
				{
					cwarn << "Test failed: tx list different:";
					cwarn << test.txs;
					cwarn << fev.txs;
					passed = false;
				}
			}
		}
		return passed;
	}

	string makeTestCase()
	{
		json_spirit::mObject o;

		VM vm;
		BlockInfo pb;
		pb.hash = sha3("previousHash");
		pb.nonce = sha3("previousNonce");
		BlockInfo cb = pb;
		cb.difficulty = 256;
		cb.timestamp = 1;
		cb.coinbaseAddress = toAddress(sha3("coinbase"));
		FeeStructure fees;
		fees.setMultiplier(1);
		FakeExtVM fev(fees, pb, cb, 0);
		fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
		o["env"] = fev.exportEnv();
		o["pre"] = fev.exportState();
		fev.setTransaction(toAddress(sha3("sender")), ether, u256s());
		mArray execs;
		execs.push_back(fev.exportExec());
		o["exec"] = execs;
		vm.go(fev);
		o["post"] = fev.exportState();
		o["txs"] = fev.exportTxs();

		return json_spirit::write_string(json_spirit::mValue(o), true);
	}
};

}

int vmTest()
{
	return UnitTest<1>()();
}

<commit_msg>Workaround OSX clang broken map operator[] using ifdef guards and manual find/insert.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file state.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * State test functions.
 */

#include <fstream>
#include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h"
#include <ExtVMFace.h>
#include <Transaction.h>
#include <VM.h>
#include <Instruction.h>
using namespace std;
using namespace json_spirit;
using namespace eth;

namespace eth
{

class FakeExtVM: public ExtVMFace
{
public:
	FakeExtVM()
	{}
	FakeExtVM(FeeStructure const& _fees, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
		ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber)
	{}

	u256 store(u256 _n)
	{
#ifdef __clang__
		tuple<u256, u256, u256, map<u256, u256> > & address = addresses[myAddress];
		map<u256, u256> & third = get<3>(address);
		auto sFinder = third.find(_n);
		if (sFinder != third.end())
			return sFinder->second;
		else
			return 0;
#else
		return get<3>(addresses[myAddress])[_n];
#endif
	}
	void setStore(u256 _n, u256 _v)
	{
#ifdef __clang__
		tuple<u256, u256, u256, map<u256, u256> > & address = addresses[myAddress];
		map<u256, u256> & third = get<3>(address);
		auto sFinder = third.find(_n);
		if (sFinder != third.end())
			sFinder->second = _v;
		else
			third.insert(std::make_pair(_n, _v));
#else
		get<3>(addresses[myAddress])[_n] = _v;
#endif
	}
	void mktx(Transaction& _t)
	{
		if (get<0>(addresses[myAddress]) >= _t.value)
		{
			get<0>(addresses[myAddress]) -= _t.value;
			get<1>(addresses[myAddress])++;
//			get<0>(addresses[_t.receiveAddress]) += _t.value;
			txs.push_back(_t);
		}
	}
	u256 balance(Address _a) { return get<0>(addresses[_a]); }
	void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); }
	u256 txCount(Address _a) { return get<1>(addresses[_a]); }
	u256 extro(Address _a, u256 _pos)
	{
#ifdef __clang__
		tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a];
		map<u256, u256> & third = get<3>(address);
		auto sFinder = third.find(_pos);
		if (sFinder != third.end())
			return sFinder->second;
		else
			return 0;
#else
		return get<3>(addresses[_a])[_pos];
#endif
	}
	u256 extroPrice(Address _a) { return get<2>(addresses[_a]); }
	void suicide(Address _a)
	{
		for (auto const& i: get<3>(addresses[myAddress]))
			if (i.second)
				get<0>(addresses[_a]) += fees.m_memoryFee;
		get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
		addresses.erase(myAddress);
	}

	void setTransaction(Address _txSender, u256 _txValue, u256s const& _txData)
	{
		txSender = _txSender;
		txValue = _txValue;
		txData = _txData;
	}
	void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		myAddress = _myAddress;
		set(myAddress, _myBalance, _myNonce, _myData);
	}
	void set(Address _a, u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		get<0>(addresses[_a]) = _myBalance;
		get<1>(addresses[_a]) = _myNonce;
		get<2>(addresses[_a]) = 0;
		for (unsigned i = 0; i < _myData.size(); ++i)
#ifdef __clang__
		{
			tuple<u256, u256, u256, map<u256, u256> > & address = addresses[_a];
			map<u256, u256> & third = get<3>(address);
			auto sFinder = third.find(i);
			if (sFinder != third.end())
				sFinder->second = _myData[i];
			else
				third.insert(std::make_pair(i, _myData[i]));
		}
#else
			get<3>(addresses[_a])[i] = _myData[i];
#endif
	}

	mObject exportEnv()
	{
		mObject ret;
		ret["previousHash"] = toString(previousBlock.hash);
		ret["previousNonce"] = toString(previousBlock.nonce);
		push(ret, "currentDifficulty", currentBlock.difficulty);
		push(ret, "currentTimestamp", currentBlock.timestamp);
		ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress);
		push(ret, "feeMultiplier", fees.multiplier());
		return ret;
	}

	void importEnv(mObject& _o)
	{
		previousBlock.hash = h256(_o["previousHash"].get_str());
		previousBlock.nonce = h256(_o["previousNonce"].get_str());
		currentBlock.difficulty = toInt(_o["currentDifficulty"]);
		currentBlock.timestamp = toInt(_o["currentTimestamp"]);
		currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
		fees.setMultiplier(toInt(_o["feeMultiplier"]));
	}

	static u256 toInt(mValue const& _v)
	{
		switch (_v.type())
		{
		case str_type: return u256(_v.get_str());
		case int_type: return (u256)_v.get_uint64();
		case bool_type: return (u256)(uint64_t)_v.get_bool();
		case real_type: return (u256)(uint64_t)_v.get_real();
		default: cwarn << "Bad type for scalar: " << _v.type();
		}
		return 0;
	}

	static void push(mObject& o, string const& _n, u256 _v)
	{
		if (_v < (u256)1 << 64)
			o[_n] = (uint64_t)_v;
		else
			o[_n] = toString(_v);
	}

	static void push(mArray& a, u256 _v)
	{
		if (_v < (u256)1 << 64)
			a.push_back((uint64_t)_v);
		else
			a.push_back(toString(_v));
	}

	mObject exportState()
	{
		mObject ret;
		for (auto const& a: addresses)
		{
			mObject o;
			push(o, "balance", get<0>(a.second));
			push(o, "nonce", get<1>(a.second));
			push(o, "extroPrice", get<2>(a.second));

			mObject store;
			string curKey;
			u256 li = 0;
			mArray curVal;
			for (auto const& s: get<3>(a.second))
			{
				if (!li || s.first > li + 8)
				{
					if (li)
						store[curKey] = curVal;
					li = s.first;
					curKey = toString(li);
					curVal = mArray();
				}
				else
					for (; li != s.first; ++li)
						curVal.push_back(0);
				push(curVal, s.second);
				++li;
			}
			if (li)
			{
				store[curKey] = curVal;
				o["store"] = store;
			}
			ret[toString(a.first)] = o;
		}
		return ret;
	}

	void importState(mObject& _o)
	{
		for (auto const& i: _o)
		{
			mObject o = i.second.get_obj();
			auto& a = addresses[Address(i.first)];
			get<0>(a) = toInt(o["balance"]);
			get<1>(a) = toInt(o["nonce"]);
			get<2>(a) = toInt(o["extroPrice"]);
			if (o.count("store"))
				for (auto const& j: o["store"].get_obj())
				{
					u256 adr(j.first);
					for (auto const& k: j.second.get_array())
#ifdef __clang__
					{
						map<u256, u256> & third = get<3>(a);
						auto sFinder = third.find(adr);
						if (sFinder != third.end())
							sFinder->second = toInt(k);
						else
							third.insert(std::make_pair(adr, toInt(k)));
						adr++;
					}
#else
						get<3>(a)[adr++] = toInt(k);
#endif
				}
			if (o.count("code"))
			{
				u256s d = compileLisp(o["code"].get_str());
				for (unsigned i = 0; i < d.size(); ++i)
#ifdef __clang__
				{
					map<u256, u256> & third = get<3>(a);
					auto sFinder = third.find(i);
					if (sFinder != third.end())
						sFinder->second = d[i];
					else
						third.insert(std::make_pair(i, d[i]));
				}
#else
					get<3>(a)[(u256)i] = d[i];
#endif
			}
		}
	}

	mObject exportExec()
	{
		mObject ret;
		ret["address"] = toString(myAddress);
		ret["sender"] = toString(txSender);
		push(ret, "value", txValue);
		mArray d;
		for (auto const& i: txData)
			push(d, i);
		ret["data"] = d;
		return ret;
	}

	void importExec(mObject& _o)
	{
		myAddress = Address(_o["address"].get_str());
		txSender = Address(_o["sender"].get_str());
		txValue = toInt(_o["value"]);
		for (auto const& j: _o["data"].get_array())
			txData.push_back(toInt(j));
	}

	mArray exportTxs()
	{
		mArray ret;
		for (Transaction const& tx: txs)
		{
			mObject o;
			o["destination"] = toString(tx.receiveAddress);
			push(o, "value", tx.value);
			mArray d;
			for (auto const& i: tx.data)
				push(d, i);
			o["data"] = d;
			ret.push_back(o);
		}
		return ret;
	}

	void importTxs(mArray& _txs)
	{
		for (mValue& v: _txs)
		{
			auto tx = v.get_obj();
			Transaction t;
			t.receiveAddress = Address(tx["destination"].get_str());
			t.value = toInt(tx["value"]);
			for (auto const& j: tx["data"].get_array())
				t.data.push_back(toInt(j));
			txs.push_back(t);
		}
	}

	void reset(u256 _myBalance, u256 _myNonce, u256s _myData)
	{
		txs.clear();
		addresses.clear();
		set(myAddress, _myBalance, _myNonce, _myData);
	}

	map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
	Transactions txs;
};

#define CREATE_TESTS 0

template <> class UnitTest<1>
{
public:
	int operator()()
	{
		json_spirit::mValue v;
#if CREATE_TESTS
		string s = asString(contents("../../cpp-ethereum/test/vmtests.json"));
		json_spirit::read_string(s, v);
		bool passed = doTests(v, true);
		cout << json_spirit::write_string(v, true) << endl;
#else
		string s = asString(contents("../../tests/vmtests.json"));
		json_spirit::read_string(s, v);
		bool passed = doTests(v, false);
#endif
		return passed ? 0 : 1;
	}

	bool doTests(json_spirit::mValue& v, bool _fillin)
	{
		bool passed = true;
		for (auto& i: v.get_obj())
		{
			cnote << i.first;
			mObject& o = i.second.get_obj();

			VM vm;
			FakeExtVM fev;
			fev.importEnv(o["env"].get_obj());
			fev.importState(o["pre"].get_obj());

			if (_fillin)
				o["pre"] = mValue(fev.exportState());

			for (auto i: o["exec"].get_array())
			{
				fev.importExec(i.get_obj());
				vm.go(fev);
			}
			if (_fillin)
			{
				o["post"] = mValue(fev.exportState());
				o["txs"] = fev.exportTxs();
			}
			else
			{
				FakeExtVM test;
				test.importState(o["post"].get_obj());
				test.importTxs(o["txs"].get_array());
				if (test.addresses != fev.addresses)
				{
					cwarn << "Test failed: state different.";
					passed = false;
				}
				if (test.txs != fev.txs)
				{
					cwarn << "Test failed: tx list different:";
					cwarn << test.txs;
					cwarn << fev.txs;
					passed = false;
				}
			}
		}
		return passed;
	}

	string makeTestCase()
	{
		json_spirit::mObject o;

		VM vm;
		BlockInfo pb;
		pb.hash = sha3("previousHash");
		pb.nonce = sha3("previousNonce");
		BlockInfo cb = pb;
		cb.difficulty = 256;
		cb.timestamp = 1;
		cb.coinbaseAddress = toAddress(sha3("coinbase"));
		FeeStructure fees;
		fees.setMultiplier(1);
		FakeExtVM fev(fees, pb, cb, 0);
		fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
		o["env"] = fev.exportEnv();
		o["pre"] = fev.exportState();
		fev.setTransaction(toAddress(sha3("sender")), ether, u256s());
		mArray execs;
		execs.push_back(fev.exportExec());
		o["exec"] = execs;
		vm.go(fev);
		o["post"] = fev.exportState();
		o["txs"] = fev.exportTxs();

		return json_spirit::write_string(json_spirit::mValue(o), true);
	}
};

}

int vmTest()
{
	return UnitTest<1>()();
}

<|endoftext|>


<commit_before>#ifndef BLUETOE_LINK_LAYER_NOTIFICATION_QUEUE_HPP
#define BLUETOE_LINK_LAYER_NOTIFICATION_QUEUE_HPP

#include <cstdint>
#include <cstdlib>
#include <utility>
#include <cassert>
#include <algorithm>
#include <iterator>

namespace bluetoe {
namespace link_layer {

    /**
     * @brief class responsible to keep track of those characteristics that have outstanding
     *        notifications.
     *
     * All operations on the queue must be reentrent / atomic!
     *
     * @param Size Number of characteristics that have notifications and / or indications enabled
     * @param Mixin a class to be mixed in, to allow empty base class optimizations
     *
     * For all function, index is an index into a list of all the characterstics with notifications / indications
     * enable. The queue is implemented by an array that contains
     */
    template < std::size_t Size, class Mixin >
    class notification_queue : public Mixin
    {
    public:
        /**
         * @brief constructs an empty notification_queue
         *
         * All constructor arguments are ment to be passed to the derviced Mixin
         */
        template < class ... Args >
        notification_queue( Args... mixin_arguments );

        /**
         * @brief queue the indexed characteristic for notification
         *
         * Once a characteristic is queued for notification, the function
         * dequeue_indication_or_confirmation() will return { notification, index }
         * on a future call.
         *
         * If the given characteristic was already queued for notification, the function
         * will not have any side effects.
         *
         * The function returns true, if the given characteristic was not already queued for notifications.
         *
         * @pre index < Size
         */
        bool queue_notification( std::size_t index );

        /**
         * @brief queue the indexed characteristic for indication
         *
         * Once a characteristic is queued for indication, the function
         * dequeue_indication_or_confirmation() will return { indication, index }
         * om a future call.
         *
         * If the given characteristic was already queued for indication, or
         * if a indication that was send to a client was not confirmed yet,
         * the function will not have any side effects.
         *
         * The function returns true, if the given characteristic was not already queued for indication or
         * if a confirmations is still awaited.
         *
         * @pre index < Size
         */
        bool queue_indication( std::size_t index );

        /**
         * @brief to be called, when a ATT Handle Value Confirmation was received.
         *
         * If not outstanding confirmation is registered, the
         * function has not side effect.
         */
        void indication_confirmed();

        /**
         * @brief type of entry
         */
        enum entry_type {
            /** returned if there no entry */
            empty,
            /** returned if the entry is a notification */
            notification,
            /** returned if the entry is an indication */
            indication
        };

        /**
         * @brief return a next notification or indication to be send.
         *
         * For a returned notification, the function will remove the returned entry.
         * For a returned indication, the function will change the entry to 'unconfirmed' and
         * will not return any indications until indication_confirmed() is called for the
         * returned index.
         */
        std::pair< entry_type, std::size_t > dequeue_indication_or_confirmation();

        /**
         * @brief removes all entries from the queue
         */
        void clear_indications_and_confirmations();
    private:
        int at( std::size_t index );
        bool add( std::size_t index, int );
        void remove( std::size_t index, int );

        static constexpr std::size_t bits_per_characteristc = 2;

        enum char_bits {
            notification_bit = 0x01,
            indication_bit   = 0x02
        };

        std::size_t     next_;
        std::uint8_t    queue_[ ( Size * bits_per_characteristc + 7 ) / 8 ];
        std::size_t     outstanding_confirmation_;

    };

    /**
     * @brief Specialisation for zero characteritics with notification or indication enabled
     */
    template < class Mixin >
    class notification_queue< 0, Mixin > : public Mixin
    {
    public:
        /** @cond HIDDEN_SYMBOLS */

        template < class ... Args >
        notification_queue( Args... mixin_arguments )
            : Mixin( mixin_arguments... )
        {
        }

        bool queue_notification( std::size_t ) { return false; }
        bool queue_indication( std::size_t ) { return false; }
        void indication_confirmed() {}

        enum entry_type {
            empty,
            notification,
            indication
        };

        std::pair< entry_type, std::size_t > dequeue_indication_or_confirmation()
        {
            return { empty, 0 };
        }

        void clear_indications_and_confirmations() {}
        /** @endcond */
    };

    // implementation
    template < std::size_t Size, class Mixin >
    template < class ... Args >
    notification_queue< Size, Mixin >::notification_queue( Args... mixin_arguments )
        : Mixin( mixin_arguments... )
    {
        clear_indications_and_confirmations();
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::queue_notification( std::size_t index )
    {
        assert( index < Size );
        return add( index, notification_bit );
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::queue_indication( std::size_t index )
    {
        assert( index < Size );

        if ( outstanding_confirmation_ == index )
            return false;

        return add( index, indication_bit );
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::indication_confirmed()
    {
        if ( outstanding_confirmation_ != Size )
        {
            outstanding_confirmation_ = Size;
        }
    }

    template < std::size_t Size, class Mixin >
    std::pair< typename notification_queue< Size, Mixin >::entry_type, std::size_t > notification_queue< Size, Mixin >::dequeue_indication_or_confirmation()
    {
        bool ignore_first = true;

        // loop over all entries in a circle
        for ( std::size_t i = next_; ignore_first || i != next_; i = ( i + 1 ) % Size )
        {
            ignore_first = false;
            auto entry = at( i );

            if ( entry & indication_bit && outstanding_confirmation_ == Size )
            {
                outstanding_confirmation_ = i;
                next_ = ( i + 1 ) % Size;
                remove( i, indication_bit );
                return { indication, i };
            }
            else if ( entry & notification_bit )
            {
                next_ = ( i + 1 ) % Size;
                remove( i, notification_bit );
                return { notification, i };
            }

        }

        return { empty, 0 };
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::clear_indications_and_confirmations()
    {
        next_ = 0;
        outstanding_confirmation_ = Size;
        std::fill( std::begin( queue_ ), std::end( queue_ ), 0 );
    }

    template < std::size_t Size, class Mixin >
    int notification_queue< Size, Mixin >::at( std::size_t index )
    {
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        return ( queue_[ byte_offset ] >> bit_offset ) & 0x03;
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::add( std::size_t index, int bits )
    {
        assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        const bool result = ( queue_[ byte_offset ] & ( bits << bit_offset ) ) == 0;
        queue_[ byte_offset ] |= bits << bit_offset;

        return result;
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::remove( std::size_t index, int bits )
    {
        assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        queue_[ byte_offset ] &= ~( bits << bit_offset );
    }

}
}

#endif // include guard
<commit_msg>documentation<commit_after>#ifndef BLUETOE_LINK_LAYER_NOTIFICATION_QUEUE_HPP
#define BLUETOE_LINK_LAYER_NOTIFICATION_QUEUE_HPP

#include <cstdint>
#include <cstdlib>
#include <utility>
#include <cassert>
#include <algorithm>
#include <iterator>

namespace bluetoe {
namespace link_layer {

    /**
     * @brief class responsible to keep track of those characteristics that have outstanding
     *        notifications.
     *
     * All operations on the queue must be reentrent / atomic!
     *
     * @param Size Number of characteristics that have notifications and / or indications enabled
     * @param Mixin a class to be mixed in, to allow empty base class optimizations
     *
     * For all function, index is an index into a list of all the characterstics with notifications / indications
     * enable. The queue is implemented by an array that contains a few bits (2) per characteristic to store the
     * requested (or queued) notifications / indications.
     */
    template < std::size_t Size, class Mixin >
    class notification_queue : public Mixin
    {
    public:
        /**
         * @brief constructs an empty notification_queue
         *
         * All constructor arguments are ment to be passed to the derviced Mixin
         */
        template < class ... Args >
        notification_queue( Args... mixin_arguments );

        /**
         * @brief queue the indexed characteristic for notification
         *
         * Once a characteristic is queued for notification, the function
         * dequeue_indication_or_confirmation() will return { notification, index }
         * on a future call.
         *
         * If the given characteristic was already queued for notification, the function
         * will not have any side effects.
         *
         * The function returns true, if the given characteristic was not already queued for notifications.
         *
         * @pre index < Size
         */
        bool queue_notification( std::size_t index );

        /**
         * @brief queue the indexed characteristic for indication
         *
         * Once a characteristic is queued for indication, the function
         * dequeue_indication_or_confirmation() will return { indication, index }
         * om a future call.
         *
         * If the given characteristic was already queued for indication, or
         * if a indication that was send to a client was not confirmed yet,
         * the function will not have any side effects.
         *
         * The function returns true, if the given characteristic was not already queued for indication or
         * if a confirmations is still awaited.
         *
         * @pre index < Size
         */
        bool queue_indication( std::size_t index );

        /**
         * @brief to be called, when a ATT Handle Value Confirmation was received.
         *
         * If not outstanding confirmation is registered, the
         * function has not side effect.
         */
        void indication_confirmed();

        /**
         * @brief type of entry
         */
        enum entry_type {
            /** returned if there no entry */
            empty,
            /** returned if the entry is a notification */
            notification,
            /** returned if the entry is an indication */
            indication
        };

        /**
         * @brief return a next notification or indication to be send.
         *
         * For a returned notification, the function will remove the returned entry.
         * For a returned indication, the function will change the entry to 'unconfirmed' and
         * will not return any indications until indication_confirmed() is called for the
         * returned index.
         */
        std::pair< entry_type, std::size_t > dequeue_indication_or_confirmation();

        /**
         * @brief removes all entries from the queue
         */
        void clear_indications_and_confirmations();
    private:
        int at( std::size_t index );
        bool add( std::size_t index, int );
        void remove( std::size_t index, int );

        static constexpr std::size_t bits_per_characteristc = 2;

        enum char_bits {
            notification_bit = 0x01,
            indication_bit   = 0x02
        };

        std::size_t     next_;
        std::uint8_t    queue_[ ( Size * bits_per_characteristc + 7 ) / 8 ];
        std::size_t     outstanding_confirmation_;

    };

    /**
     * @brief Specialisation for zero characteritics with notification or indication enabled
     */
    template < class Mixin >
    class notification_queue< 0, Mixin > : public Mixin
    {
    public:
        /** @cond HIDDEN_SYMBOLS */

        template < class ... Args >
        notification_queue( Args... mixin_arguments )
            : Mixin( mixin_arguments... )
        {
        }

        bool queue_notification( std::size_t ) { return false; }
        bool queue_indication( std::size_t ) { return false; }
        void indication_confirmed() {}

        enum entry_type {
            empty,
            notification,
            indication
        };

        std::pair< entry_type, std::size_t > dequeue_indication_or_confirmation()
        {
            return { empty, 0 };
        }

        void clear_indications_and_confirmations() {}
        /** @endcond */
    };

    // implementation
    template < std::size_t Size, class Mixin >
    template < class ... Args >
    notification_queue< Size, Mixin >::notification_queue( Args... mixin_arguments )
        : Mixin( mixin_arguments... )
    {
        clear_indications_and_confirmations();
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::queue_notification( std::size_t index )
    {
        assert( index < Size );
        return add( index, notification_bit );
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::queue_indication( std::size_t index )
    {
        assert( index < Size );

        if ( outstanding_confirmation_ == index )
            return false;

        return add( index, indication_bit );
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::indication_confirmed()
    {
        if ( outstanding_confirmation_ != Size )
        {
            outstanding_confirmation_ = Size;
        }
    }

    template < std::size_t Size, class Mixin >
    std::pair< typename notification_queue< Size, Mixin >::entry_type, std::size_t > notification_queue< Size, Mixin >::dequeue_indication_or_confirmation()
    {
        bool ignore_first = true;

        // loop over all entries in a circle
        for ( std::size_t i = next_; ignore_first || i != next_; i = ( i + 1 ) % Size )
        {
            ignore_first = false;
            auto entry = at( i );

            if ( entry & indication_bit && outstanding_confirmation_ == Size )
            {
                outstanding_confirmation_ = i;
                next_ = ( i + 1 ) % Size;
                remove( i, indication_bit );
                return { indication, i };
            }
            else if ( entry & notification_bit )
            {
                next_ = ( i + 1 ) % Size;
                remove( i, notification_bit );
                return { notification, i };
            }

        }

        return { empty, 0 };
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::clear_indications_and_confirmations()
    {
        next_ = 0;
        outstanding_confirmation_ = Size;
        std::fill( std::begin( queue_ ), std::end( queue_ ), 0 );
    }

    template < std::size_t Size, class Mixin >
    int notification_queue< Size, Mixin >::at( std::size_t index )
    {
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        return ( queue_[ byte_offset ] >> bit_offset ) & 0x03;
    }

    template < std::size_t Size, class Mixin >
    bool notification_queue< Size, Mixin >::add( std::size_t index, int bits )
    {
        assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        const bool result = ( queue_[ byte_offset ] & ( bits << bit_offset ) ) == 0;
        queue_[ byte_offset ] |= bits << bit_offset;

        return result;
    }

    template < std::size_t Size, class Mixin >
    void notification_queue< Size, Mixin >::remove( std::size_t index, int bits )
    {
        assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
        const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
        const auto byte_offset = index * bits_per_characteristc / 8;
        assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );

        queue_[ byte_offset ] &= ~( bits << bit_offset );
    }

}
}

#endif // include guard
<|endoftext|>


<commit_before>/*
 *    The MIT License
 *
 *    Copyright (c) 2011, Tamás Szelei
 *
 *    Permission is hereby granted, free of charge, to any person obtaining a copy
 *    of this software and associated documentation files (the "Software"), to deal
 *    in the Software without restriction, including without limitation the rights
 *    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *    copies of the Software, and to permit persons to whom the Software is
 *    furnished to do so, subject to the following conditions:
 *
 *    The above copyright notice and this permission notice shall be included in
 *    all copies or substantial portions of the Software.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *    THE SOFTWARE.
 */

#include "consts.h"
#include "instruction.h"
#include "mipscpu.h"

#include <iostream>

namespace tememu
{
    #define REG_OP_FUNC(fn,code) this->_fnMap[(code)] = (&tememu::MipsCPU::fn)

    MipsCPU::MipsCPU()
        : _HI(0), _LO(0), _PC(4), _nPC(4), _FCSR(0)
    {
        _GPR.reserve(gpr_count);
        _FPR.reserve(fpr_count);
        _FCR.reserve(fcr_count);

        for ( int i = 0; i < gpr_count; ++i ) _GPR.push_back(0);
        for ( int i = 0; i < fpr_count; ++i ) _FPR.push_back(0);
        for ( int i = 0; i < fcr_count; ++i ) _FCR.push_back(0);

        // set up instruction table
        // see runDecodedInstr for the construction of the constants

        REG_OP_FUNC(op_add,     0x20 << 4);
        REG_OP_FUNC(op_addu,    0x21 << 4);
        REG_OP_FUNC(op_sub,     0x22 << 4);
        REG_OP_FUNC(op_subu,    0x23 << 4);
        REG_OP_FUNC(op_addi,    0x8);
        REG_OP_FUNC(op_addiu,   0x9);
        REG_OP_FUNC(op_mult,    0x18 << 4);
        REG_OP_FUNC(op_div,     0x1A << 4);
        REG_OP_FUNC(op_divu,    0x1B << 4);

        REG_OP_FUNC(op_beq,     0x04);
    }

    /**
     * @brief Extracts the internal opcode for the function and dispatches the call.
     *
     * @param instr The raw instruction.
     */
    void MipsCPU::runDecodedInstr(int32 instr)
    {
        int32 opcode = (instr & 0x03fffffff) >> 26;
        int32 internal_opcode = 0, func = 0;

        if (opcode == 0)
        {
            func = instr & 0x0000003F;
            internal_opcode = func << 4;
        }
        else
        {
            internal_opcode = opcode;
        }

#if defined(DEBUG) && defined(TRACE_OPCODES)
        std::cout << "opcode = " << opcode << ", func = " << func << ", internal_opcode = " << internal_opcode << "\n";
#endif

        boost::unordered_map<int32, OpcodeFn>::iterator it = _fnMap.find(internal_opcode);

        if (it != _fnMap.end())
        {
            CALL_MEMBER(this, (*it).second)(instr);
        }
        else
        {
#ifdef DEBUG
            std::cout << "Unknown internal_opcode: " << internal_opcode << "\n";
#endif
            step();
        }
    }

    void MipsCPU::advance_pc(int32 offset)
    {
        _PC = _nPC;
        _nPC += offset;
    }

    void MipsCPU::op_add(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = _GPR[i.rs] + _GPR[i.rt];
        step();
    }

    void MipsCPU::op_addu(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = (boost::uint32_t)(_GPR[i.rs]) + (boost::uint32_t)(_GPR[i.rt]);
        step();
    }

    void MipsCPU::op_addi(int32 instr)
    {
        IInstruction i(instr);
        _GPR[i.rt] = _GPR[i.rs] + i.immediate;
        step();
    }

    void MipsCPU::op_addiu(int32 instr)
    {
        IInstruction i(instr);
        _GPR[i.rt] = _GPR[i.rs] + i.immediate;
        step();
    }

    void MipsCPU::op_sub(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = _GPR[i.rs] - _GPR[i.rt];
        step();
    }

    void MipsCPU::op_subu(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = (boost::uint32_t)(_GPR[i.rs]) - (boost::uint32_t)(_GPR[i.rt]);
        step();
    }

    void MipsCPU::op_mult(int32 instr)
    {
        RInstruction i(instr);
        _LO = ((_GPR[i.rt] * _GPR[i.rs]) << 16) >> 16;
        _HI = (_GPR[i.rt] * _GPR[i.rs]) << 16;
        step();
    }

    void MipsCPU::op_div(int32 instr)
    {
        RInstruction i(instr);
        _LO = _GPR[i.rs] / _GPR[i.rt];
        _HI = _GPR[i.rs] % _GPR[i.rt];
        step();
    }

    void MipsCPU::op_divu(int32 instr)
    {
        RInstruction i(instr);
        _LO = _GPR[i.rs] / _GPR[i.rt];
        _HI = _GPR[i.rs] % _GPR[i.rt];
        step();
    }

    void MipsCPU::op_beq(int32 instr)
    {
        IInstruction i(instr);
        if (_GPR[i.rs] == _GPR[i.rt])
        {
            advance_pc(4 + 4 * i.immediate);
        }
        else
        {
            step();
        }
    }

    void MipsCPU::loadProgram(boost::shared_ptr< std::vector<int32> > program)
    {
        _program = program;
    }

    void MipsCPU::runProgram()
    {
        std::vector<int32>* p = _program.get();

        while (_nPC / 4 - 1 < p->size())
            runDecodedInstr(p->at(_nPC / 4 - 1));
    }

} // tememu
<commit_msg>added op_bne, op_j, op_jr, op_jal<commit_after>/*
 *    The MIT License
 *
 *    Copyright (c) 2011, Tamás Szelei
 *
 *    Permission is hereby granted, free of charge, to any person obtaining a copy
 *    of this software and associated documentation files (the "Software"), to deal
 *    in the Software without restriction, including without limitation the rights
 *    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *    copies of the Software, and to permit persons to whom the Software is
 *    furnished to do so, subject to the following conditions:
 *
 *    The above copyright notice and this permission notice shall be included in
 *    all copies or substantial portions of the Software.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *    THE SOFTWARE.
 */

#include "consts.h"
#include "instruction.h"
#include "mipscpu.h"

#include <iostream>

namespace tememu
{
    #define REG_OP_FUNC(fn,code) this->_fnMap[(code)] = (&tememu::MipsCPU::fn)

    MipsCPU::MipsCPU()
        : _HI(0), _LO(0), _PC(4), _nPC(4), _FCSR(0)
    {
        _GPR.reserve(gpr_count);
        _FPR.reserve(fpr_count);
        _FCR.reserve(fcr_count);

        for ( int i = 0; i < gpr_count; ++i ) _GPR.push_back(0);
        for ( int i = 0; i < fpr_count; ++i ) _FPR.push_back(0);
        for ( int i = 0; i < fcr_count; ++i ) _FCR.push_back(0);

        // set up instruction table
        // see runDecodedInstr for the construction of the constants
        // R instructions internal opcodes = funct << 4.

        REG_OP_FUNC(op_add,     0x20 << 4);
        REG_OP_FUNC(op_addu,    0x21 << 4);
        REG_OP_FUNC(op_sub,     0x22 << 4);
        REG_OP_FUNC(op_subu,    0x23 << 4);
        REG_OP_FUNC(op_addi,    0x8);
        REG_OP_FUNC(op_addiu,   0x9);
        REG_OP_FUNC(op_mult,    0x18 << 4);
        REG_OP_FUNC(op_div,     0x1A << 4);
        REG_OP_FUNC(op_divu,    0x1B << 4);

        REG_OP_FUNC(op_beq,     0x04);
        REG_OP_FUNC(op_bne,     0x05);
        REG_OP_FUNC(op_j,       0x02);
        REG_OP_FUNC(op_jal,     0x03);
        REG_OP_FUNC(op_jr,      0x08 << 4);
    }

    /**
     * @brief Extracts the internal opcode for the function and dispatches the call.
     *
     * @param instr The raw instruction.
     */
    void MipsCPU::runDecodedInstr(int32 instr)
    {
        int32 opcode = (instr & 0x03fffffff) >> 26;
        int32 internal_opcode = 0, func = 0;

        if (opcode == 0)
        {
            func = instr & 0x0000003F;
            internal_opcode = func << 4;
        }
        else
        {
            internal_opcode = opcode;
        }

#if defined(DEBUG) && defined(TRACE_OPCODES)
        std::cout << "opcode = " << opcode << ", func = " << func << ", internal_opcode = " << internal_opcode << "\n";
#endif

        boost::unordered_map<int32, OpcodeFn>::iterator it = _fnMap.find(internal_opcode);

        if (it != _fnMap.end())
        {
            CALL_MEMBER(this, it->second)(instr);
        }
        else
        {
#ifdef DEBUG
            std::cout << "Unknown internal_opcode: " << internal_opcode << "\n";
#endif
            step();
        }
    }

    void MipsCPU::advance_pc(int32 offset)
    {
        _PC = _nPC;
        _nPC += offset;
    }

    void MipsCPU::op_add(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = _GPR[i.rs] + _GPR[i.rt];
        step();
    }

    void MipsCPU::op_addu(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = (boost::uint32_t)(_GPR[i.rs]) + (boost::uint32_t)(_GPR[i.rt]);
        step();
    }

    void MipsCPU::op_addi(int32 instr)
    {
        IInstruction i(instr);
        _GPR[i.rt] = _GPR[i.rs] + i.immediate;
        step();
    }

    void MipsCPU::op_addiu(int32 instr)
    {
        IInstruction i(instr);
        _GPR[i.rt] = _GPR[i.rs] + i.immediate;
        step();
    }

    void MipsCPU::op_sub(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = _GPR[i.rs] - _GPR[i.rt];
        step();
    }

    void MipsCPU::op_subu(int32 instr)
    {
        RInstruction i(instr);
        _GPR[i.rd] = (boost::uint32_t)(_GPR[i.rs]) - (boost::uint32_t)(_GPR[i.rt]);
        step();
    }

    void MipsCPU::op_mult(int32 instr)
    {
        RInstruction i(instr);
        _LO = ((_GPR[i.rt] * _GPR[i.rs]) << 16) >> 16;
        _HI = (_GPR[i.rt] * _GPR[i.rs]) << 16;
        step();
    }

    void MipsCPU::op_div(int32 instr)
    {
        RInstruction i(instr);
        _LO = _GPR[i.rs] / _GPR[i.rt];
        _HI = _GPR[i.rs] % _GPR[i.rt];
        step();
    }

    void MipsCPU::op_divu(int32 instr)
    {
        RInstruction i(instr);
        _LO = _GPR[i.rs] / _GPR[i.rt];
        _HI = _GPR[i.rs] % _GPR[i.rt];
        step();
    }

    void MipsCPU::op_beq(int32 instr)
    {
        IInstruction i(instr);
        if (_GPR[i.rs] == _GPR[i.rt])
        {
            advance_pc(4 * i.immediate);
        }
        else
        {
            step();
        }
    }

    void MipsCPU::op_bne(int32 instr)
    {
        IInstruction i(instr);
        if (_GPR[i.rs] != _GPR[i.rt])
        {
            advance_pc(4 * i.immediate);
        }
        else
        {
            step();
        }
    }

    void MipsCPU::op_j(int32 instr)
    {
        JInstruction i(instr);
        _PC = _nPC;
        _nPC = (_PC & 0xf0000000) | i.address << 2;
    }

    void MipsCPU::op_jal(int32 instr)
    {
        JInstruction i(instr);
        _GPR[31] = _nPC + 4; // return address is the next instruction from here
        _PC = _nPC;
        _nPC = (_PC & 0xf0000000) | i.address << 2;
    }

    void MipsCPU::op_jr(int32 instr)
    {
        RInstruction i(instr);
        _PC = _nPC;
        _nPC = i.rs;
    }

    void MipsCPU::loadProgram(boost::shared_ptr< std::vector<int32> > program)
    {
        _program = program;
    }

    void MipsCPU::runProgram()
    {
        std::vector<int32>* p = _program.get();

        while (_nPC / 4 - 1 < p->size())
            runDecodedInstr(p->at(_nPC / 4 - 1));
    }

} // tememu
<|endoftext|>


<commit_before>/*
 * Unit tests for the TTDelay Object for Jamoma DSP
 * Copyright © 2011, Nils Peters, Tim Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTDelay.h"

TTErr TTDelay::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;
	int					badSampleCount = 0;
	TTAudioSignalPtr	input = NULL;
	TTAudioSignalPtr	output = NULL;

	// create 1 channel audio signal objects
	TTObjectInstantiate(kTTSym_audiosignal, &input, 1);
	TTObjectInstantiate(kTTSym_audiosignal, &output, 1);
	input->allocWithVectorSize(64);
	output->allocWithVectorSize(64);

	// create an impulse
	input->clear();						// set all samples to zero
	input->mSampleVectors[0][0] = 1.0;	// set the first sample to 1

	// setup the delay
	this->setAttributeValue(TT("delayMaxInSamples"), 64);
	this->setAttributeValue(TT("delayInSamples"), 1);
	this->setAttributeValue(TT("interpolation"), TT("none")),
	this->process(input, output);

	TTFloat64 expectedImpulseResponse[64] = {
		0.0000000000000000e+00,
		1.0,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00
	};

	for (int i=0; i<64; i++) {
		TTBoolean result = TTTestFloatEquivalence(output->mSampleVectors[0][i], expectedImpulseResponse[i]);
		badSampleCount += !result;
		if (result)
			TTTestLog("BAD SAMPLE @ i=%i  ( value=%.10f   expected=%.10f )", i, output->mSampleVectors[0][i], expectedImpulseResponse[i]);
	}

	TTTestAssertion("Produces correct impulse response for a delay of 1 sample",
					badSampleCount == 0,
					testAssertionCount,
					errorCount);
	if (badSampleCount)
		TTTestLog("badSampleCount is %i", badSampleCount);

	TTObjectRelease(&input);
	TTObjectRelease(&output);

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}

<commit_msg>TTDelay: unit test fix<commit_after>/*
 * Unit tests for the TTDelay Object for Jamoma DSP
 * Copyright © 2011, Nils Peters, Tim Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTDelay.h"

TTErr TTDelay::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;
	int					badSampleCount = 0;
	TTAudioSignalPtr	input = NULL;
	TTAudioSignalPtr	output = NULL;

	// create 1 channel audio signal objects
	TTObjectInstantiate(kTTSym_audiosignal, &input, 1);
	TTObjectInstantiate(kTTSym_audiosignal, &output, 1);
	input->allocWithVectorSize(64);
	output->allocWithVectorSize(64);

	// create an impulse
	input->clear();						// set all samples to zero
	input->mSampleVectors[0][0] = 1.0;	// set the first sample to 1

	// setup the delay
	this->setAttributeValue(TT("delayMaxInSamples"), 64);
	this->setAttributeValue(TT("delayInSamples"), 1);
	this->setAttributeValue(TT("interpolation"), TT("none")),
	this->process(input, output);

	TTFloat64 expectedImpulseResponse[64] = {
		0.0000000000000000e+00,
		1.0,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00,
		0.0000000000000000e+00
	};

	for (int i=0; i<64; i++) {
		TTBoolean result = TTTestFloatEquivalence(output->mSampleVectors[0][i], expectedImpulseResponse[i]);
		badSampleCount += !result;
		if (!result)
			TTTestLog("BAD SAMPLE @ i=%i  ( value=%.10f   expected=%.10f )", i, output->mSampleVectors[0][i], expectedImpulseResponse[i]);
	}

	TTTestAssertion("Produces correct impulse response for a delay of 1 sample",
					badSampleCount == 0,
					testAssertionCount,
					errorCount);
	if (badSampleCount)
		TTTestLog("badSampleCount is %i", badSampleCount);

	TTObjectRelease(&input);
	TTObjectRelease(&output);

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}

<|endoftext|>


<commit_before>/**
 * @file   ThreadGroup.hpp
 * @brief  ThreadGroup class prototype.
 * @author zer0
 * @date   2016-05-12
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/lock/RwLock.hpp>

#include <thread>
#include <list>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace thread {

/**
 * ThreadGroup class prototype.
 *
 * @author zer0
 * @date   2016-05-12
 */
class ThreadGroup : public Noncopyable
{
public:
    using ThreadPointer = std::thread*;
    using List = std::list<ThreadPointer>;

private:
    mutable lock::RwLock _lock;
    List _list;

public:
    ThreadGroup() {
        __EMPTY_BLOCK__
    }

    ~ThreadGroup() {
        clear();
    }

public:
    void clear() {
        lock::WriteLockGuard guard(_lock);
        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            delete *itr;
        }
        _list.clear();
    }

// exists thread.
public:
    bool exists(std::thread::id const & id) const {
        lock::ReadLockGuard guard(_lock);
        for (List::const_iterator itr = _list.cbegin(), end = _list.cend(); itr != end; ++itr) {
            if ((*itr)->get_id() == id) {
                return true;
            }
        }
        return false;
    }

    bool exists(std::thread const * thread) const {
        if (thread != nullptr) {
            return exists(thread->get_id());
        }
        return true;
    }

    bool existsThis() const {
        return exists(std::this_thread::get_id());
    }

public:
    template <typename Function>
    std::thread * createThread(Function callback) {
        std::thread * create_thread = new (std::nothrow) std::thread(callback);
        addThread(create_thread);
        return create_thread;
    }

    void addThread(std::thread * thread) {
        if (thread != nullptr && exists(thread) == false) {
            lock::WriteLockGuard guard(_lock);
            _list.push_back(thread);
        }
    }

    void removeThread(std::thread * thread) {
        lock::WriteLockGuard guard(_lock);

        // [WARNING]
        // Don't use std::find.
        // Reason: No matching function for call to std::find (in G++).
        //         'std::find(List::iterator, List::iterator, std::thread * &)'
        // List::iterator itr = std::find(_list.begin(), _list.end(), thread);

        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            if ((*itr) == thread) {
                _list.erase(itr);
                break;
            }
        }
    }

public:
    void joinAll() {
        lock::ReadLockGuard guard(_lock);
        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            if ((*itr)->joinable()) {
                (*itr)->join();
            }
        }
    }

    std::size_t size() const noexcept {
        lock::ReadLockGuard guard(_lock);
        return _list.size();
    }
};

} // namespace thread

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__

<commit_msg>Fix the thread::ThreadGroup::createThread() signature.<commit_after>/**
 * @file   ThreadGroup.hpp
 * @brief  ThreadGroup class prototype.
 * @author zer0
 * @date   2016-05-12
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/lock/RwLock.hpp>

#include <thread>
#include <list>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace thread {

/**
 * ThreadGroup class prototype.
 *
 * @author zer0
 * @date   2016-05-12
 */
class ThreadGroup : public Noncopyable
{
public:
    using ThreadPointer = std::thread*;
    using List = std::list<ThreadPointer>;

private:
    mutable lock::RwLock _lock;
    List _list;

public:
    ThreadGroup() {
        __EMPTY_BLOCK__
    }

    ~ThreadGroup() {
        clear();
    }

public:
    void clear() {
        lock::WriteLockGuard guard(_lock);
        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            delete *itr;
        }
        _list.clear();
    }

// exists thread.
public:
    bool exists(std::thread::id const & id) const {
        lock::ReadLockGuard guard(_lock);
        for (List::const_iterator itr = _list.cbegin(), end = _list.cend(); itr != end; ++itr) {
            if ((*itr)->get_id() == id) {
                return true;
            }
        }
        return false;
    }

    bool exists(std::thread const * thread) const {
        if (thread != nullptr) {
            return exists(thread->get_id());
        }
        return true;
    }

    bool existsThis() const {
        return exists(std::this_thread::get_id());
    }

public:
    template <typename ...Args>
    std::thread * createThread(Args ... args) {
        std::thread * create_thread = new (std::nothrow) std::thread(args...);
        addThread(create_thread);
        return create_thread;
    }

    void addThread(std::thread * thread) {
        if (thread != nullptr && exists(thread) == false) {
            lock::WriteLockGuard guard(_lock);
            _list.push_back(thread);
        }
    }

    void removeThread(std::thread * thread) {
        lock::WriteLockGuard guard(_lock);

        // [WARNING]
        // Don't use std::find.
        // Reason: No matching function for call to std::find (in G++).
        //         'std::find(List::iterator, List::iterator, std::thread * &)'
        // List::iterator itr = std::find(_list.begin(), _list.end(), thread);

        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            if ((*itr) == thread) {
                _list.erase(itr);
                break;
            }
        }
    }

public:
    void joinAll() {
        lock::ReadLockGuard guard(_lock);
        for (List::iterator itr = _list.begin(), end = _list.end(); itr != end; ++itr) {
            if ((*itr)->joinable()) {
                (*itr)->join();
            }
        }
    }

    std::size_t size() const noexcept {
        lock::ReadLockGuard guard(_lock);
        return _list.size();
    }
};

} // namespace thread

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_THREAD_THREADGROUP_HPP__

<|endoftext|>