<commit_before>//===-- GCStrategy.cpp - Garbage collection infrastructure -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements target- and collector-independent garbage collection
// infrastructure.
//
// MachineCodeAnalysis identifies the GC safe points in the machine code. Roots
// are identified in SelectionDAGISel.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GCStrategy.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

  /// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
  /// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
  /// directed by the GCStrategy. It also performs automatic root initialization
  /// and custom intrinsic lowering.
  class LowerIntrinsics : public FunctionPass {
    static bool NeedsDefaultLoweringPass(const GCStrategy &C);
    static bool NeedsCustomLoweringPass(const GCStrategy &C);
    static bool CouldBecomeSafePoint(Instruction *I);
    bool PerformDefaultLowering(Function &F, GCStrategy &Coll);
    static bool InsertRootInitializers(Function &F,
                                       AllocaInst **Roots, unsigned Count);

  public:
    static char ID;

    LowerIntrinsics();
    const char *getPassName() const;
    void getAnalysisUsage(AnalysisUsage &AU) const;

    bool doInitialization(Module &M);
    bool runOnFunction(Function &F);
  };

  /// MachineCodeAnalysis - This is a target-independent pass over the machine
  /// function representation to identify safe points for the garbage collector
  /// in the machine code. It inserts labels at safe points and populates a
  /// GCMetadata record for each function.
  class MachineCodeAnalysis : public MachineFunctionPass {
    const TargetMachine *TM;
    GCFunctionInfo *FI;
    MachineModuleInfo *MMI;
    const TargetInstrInfo *TII;

    void FindSafePoints(MachineFunction &MF);
    void VisitCallPoint(MachineBasicBlock::iterator MI);
    MCSymbol *InsertLabel(MachineBasicBlock &MBB,
                          MachineBasicBlock::iterator MI,
                          DebugLoc DL) const;

    void FindStackOffsets(MachineFunction &MF);

  public:
    static char ID;

    MachineCodeAnalysis();
    const char *getPassName() const;
    void getAnalysisUsage(AnalysisUsage &AU) const;

    bool runOnMachineFunction(MachineFunction &MF);
  };

}

// -----------------------------------------------------------------------------

GCStrategy::GCStrategy() :
  NeededSafePoints(0),
  CustomReadBarriers(false),
  CustomWriteBarriers(false),
  CustomRoots(false),
  InitRoots(true),
  UsesMetadata(false)
{}

GCStrategy::~GCStrategy() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    delete *I;

  Functions.clear();
}

bool GCStrategy::initializeCustomLowering(Module &M) { return false; }

bool GCStrategy::performCustomLowering(Function &F) {
  dbgs() << "gc " << getName() << " must override performCustomLowering.\n";
  llvm_unreachable(0);
  return 0;
}

GCFunctionInfo *GCStrategy::insertFunctionInfo(const Function &F) {
  GCFunctionInfo *FI = new GCFunctionInfo(F, *this);
  Functions.push_back(FI);
  return FI;
}

// -----------------------------------------------------------------------------

FunctionPass *llvm::createGCLoweringPass() {
  return new LowerIntrinsics();
}

char LowerIntrinsics::ID = 0;

LowerIntrinsics::LowerIntrinsics()
  : FunctionPass(&ID) {}

const char *LowerIntrinsics::getPassName() const {
  return "Lower Garbage Collection Instructions";
}

void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
  FunctionPass::getAnalysisUsage(AU);
  AU.addRequired<GCModuleInfo>();
}

/// doInitialization - If this module uses the GC intrinsics, find them now.
bool LowerIntrinsics::doInitialization(Module &M) {
  // FIXME: This is rather antisocial in the context of a JIT since it performs
  //        work against the entire module. But this cannot be done at
  //        runFunction time (initializeCustomLowering likely needs to change
  //        the module).
  GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
  assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (!I->isDeclaration() && I->hasGC())
      MI->getFunctionInfo(*I); // Instantiate the GC strategy.

  bool MadeChange = false;
  for (GCModuleInfo::iterator I = MI->begin(), E = MI->end(); I != E; ++I)
    if (NeedsCustomLoweringPass(**I))
      if ((*I)->initializeCustomLowering(M))
        MadeChange = true;

  return MadeChange;
}

bool LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
                                                          unsigned Count) {
  // Scroll past alloca instructions.
  BasicBlock::iterator IP = F.getEntryBlock().begin();
  while (isa<AllocaInst>(IP)) ++IP;

  // Search for initializers in the initial BB.
  SmallPtrSet<AllocaInst*,16> InitedRoots;
  for (; !CouldBecomeSafePoint(IP); ++IP)
    if (StoreInst *SI = dyn_cast<StoreInst>(IP))
      if (AllocaInst *AI =
          dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
        InitedRoots.insert(AI);

  // Add root initializers.
  bool MadeChange = false;

  for (AllocaInst **I = Roots, **E = Roots + Count; I != E; ++I)
    if (!InitedRoots.count(*I)) {
      new StoreInst(ConstantPointerNull::get(cast<PointerType>(
                      cast<PointerType>((*I)->getType())->getElementType())),
                    *I, IP);
      MadeChange = true;
    }

  return MadeChange;
}

bool LowerIntrinsics::NeedsDefaultLoweringPass(const GCStrategy &C) {
  // Default lowering is necessary only if read or write barriers have a default
  // action. The default for roots is no action.
  return !C.customWriteBarrier()
      || !C.customReadBarrier()
      || C.initializeRoots();
}

bool LowerIntrinsics::NeedsCustomLoweringPass(const GCStrategy &C) {
  // Custom lowering is only necessary if enabled for some action.
  return C.customWriteBarrier()
      || C.customReadBarrier()
      || C.customRoots();
}

/// CouldBecomeSafePoint - Predicate to conservatively determine whether the
/// instruction could introduce a safe point.
bool LowerIntrinsics::CouldBecomeSafePoint(Instruction *I) {
  // The natural definition of instructions which could introduce safe points
  // are:
  //
  //   - call, invoke (AfterCall, BeforeCall)
  //   - phis (Loops)
  //   - invoke, ret, unwind (Exit)
  //
  // However, instructions as seemingly inoccuous as arithmetic can become
  // libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
  // it is necessary to take a conservative approach.

  if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) ||
      isa<StoreInst>(I) || isa<LoadInst>(I))
    return false;

  // llvm.gcroot is safe because it doesn't do anything at runtime.
  if (CallInst *CI = dyn_cast<CallInst>(I))
    if (Function *F = CI->getCalledFunction())
      if (unsigned IID = F->getIntrinsicID())
        if (IID == Intrinsic::gcroot)
          return false;

  return true;
}

/// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
/// Leave gcroot intrinsics; the code generator needs to see those.
bool LowerIntrinsics::runOnFunction(Function &F) {
  // Quick exit for functions that do not use GC.
  if (!F.hasGC())
    return false;

  GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
  GCStrategy &S = FI.getStrategy();

  bool MadeChange = false;

  if (NeedsDefaultLoweringPass(S))
    MadeChange |= PerformDefaultLowering(F, S);

  if (NeedsCustomLoweringPass(S))
    MadeChange |= S.performCustomLowering(F);

  return MadeChange;
}

bool LowerIntrinsics::PerformDefaultLowering(Function &F, GCStrategy &S) {
  bool LowerWr = !S.customWriteBarrier();
  bool LowerRd = !S.customReadBarrier();
  bool InitRoots = S.initializeRoots();

  SmallVector<AllocaInst*,32> Roots;

  bool MadeChange = false;
  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
    for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;) {
      if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(II++)) {
        Function *F = CI->getCalledFunction();
        switch (F->getIntrinsicID()) {
        case Intrinsic::gcwrite:
          if (LowerWr) {
            // Replace a write barrier with a simple store.
            Value *St = new StoreInst(CI->getOperand(1), CI->getOperand(3), CI);
            CI->replaceAllUsesWith(St);
            CI->eraseFromParent();
          }
          break;
        case Intrinsic::gcread:
          if (LowerRd) {
            // Replace a read barrier with a simple load.
            Value *Ld = new LoadInst(CI->getOperand(2), "", CI);
            Ld->takeName(CI);
            CI->replaceAllUsesWith(Ld);
            CI->eraseFromParent();
          }
          break;
        case Intrinsic::gcroot:
          if (InitRoots) {
            // Initialize the GC root, but do not delete the intrinsic. The
            // backend needs the intrinsic to flag the stack slot.
            Roots.push_back(cast<AllocaInst>(
                              CI->getOperand(1)->stripPointerCasts()));
          }
          break;
        default:
          continue;
        }

        MadeChange = true;
      }
    }
  }

  if (Roots.size())
    MadeChange |= InsertRootInitializers(F, Roots.begin(), Roots.size());

  return MadeChange;
}

// -----------------------------------------------------------------------------

FunctionPass *llvm::createGCMachineCodeAnalysisPass() {
  return new MachineCodeAnalysis();
}

char MachineCodeAnalysis::ID = 0;

MachineCodeAnalysis::MachineCodeAnalysis()
  : MachineFunctionPass(&ID) {}

const char *MachineCodeAnalysis::getPassName() const {
  return "Analyze Machine Code For Garbage Collection";
}

void MachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  MachineFunctionPass::getAnalysisUsage(AU);
  AU.setPreservesAll();
  AU.addRequired<MachineModuleInfo>();
  AU.addRequired<GCModuleInfo>();
}

MCSymbol *MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
                                           MachineBasicBlock::iterator MI,
                                           DebugLoc DL) const {
  MCSymbol *Label = MMI->getLabelSym(MMI->NextLabelID());
  BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
  return Label;
}

void MachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
  // Find the return address (next instruction), too, so as to bracket the call
  // instruction.
  MachineBasicBlock::iterator RAI = CI;
  ++RAI;

  if (FI->getStrategy().needsSafePoint(GC::PreCall))
    FI->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI,
                                              CI->getDebugLoc()));

  if (FI->getStrategy().needsSafePoint(GC::PostCall))
    FI->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI,
                                               CI->getDebugLoc()));
}

void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
  for (MachineFunction::iterator BBI = MF.begin(),
                                 BBE = MF.end(); BBI != BBE; ++BBI)
    for (MachineBasicBlock::iterator MI = BBI->begin(),
                                     ME = BBI->end(); MI != ME; ++MI)
      if (MI->getDesc().isCall())
        VisitCallPoint(MI);
}

void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
  const TargetRegisterInfo *TRI = TM->getRegisterInfo();
  assert(TRI && "TargetRegisterInfo not available!");

  for (GCFunctionInfo::roots_iterator RI = FI->roots_begin(),
                                      RE = FI->roots_end(); RI != RE; ++RI)
    RI->StackOffset = TRI->getFrameIndexOffset(MF, RI->Num);
}

bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
  // Quick exit for functions that do not use GC.
  if (!MF.getFunction()->hasGC())
    return false;

  FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(*MF.getFunction());
  if (!FI->getStrategy().needsSafePoints())
    return false;

  TM = &MF.getTarget();
  MMI = &getAnalysis<MachineModuleInfo>();
  TII = TM->getInstrInfo();

  // Find the size of the stack frame.
  FI->setFrameSize(MF.getFrameInfo()->getStackSize());

  // Find all safe points.
  FindSafePoints(MF);

  // Find the stack offsets for all roots.
  FindStackOffsets(MF);

  return false;
}
<commit_msg>Change this code to allocate temporary labels from mccontext, not from MMI.<commit_after>//===-- GCStrategy.cpp - Garbage collection infrastructure -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements target- and collector-independent garbage collection
// infrastructure.
//
// MachineCodeAnalysis identifies the GC safe points in the machine code. Roots
// are identified in SelectionDAGISel.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GCStrategy.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

  /// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
  /// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
  /// directed by the GCStrategy. It also performs automatic root initialization
  /// and custom intrinsic lowering.
  class LowerIntrinsics : public FunctionPass {
    static bool NeedsDefaultLoweringPass(const GCStrategy &C);
    static bool NeedsCustomLoweringPass(const GCStrategy &C);
    static bool CouldBecomeSafePoint(Instruction *I);
    bool PerformDefaultLowering(Function &F, GCStrategy &Coll);
    static bool InsertRootInitializers(Function &F,
                                       AllocaInst **Roots, unsigned Count);

  public:
    static char ID;

    LowerIntrinsics();
    const char *getPassName() const;
    void getAnalysisUsage(AnalysisUsage &AU) const;

    bool doInitialization(Module &M);
    bool runOnFunction(Function &F);
  };

  /// MachineCodeAnalysis - This is a target-independent pass over the machine
  /// function representation to identify safe points for the garbage collector
  /// in the machine code. It inserts labels at safe points and populates a
  /// GCMetadata record for each function.
  class MachineCodeAnalysis : public MachineFunctionPass {
    const TargetMachine *TM;
    GCFunctionInfo *FI;
    MachineModuleInfo *MMI;
    const TargetInstrInfo *TII;

    void FindSafePoints(MachineFunction &MF);
    void VisitCallPoint(MachineBasicBlock::iterator MI);
    MCSymbol *InsertLabel(MachineBasicBlock &MBB,
                          MachineBasicBlock::iterator MI,
                          DebugLoc DL) const;

    void FindStackOffsets(MachineFunction &MF);

  public:
    static char ID;

    MachineCodeAnalysis();
    const char *getPassName() const;
    void getAnalysisUsage(AnalysisUsage &AU) const;

    bool runOnMachineFunction(MachineFunction &MF);
  };

}

// -----------------------------------------------------------------------------

GCStrategy::GCStrategy() :
  NeededSafePoints(0),
  CustomReadBarriers(false),
  CustomWriteBarriers(false),
  CustomRoots(false),
  InitRoots(true),
  UsesMetadata(false)
{}

GCStrategy::~GCStrategy() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    delete *I;

  Functions.clear();
}

bool GCStrategy::initializeCustomLowering(Module &M) { return false; }

bool GCStrategy::performCustomLowering(Function &F) {
  dbgs() << "gc " << getName() << " must override performCustomLowering.\n";
  llvm_unreachable(0);
  return 0;
}

GCFunctionInfo *GCStrategy::insertFunctionInfo(const Function &F) {
  GCFunctionInfo *FI = new GCFunctionInfo(F, *this);
  Functions.push_back(FI);
  return FI;
}

// -----------------------------------------------------------------------------

FunctionPass *llvm::createGCLoweringPass() {
  return new LowerIntrinsics();
}

char LowerIntrinsics::ID = 0;

LowerIntrinsics::LowerIntrinsics()
  : FunctionPass(&ID) {}

const char *LowerIntrinsics::getPassName() const {
  return "Lower Garbage Collection Instructions";
}

void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
  FunctionPass::getAnalysisUsage(AU);
  AU.addRequired<GCModuleInfo>();
}

/// doInitialization - If this module uses the GC intrinsics, find them now.
bool LowerIntrinsics::doInitialization(Module &M) {
  // FIXME: This is rather antisocial in the context of a JIT since it performs
  //        work against the entire module. But this cannot be done at
  //        runFunction time (initializeCustomLowering likely needs to change
  //        the module).
  GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
  assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (!I->isDeclaration() && I->hasGC())
      MI->getFunctionInfo(*I); // Instantiate the GC strategy.

  bool MadeChange = false;
  for (GCModuleInfo::iterator I = MI->begin(), E = MI->end(); I != E; ++I)
    if (NeedsCustomLoweringPass(**I))
      if ((*I)->initializeCustomLowering(M))
        MadeChange = true;

  return MadeChange;
}

bool LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
                                                          unsigned Count) {
  // Scroll past alloca instructions.
  BasicBlock::iterator IP = F.getEntryBlock().begin();
  while (isa<AllocaInst>(IP)) ++IP;

  // Search for initializers in the initial BB.
  SmallPtrSet<AllocaInst*,16> InitedRoots;
  for (; !CouldBecomeSafePoint(IP); ++IP)
    if (StoreInst *SI = dyn_cast<StoreInst>(IP))
      if (AllocaInst *AI =
          dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
        InitedRoots.insert(AI);

  // Add root initializers.
  bool MadeChange = false;

  for (AllocaInst **I = Roots, **E = Roots + Count; I != E; ++I)
    if (!InitedRoots.count(*I)) {
      new StoreInst(ConstantPointerNull::get(cast<PointerType>(
                      cast<PointerType>((*I)->getType())->getElementType())),
                    *I, IP);
      MadeChange = true;
    }

  return MadeChange;
}

bool LowerIntrinsics::NeedsDefaultLoweringPass(const GCStrategy &C) {
  // Default lowering is necessary only if read or write barriers have a default
  // action. The default for roots is no action.
  return !C.customWriteBarrier()
      || !C.customReadBarrier()
      || C.initializeRoots();
}

bool LowerIntrinsics::NeedsCustomLoweringPass(const GCStrategy &C) {
  // Custom lowering is only necessary if enabled for some action.
  return C.customWriteBarrier()
      || C.customReadBarrier()
      || C.customRoots();
}

/// CouldBecomeSafePoint - Predicate to conservatively determine whether the
/// instruction could introduce a safe point.
bool LowerIntrinsics::CouldBecomeSafePoint(Instruction *I) {
  // The natural definition of instructions which could introduce safe points
  // are:
  //
  //   - call, invoke (AfterCall, BeforeCall)
  //   - phis (Loops)
  //   - invoke, ret, unwind (Exit)
  //
  // However, instructions as seemingly inoccuous as arithmetic can become
  // libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
  // it is necessary to take a conservative approach.

  if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) ||
      isa<StoreInst>(I) || isa<LoadInst>(I))
    return false;

  // llvm.gcroot is safe because it doesn't do anything at runtime.
  if (CallInst *CI = dyn_cast<CallInst>(I))
    if (Function *F = CI->getCalledFunction())
      if (unsigned IID = F->getIntrinsicID())
        if (IID == Intrinsic::gcroot)
          return false;

  return true;
}

/// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
/// Leave gcroot intrinsics; the code generator needs to see those.
bool LowerIntrinsics::runOnFunction(Function &F) {
  // Quick exit for functions that do not use GC.
  if (!F.hasGC())
    return false;

  GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
  GCStrategy &S = FI.getStrategy();

  bool MadeChange = false;

  if (NeedsDefaultLoweringPass(S))
    MadeChange |= PerformDefaultLowering(F, S);

  if (NeedsCustomLoweringPass(S))
    MadeChange |= S.performCustomLowering(F);

  return MadeChange;
}

bool LowerIntrinsics::PerformDefaultLowering(Function &F, GCStrategy &S) {
  bool LowerWr = !S.customWriteBarrier();
  bool LowerRd = !S.customReadBarrier();
  bool InitRoots = S.initializeRoots();

  SmallVector<AllocaInst*,32> Roots;

  bool MadeChange = false;
  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
    for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;) {
      if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(II++)) {
        Function *F = CI->getCalledFunction();
        switch (F->getIntrinsicID()) {
        case Intrinsic::gcwrite:
          if (LowerWr) {
            // Replace a write barrier with a simple store.
            Value *St = new StoreInst(CI->getOperand(1), CI->getOperand(3), CI);
            CI->replaceAllUsesWith(St);
            CI->eraseFromParent();
          }
          break;
        case Intrinsic::gcread:
          if (LowerRd) {
            // Replace a read barrier with a simple load.
            Value *Ld = new LoadInst(CI->getOperand(2), "", CI);
            Ld->takeName(CI);
            CI->replaceAllUsesWith(Ld);
            CI->eraseFromParent();
          }
          break;
        case Intrinsic::gcroot:
          if (InitRoots) {
            // Initialize the GC root, but do not delete the intrinsic. The
            // backend needs the intrinsic to flag the stack slot.
            Roots.push_back(cast<AllocaInst>(
                              CI->getOperand(1)->stripPointerCasts()));
          }
          break;
        default:
          continue;
        }

        MadeChange = true;
      }
    }
  }

  if (Roots.size())
    MadeChange |= InsertRootInitializers(F, Roots.begin(), Roots.size());

  return MadeChange;
}

// -----------------------------------------------------------------------------

FunctionPass *llvm::createGCMachineCodeAnalysisPass() {
  return new MachineCodeAnalysis();
}

char MachineCodeAnalysis::ID = 0;

MachineCodeAnalysis::MachineCodeAnalysis()
  : MachineFunctionPass(&ID) {}

const char *MachineCodeAnalysis::getPassName() const {
  return "Analyze Machine Code For Garbage Collection";
}

void MachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  MachineFunctionPass::getAnalysisUsage(AU);
  AU.setPreservesAll();
  AU.addRequired<MachineModuleInfo>();
  AU.addRequired<GCModuleInfo>();
}

MCSymbol *MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
                                           MachineBasicBlock::iterator MI,
                                           DebugLoc DL) const {
  MCSymbol *Label = MBB.getParent()->getContext().GetOrCreateTemporarySymbol();
  BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
  return Label;
}

void MachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
  // Find the return address (next instruction), too, so as to bracket the call
  // instruction.
  MachineBasicBlock::iterator RAI = CI;
  ++RAI;

  if (FI->getStrategy().needsSafePoint(GC::PreCall))
    FI->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI,
                                              CI->getDebugLoc()));

  if (FI->getStrategy().needsSafePoint(GC::PostCall))
    FI->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI,
                                               CI->getDebugLoc()));
}

void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
  for (MachineFunction::iterator BBI = MF.begin(),
                                 BBE = MF.end(); BBI != BBE; ++BBI)
    for (MachineBasicBlock::iterator MI = BBI->begin(),
                                     ME = BBI->end(); MI != ME; ++MI)
      if (MI->getDesc().isCall())
        VisitCallPoint(MI);
}

void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
  const TargetRegisterInfo *TRI = TM->getRegisterInfo();
  assert(TRI && "TargetRegisterInfo not available!");

  for (GCFunctionInfo::roots_iterator RI = FI->roots_begin(),
                                      RE = FI->roots_end(); RI != RE; ++RI)
    RI->StackOffset = TRI->getFrameIndexOffset(MF, RI->Num);
}

bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
  // Quick exit for functions that do not use GC.
  if (!MF.getFunction()->hasGC())
    return false;

  FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(*MF.getFunction());
  if (!FI->getStrategy().needsSafePoints())
    return false;

  TM = &MF.getTarget();
  MMI = &getAnalysis<MachineModuleInfo>();
  TII = TM->getInstrInfo();

  // Find the size of the stack frame.
  FI->setFrameSize(MF.getFrameInfo()->getStackSize());

  // Find all safe points.
  FindSafePoints(MF);

  // Find the stack offsets for all roots.
  FindStackOffsets(MF);

  return false;
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <gflags/gflags.h>

#include "xenia/app/emulator_window.h"
#include "xenia/base/debugging.h"
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/base/profiling.h"
#include "xenia/base/threading.h"
#include "xenia/debug/ui/debug_window.h"
#include "xenia/emulator.h"
#include "xenia/ui/file_picker.h"
#include "xenia/vfs/devices/host_path_device.h"

// Available audio systems:
#include "xenia/apu/nop/nop_audio_system.h"
#if XE_PLATFORM_WIN32
#include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#endif  // XE_PLATFORM_WIN32

// Available graphics systems:
#include "xenia/gpu/null/null_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"

// Available input drivers:
#include "xenia/hid/nop/nop_hid.h"
#if XE_PLATFORM_WIN32
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h"
#endif  // XE_PLATFORM_WIN32

DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");

DEFINE_string(target, "", "Specifies the target .xex or .iso to execute.");
DEFINE_bool(fullscreen, false, "Toggles fullscreen");

DEFINE_string(content_root, "", "Root path for content (save/etc) storage.");

DEFINE_bool(mount_scratch, false, "Enable scratch mount");
DEFINE_bool(mount_cache, false, "Enable cache mount");

namespace xe {
namespace app {

std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
  if (FLAGS_apu.compare("nop") == 0) {
    return apu::nop::NopAudioSystem::Create(processor);
#if XE_PLATFORM_WIN32
  } else if (FLAGS_apu.compare("xaudio2") == 0) {
    return apu::xaudio2::XAudio2AudioSystem::Create(processor);
#endif  // XE_PLATFORM_WIN32
  } else {
    // Create best available.
    std::unique_ptr<apu::AudioSystem> best;

#if XE_PLATFORM_WIN32
    best = apu::xaudio2::XAudio2AudioSystem::Create(processor);
    if (best) {
      return best;
    }
#endif  // XE_PLATFORM_WIN32

    // Fallback to nop.
    return apu::nop::NopAudioSystem::Create(processor);
  }
}

std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
  if (FLAGS_gpu.compare("vulkan") == 0) {
    return std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::vulkan::VulkanGraphicsSystem());
  } else if (FLAGS_gpu.compare("null") == 0) {
    return std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::null::NullGraphicsSystem());
  } else {
    // Create best available.
    std::unique_ptr<gpu::GraphicsSystem> best;

    best = std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::vulkan::VulkanGraphicsSystem());
    if (best) {
      return best;
    }

    // Nothing!
    return nullptr;
  }
}

std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
    ui::Window* window) {
  std::vector<std::unique_ptr<hid::InputDriver>> drivers;
  if (FLAGS_hid.compare("nop") == 0) {
    drivers.emplace_back(xe::hid::nop::Create(window));
#if XE_PLATFORM_WIN32
  } else if (FLAGS_hid.compare("winkey") == 0) {
    drivers.emplace_back(xe::hid::winkey::Create(window));
  } else if (FLAGS_hid.compare("xinput") == 0) {
    drivers.emplace_back(xe::hid::xinput::Create(window));
#endif  // XE_PLATFORM_WIN32
  } else {
#if XE_PLATFORM_WIN32
    auto xinput_driver = xe::hid::xinput::Create(window);
    if (xinput_driver) {
      drivers.emplace_back(std::move(xinput_driver));
    }
    auto winkey_driver = xe::hid::winkey::Create(window);
    if (winkey_driver) {
      drivers.emplace_back(std::move(winkey_driver));
    }
#endif  // XE_PLATFORM_WIN32
  }
  for (auto it = drivers.begin(); it != drivers.end();) {
    if (XFAILED((*it)->Setup())) {
      it = drivers.erase(it);
    } else {
      ++it;
    }
  }
  if (drivers.empty()) {
    // Fallback to nop if none created.
    drivers.emplace_back(xe::hid::nop::Create(window));
  }
  return drivers;
}

int xenia_main(const std::vector<std::wstring>& args) {
  Profiler::Initialize();
  Profiler::ThreadEnter("main");

  // Figure out where content should go.
  std::wstring content_root;
  if (!FLAGS_content_root.empty()) {
    content_root = xe::to_wstring(FLAGS_content_root);
  } else {
    auto base_path = xe::filesystem::GetExecutableFolder();
    base_path = xe::to_absolute_path(base_path);

    auto portable_path = xe::join_paths(base_path, L"portable.txt");
    if (xe::filesystem::PathExists(portable_path)) {
      content_root = xe::join_paths(base_path, L"content");
    } else {
      content_root = xe::filesystem::GetUserFolder();
#if defined(XE_PLATFORM_WIN32)
      content_root = xe::join_paths(content_root, L"Xenia");
#elif defined(XE_PLATFORM_LINUX)
      content_root = xe::join_paths(content_root, L".xenia");
#else
#warning Unhandled platform for content root.
      content_root = xe::join_paths(content_root, L"Xenia");
#endif
      content_root = xe::join_paths(content_root, L"content");
    }
  }
  content_root = xe::to_absolute_path(content_root);

  // Create the emulator but don't initialize so we can setup the window.
  auto emulator = std::make_unique<Emulator>(L"", content_root);

  // Main emulator display window.
  auto emulator_window = EmulatorWindow::Create(emulator.get());

  // Setup and initialize all subsystems. If we can't do something
  // (unsupported system, memory issues, etc) this will fail early.
  X_STATUS result =
      emulator->Setup(emulator_window->window(), CreateAudioSystem,
                      CreateGraphicsSystem, CreateInputDrivers);
  if (XFAILED(result)) {
    XELOGE("Failed to setup emulator: %.8X", result);
    return 1;
  }

  if (FLAGS_mount_scratch) {
    auto scratch_device = std::make_unique<xe::vfs::HostPathDevice>(
        "\\SCRATCH", L"scratch", false);
    if (!scratch_device->Initialize()) {
      XELOGE("Unable to scan scratch path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(scratch_device))) {
        XELOGE("Unable to register scratch path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("scratch:", "\\SCRATCH");
      }
    }
  }

  if (FLAGS_mount_cache) {
    auto cache0_device =
        std::make_unique<xe::vfs::HostPathDevice>("\\CACHE0", L"cache0", false);
    if (!cache0_device->Initialize()) {
      XELOGE("Unable to scan cache0 path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(cache0_device))) {
        XELOGE("Unable to register cache0 path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("cache0:", "\\CACHE0");
      }
    }

    auto cache1_device =
        std::make_unique<xe::vfs::HostPathDevice>("\\CACHE1", L"cache1", false);
    if (!cache1_device->Initialize()) {
      XELOGE("Unable to scan cache1 path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(cache1_device))) {
        XELOGE("Unable to register cache1 path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("cache1:", "\\CACHE1");
      }
    }
  }

  // Set a debug handler.
  // This will respond to debugging requests so we can open the debug UI.
  std::unique_ptr<xe::debug::ui::DebugWindow> debug_window;
  if (FLAGS_debug) {
    emulator->processor()->set_debug_listener_request_handler(
        [&](xe::cpu::Processor* processor) {
          if (debug_window) {
            return debug_window.get();
          }
          emulator_window->loop()->PostSynchronous([&]() {
            debug_window = xe::debug::ui::DebugWindow::Create(
                emulator.get(), emulator_window->loop());
            debug_window->window()->on_closed.AddListener(
                [&](xe::ui::UIEvent* e) {
                  emulator->processor()->set_debug_listener(nullptr);
                  emulator_window->loop()->Post(
                      [&]() { debug_window.reset(); });
                });
          });
          return debug_window.get();
        });
  }

  auto evt = xe::threading::Event::CreateAutoResetEvent(false);
  emulator->on_launch.AddListener([&]() {
    emulator_window->UpdateTitle();
    evt->Set();
  });

  emulator_window->window()->on_closing.AddListener([&](ui::UIEvent* e) {
    // This needs to shut down before the graphics context.
    Profiler::Shutdown();
  });

  bool exiting = false;
  emulator_window->loop()->on_quit.AddListener([&](ui::UIEvent* e) {
    exiting = true;
    evt->Set();

    // TODO(DrChat): Remove this code and do a proper exit.
    XELOGI("Cheap-skate exit!");
    exit(0);
  });

  // Enable the main menu now that the emulator is properly loaded
  emulator_window->window()->EnableMainMenu();

  // Grab path from the flag or unnamed argument.
  std::wstring path;
  if (!FLAGS_target.empty() || args.size() >= 2) {
    if (!FLAGS_target.empty()) {
      // Passed as a named argument.
      // TODO(benvanik): find something better than gflags that supports
      // unicode.
      path = xe::to_wstring(FLAGS_target);
    } else {
      // Passed as an unnamed argument.
      path = args[1];
    }
  }

  // Toggles fullscreen
  if (FLAGS_fullscreen) emulator_window->ToggleFullscreen();

  if (!path.empty()) {
    // Normalize the path and make absolute.
    std::wstring abs_path = xe::to_absolute_path(path);
    result = emulator->LaunchPath(abs_path);
    if (XFAILED(result)) {
      xe::FatalError("Failed to launch target: %.8X", result);
      emulator.reset();
      emulator_window.reset();
      return 1;
    }
  }

  // Now, we're going to use the main thread to drive events related to
  // emulation.
  while (!exiting) {
    xe::threading::Wait(evt.get(), false);

    while (true) {
      emulator->WaitUntilExit();
      if (emulator->TitleRequested()) {
        emulator->LaunchNextTitle();
      } else {
        break;
      }
    }
  }

  debug_window.reset();
  emulator.reset();

  Profiler::Dump();
  Profiler::Shutdown();
  emulator_window.reset();
  return 0;
}

}  // namespace app
}  // namespace xe

DEFINE_ENTRY_POINT(L"xenia", L"xenia some.xex", xe::app::xenia_main);
<commit_msg>[App] Log content root.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <gflags/gflags.h>

#include "xenia/app/emulator_window.h"
#include "xenia/base/debugging.h"
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/base/profiling.h"
#include "xenia/base/threading.h"
#include "xenia/debug/ui/debug_window.h"
#include "xenia/emulator.h"
#include "xenia/ui/file_picker.h"
#include "xenia/vfs/devices/host_path_device.h"

// Available audio systems:
#include "xenia/apu/nop/nop_audio_system.h"
#if XE_PLATFORM_WIN32
#include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#endif  // XE_PLATFORM_WIN32

// Available graphics systems:
#include "xenia/gpu/null/null_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"

// Available input drivers:
#include "xenia/hid/nop/nop_hid.h"
#if XE_PLATFORM_WIN32
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h"
#endif  // XE_PLATFORM_WIN32

DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");

DEFINE_string(target, "", "Specifies the target .xex or .iso to execute.");
DEFINE_bool(fullscreen, false, "Toggles fullscreen");

DEFINE_string(content_root, "", "Root path for content (save/etc) storage.");

DEFINE_bool(mount_scratch, false, "Enable scratch mount");
DEFINE_bool(mount_cache, false, "Enable cache mount");

namespace xe {
namespace app {

std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
  if (FLAGS_apu.compare("nop") == 0) {
    return apu::nop::NopAudioSystem::Create(processor);
#if XE_PLATFORM_WIN32
  } else if (FLAGS_apu.compare("xaudio2") == 0) {
    return apu::xaudio2::XAudio2AudioSystem::Create(processor);
#endif  // XE_PLATFORM_WIN32
  } else {
    // Create best available.
    std::unique_ptr<apu::AudioSystem> best;

#if XE_PLATFORM_WIN32
    best = apu::xaudio2::XAudio2AudioSystem::Create(processor);
    if (best) {
      return best;
    }
#endif  // XE_PLATFORM_WIN32

    // Fallback to nop.
    return apu::nop::NopAudioSystem::Create(processor);
  }
}

std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
  if (FLAGS_gpu.compare("vulkan") == 0) {
    return std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::vulkan::VulkanGraphicsSystem());
  } else if (FLAGS_gpu.compare("null") == 0) {
    return std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::null::NullGraphicsSystem());
  } else {
    // Create best available.
    std::unique_ptr<gpu::GraphicsSystem> best;

    best = std::unique_ptr<gpu::GraphicsSystem>(
        new xe::gpu::vulkan::VulkanGraphicsSystem());
    if (best) {
      return best;
    }

    // Nothing!
    return nullptr;
  }
}

std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
    ui::Window* window) {
  std::vector<std::unique_ptr<hid::InputDriver>> drivers;
  if (FLAGS_hid.compare("nop") == 0) {
    drivers.emplace_back(xe::hid::nop::Create(window));
#if XE_PLATFORM_WIN32
  } else if (FLAGS_hid.compare("winkey") == 0) {
    drivers.emplace_back(xe::hid::winkey::Create(window));
  } else if (FLAGS_hid.compare("xinput") == 0) {
    drivers.emplace_back(xe::hid::xinput::Create(window));
#endif  // XE_PLATFORM_WIN32
  } else {
#if XE_PLATFORM_WIN32
    auto xinput_driver = xe::hid::xinput::Create(window);
    if (xinput_driver) {
      drivers.emplace_back(std::move(xinput_driver));
    }
    auto winkey_driver = xe::hid::winkey::Create(window);
    if (winkey_driver) {
      drivers.emplace_back(std::move(winkey_driver));
    }
#endif  // XE_PLATFORM_WIN32
  }
  for (auto it = drivers.begin(); it != drivers.end();) {
    if (XFAILED((*it)->Setup())) {
      it = drivers.erase(it);
    } else {
      ++it;
    }
  }
  if (drivers.empty()) {
    // Fallback to nop if none created.
    drivers.emplace_back(xe::hid::nop::Create(window));
  }
  return drivers;
}

int xenia_main(const std::vector<std::wstring>& args) {
  Profiler::Initialize();
  Profiler::ThreadEnter("main");

  // Figure out where content should go.
  std::wstring content_root;
  if (!FLAGS_content_root.empty()) {
    content_root = xe::to_wstring(FLAGS_content_root);
  } else {
    auto base_path = xe::filesystem::GetExecutableFolder();
    base_path = xe::to_absolute_path(base_path);

    auto portable_path = xe::join_paths(base_path, L"portable.txt");
    if (xe::filesystem::PathExists(portable_path)) {
      content_root = xe::join_paths(base_path, L"content");
    } else {
      content_root = xe::filesystem::GetUserFolder();
#if defined(XE_PLATFORM_WIN32)
      content_root = xe::join_paths(content_root, L"Xenia");
#elif defined(XE_PLATFORM_LINUX)
      content_root = xe::join_paths(content_root, L".xenia");
#else
#warning Unhandled platform for content root.
      content_root = xe::join_paths(content_root, L"Xenia");
#endif
      content_root = xe::join_paths(content_root, L"content");
    }
  }
  content_root = xe::to_absolute_path(content_root);
  XELOGI("Content root: %S", content_root.c_str());

  // Create the emulator but don't initialize so we can setup the window.
  auto emulator = std::make_unique<Emulator>(L"", content_root);

  // Main emulator display window.
  auto emulator_window = EmulatorWindow::Create(emulator.get());

  // Setup and initialize all subsystems. If we can't do something
  // (unsupported system, memory issues, etc) this will fail early.
  X_STATUS result =
      emulator->Setup(emulator_window->window(), CreateAudioSystem,
                      CreateGraphicsSystem, CreateInputDrivers);
  if (XFAILED(result)) {
    XELOGE("Failed to setup emulator: %.8X", result);
    return 1;
  }

  if (FLAGS_mount_scratch) {
    auto scratch_device = std::make_unique<xe::vfs::HostPathDevice>(
        "\\SCRATCH", L"scratch", false);
    if (!scratch_device->Initialize()) {
      XELOGE("Unable to scan scratch path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(scratch_device))) {
        XELOGE("Unable to register scratch path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("scratch:", "\\SCRATCH");
      }
    }
  }

  if (FLAGS_mount_cache) {
    auto cache0_device =
        std::make_unique<xe::vfs::HostPathDevice>("\\CACHE0", L"cache0", false);
    if (!cache0_device->Initialize()) {
      XELOGE("Unable to scan cache0 path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(cache0_device))) {
        XELOGE("Unable to register cache0 path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("cache0:", "\\CACHE0");
      }
    }

    auto cache1_device =
        std::make_unique<xe::vfs::HostPathDevice>("\\CACHE1", L"cache1", false);
    if (!cache1_device->Initialize()) {
      XELOGE("Unable to scan cache1 path");
    } else {
      if (!emulator->file_system()->RegisterDevice(std::move(cache1_device))) {
        XELOGE("Unable to register cache1 path");
      } else {
        emulator->file_system()->RegisterSymbolicLink("cache1:", "\\CACHE1");
      }
    }
  }

  // Set a debug handler.
  // This will respond to debugging requests so we can open the debug UI.
  std::unique_ptr<xe::debug::ui::DebugWindow> debug_window;
  if (FLAGS_debug) {
    emulator->processor()->set_debug_listener_request_handler(
        [&](xe::cpu::Processor* processor) {
          if (debug_window) {
            return debug_window.get();
          }
          emulator_window->loop()->PostSynchronous([&]() {
            debug_window = xe::debug::ui::DebugWindow::Create(
                emulator.get(), emulator_window->loop());
            debug_window->window()->on_closed.AddListener(
                [&](xe::ui::UIEvent* e) {
                  emulator->processor()->set_debug_listener(nullptr);
                  emulator_window->loop()->Post(
                      [&]() { debug_window.reset(); });
                });
          });
          return debug_window.get();
        });
  }

  auto evt = xe::threading::Event::CreateAutoResetEvent(false);
  emulator->on_launch.AddListener([&]() {
    emulator_window->UpdateTitle();
    evt->Set();
  });

  emulator_window->window()->on_closing.AddListener([&](ui::UIEvent* e) {
    // This needs to shut down before the graphics context.
    Profiler::Shutdown();
  });

  bool exiting = false;
  emulator_window->loop()->on_quit.AddListener([&](ui::UIEvent* e) {
    exiting = true;
    evt->Set();

    // TODO(DrChat): Remove this code and do a proper exit.
    XELOGI("Cheap-skate exit!");
    exit(0);
  });

  // Enable the main menu now that the emulator is properly loaded
  emulator_window->window()->EnableMainMenu();

  // Grab path from the flag or unnamed argument.
  std::wstring path;
  if (!FLAGS_target.empty() || args.size() >= 2) {
    if (!FLAGS_target.empty()) {
      // Passed as a named argument.
      // TODO(benvanik): find something better than gflags that supports
      // unicode.
      path = xe::to_wstring(FLAGS_target);
    } else {
      // Passed as an unnamed argument.
      path = args[1];
    }
  }

  // Toggles fullscreen
  if (FLAGS_fullscreen) emulator_window->ToggleFullscreen();

  if (!path.empty()) {
    // Normalize the path and make absolute.
    std::wstring abs_path = xe::to_absolute_path(path);
    result = emulator->LaunchPath(abs_path);
    if (XFAILED(result)) {
      xe::FatalError("Failed to launch target: %.8X", result);
      emulator.reset();
      emulator_window.reset();
      return 1;
    }
  }

  // Now, we're going to use the main thread to drive events related to
  // emulation.
  while (!exiting) {
    xe::threading::Wait(evt.get(), false);

    while (true) {
      emulator->WaitUntilExit();
      if (emulator->TitleRequested()) {
        emulator->LaunchNextTitle();
      } else {
        break;
      }
    }
  }

  debug_window.reset();
  emulator.reset();

  Profiler::Dump();
  Profiler::Shutdown();
  emulator_window.reset();
  return 0;
}

}  // namespace app
}  // namespace xe

DEFINE_ENTRY_POINT(L"xenia", L"xenia some.xex", xe::app::xenia_main);
<|endoftext|>


<commit_before>/***********************************************************************
	filename: 	CEGUIDevILImageCodec.cpp
	created:	07/06/2006
	author:		Olivier Delannoy

	purpose:	This codec provide DevIL based image loading
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUIDevILImageCodec.h"
#include <IL/il.h>
#include <IL/ilu.h>

// Start of CEGUI namespace section
namespace CEGUI
{
DevILImageCodec::DevILImageCodec()
    : ImageCodec("DevILImageCodec - Official DevIL based image codec")
{
    // init DevIL libs we use
    ilInit();
    iluInit();
}

DevILImageCodec::~DevILImageCodec()
{

}

Texture* DevILImageCodec::load(const RawDataContainer& data, Texture* result)
{
    ilPushAttrib(IL_ORIGIN_SET);
    ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
    ilEnable(IL_ORIGIN_SET);

    ILuint imgName;
    ilGenImages(1, &imgName);
    ilBindImage(imgName);

    if (ilLoadL(IL_TYPE_UNKNOWN, (ILvoid*)data.getDataPtr(), data.getSize()) != IL_FALSE)
    {
        // get details about size of loaded image
        ILinfo imgInfo;
        iluGetImageInfo(&imgInfo);
        // set dimensions of texture
        size_t width = imgInfo.Width;
        size_t height = imgInfo.Height;
        // allocate temp buffer to receive image data
        uchar* tmpBuff = new uchar[width * height * 4];
        // get image data in required format
        ilCopyPixels(0, 0, 0, width, height, 1, IL_RGBA, IL_UNSIGNED_BYTE, (ILvoid*)tmpBuff);
        result->loadFromMemory(tmpBuff, width, height);
        // delete DevIL image
        ilDeleteImages(1, &imgName);
        return result;
    }
	// failed to load image properly.
	else
	{
		// delete DevIL image
		ilDeleteImages(1, &imgName);
        return 0;
    }
}

} // End of CEGUI namespace section

<commit_msg>oups only applied half the devil fix<commit_after>/***********************************************************************
	filename: 	CEGUIDevILImageCodec.cpp
	created:	07/06/2006
	author:		Olivier Delannoy

	purpose:	This codec provide DevIL based image loading
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUIDevILImageCodec.h"
#include <IL/il.h>
#include <IL/ilu.h>

// Start of CEGUI namespace section
namespace CEGUI
{
DevILImageCodec::DevILImageCodec()
    : ImageCodec("DevILImageCodec - Official DevIL based image codec")
{
    // init DevIL libs we use
    ilInit();
    iluInit();
}

DevILImageCodec::~DevILImageCodec()
{

}

Texture* DevILImageCodec::load(const RawDataContainer& data, Texture* result)
{
    ilPushAttrib(IL_ORIGIN_SET);
    ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
    ilEnable(IL_ORIGIN_SET);

    ILuint imgName;
    ilGenImages(1, &imgName);
    ilBindImage(imgName);

    if (ilLoadL(IL_TYPE_UNKNOWN, (ILvoid*)data.getDataPtr(), data.getSize()) != IL_FALSE)
    {
        // get details about size of loaded image
        ILinfo imgInfo;
        iluGetImageInfo(&imgInfo);
        // set dimensions of texture
        size_t width = imgInfo.Width;
        size_t height = imgInfo.Height;
        // allocate temp buffer to receive image data
        uchar* tmpBuff = new uchar[width * height * 4];
        // get image data in required format
        ilCopyPixels(0, 0, 0, width, height, 1, IL_RGBA, IL_UNSIGNED_BYTE, (ILvoid*)tmpBuff);
        result->loadFromMemory(tmpBuff, width, height);
        // delete DevIL image
        ilDeleteImages(1, &imgName);
        ilPopAttrib();
        return result;
    }
	// failed to load image properly.
	else
	{
		// delete DevIL image
		ilDeleteImages(1, &imgName);
		ilPopAttrib();
        return 0;
    }
}

} // End of CEGUI namespace section

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkProcessObject.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkProcessObject.h"

#include "vtkObjectFactory.h"
#include "vtkOldStyleCallbackCommand.h"
#include "vtkDataObject.h"

vtkCxxRevisionMacro(vtkProcessObject, "1.29");

// Instantiate object with no start, end, or progress methods.
vtkProcessObject::vtkProcessObject()
{
  this->StartTag = 0;
  this->ProgressTag = 0;
  this->EndTag = 0;
  this->AbortExecute = 0;
  this->Progress = 0.0;
  this->ProgressText = NULL;
  this->NumberOfInputs = 0;
  this->NumberOfRequiredInputs = 0;
  this->Inputs = NULL;
  this->SortedInputs = NULL;
  this->SortedInputs2 = NULL;
}

// Destructor for the vtkProcessObject class
vtkProcessObject::~vtkProcessObject()
{
  int idx;

  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx])
      {
      this->Inputs[idx]->UnRegister(this);
      this->Inputs[idx] = NULL;
      this->SortedInputs[idx] = NULL;
      this->SortedInputs2[idx] = NULL;
      }
    }
  if (this->Inputs)
    {
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    delete [] this->SortedInputs;
    this->SortedInputs = NULL;
    delete [] this->SortedInputs2;
    this->SortedInputs2 = NULL;
    }
  delete [] this->ProgressText;
  this->ProgressText = NULL;
}

typedef vtkDataObject *vtkDataObjectPointer;
//----------------------------------------------------------------------------
// Called by constructor to set up input array.
void vtkProcessObject::SetNumberOfInputs(int num)
{
  int idx;
  vtkDataObjectPointer *inputs;

  // in case nothing has changed.
  if (num == this->NumberOfInputs)
    {
    return;
    }

  // Allocate new arrays.
  inputs = new vtkDataObjectPointer[num];

  // Initialize with NULLs.
  for (idx = 0; idx < num; ++idx)
    {
    inputs[idx] = NULL;
    }

  // Copy old inputs
  for (idx = 0; idx < num && idx < this->NumberOfInputs; ++idx)
    {
    inputs[idx] = this->Inputs[idx];
    }

  // delete the previous arrays
  if (this->Inputs)
    {
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    delete [] this->SortedInputs;
    this->SortedInputs = NULL;
    delete [] this->SortedInputs2;
    this->SortedInputs2 = NULL;
    }

  // Set the new arrays
  this->Inputs = inputs;
  this->SortedInputs = new vtkDataObjectPointer[num];
  this->SortedInputs2 = new vtkDataObjectPointer[num];

  this->NumberOfInputs = num;
  this->Modified();
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::AddInput(vtkDataObject *input)
{
  int idx;

  if (input)
    {
    input->AddConsumer(this);
    input->Register(this);
    }
  this->Modified();

  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == NULL)
      {
      this->Inputs[idx] = input;
      return;
      }
    }

  this->SetNumberOfInputs(this->NumberOfInputs + 1);
  this->Inputs[this->NumberOfInputs - 1] = input;
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::RemoveInput(vtkDataObject *input)
{
  int idx, loc;

  if (!input)
    {
    return;
    }

  // find the input in the list of inputs
  loc = -1;
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == input)
      {
      loc = idx;
      }
    }
  if (loc == -1)
    {
    vtkDebugMacro("tried to remove an input that was not in the list");
    return;
    }

  this->Inputs[loc]->RemoveConsumer(this);
  this->Inputs[loc]->UnRegister(this);
  this->Inputs[loc] = NULL;

  // if that was the last input, then shrink the list
  if (loc == this->NumberOfInputs - 1)
    {
    this->SetNumberOfInputs(this->NumberOfInputs - 1);
    }

  this->Modified();
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::SqueezeInputArray()
{
  int idx, loc;

  // move NULL entries to the end
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == NULL)
      {
      for (loc = idx+1; loc < this->NumberOfInputs; loc++)
        {
        this->Inputs[loc-1] = this->Inputs[loc];
        }
      this->Inputs[this->NumberOfInputs -1] = NULL;
      }
    }

  // adjust the size of the array
  loc = -1;
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (loc == -1 && this->Inputs[idx] == NULL)
      {
      loc = idx;
      }
    }
  if (loc > 0)
    {
    this->SetNumberOfInputs(loc);
    }
}

//----------------------------------------------------------------------------
// Set an Input of this filter.
void vtkProcessObject::SetNthInput(int idx, vtkDataObject *input)
{
  if (idx < 0)
    {
    vtkErrorMacro(<< "SetNthInput: " << idx << ", cannot set input. ");
    return;
    }
  // Expand array if necessary.
  if (idx >= this->NumberOfInputs)
    {
    this->SetNumberOfInputs(idx + 1);
    }

  // does this change anything?
  if (input == this->Inputs[idx])
    {
    return;
    }

  if (this->Inputs[idx])
    {
    this->Inputs[idx]->RemoveConsumer(this);
    this->Inputs[idx]->UnRegister(this);
    this->Inputs[idx] = NULL;
    }

  if (input)
    {
    input->AddConsumer(this);
    input->Register(this);
    }

  this->Inputs[idx] = input;
  this->Modified();
}

// Update the progress of the process object. If a ProgressMethod exists,
// executes it. Then set the Progress ivar to amount. The parameter amount
// should range between (0,1).
void vtkProcessObject::UpdateProgress(float amount)
{
  this->Progress = amount;
  this->InvokeEvent(vtkCommand::ProgressEvent,(void *)&amount);
}

// Specify function to be called before object executes.
void vtkProcessObject::SetStartMethod(void (*f)(void *), void *arg)
{
  if ( this->StartTag )
    {
    this->RemoveObserver(this->StartTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->StartTag = this->AddObserver(vtkCommand::StartEvent,cbc);
    cbc->Delete();
    }
}

// Specify function to be called to show progress of filter
void vtkProcessObject::SetProgressMethod(void (*f)(void *), void *arg)
{
  if ( this->ProgressTag )
    {
    this->RemoveObserver(this->ProgressTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->ProgressTag = this->AddObserver(vtkCommand::ProgressEvent,cbc);
    cbc->Delete();
    }
}

// Specify function to be called after object executes.
void vtkProcessObject::SetEndMethod(void (*f)(void *), void *arg)
{
  if ( this->EndTag )
    {
    this->RemoveObserver(this->EndTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->EndTag = this->AddObserver(vtkCommand::EndEvent,cbc);
    cbc->Delete();
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetStartMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->StartTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetProgressMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->ProgressTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetEndMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->EndTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

void vtkProcessObject::RemoveAllInputs()
{
  if ( this->Inputs )
    {
    for (int idx = 0; idx < this->NumberOfInputs; ++idx)
      {
      if ( this->Inputs[idx] )
        {
        this->Inputs[idx]->UnRegister(this);
        this->Inputs[idx] = NULL;
        }
      }
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    this->Modified();
    }
}

void vtkProcessObject::SortInputsByLocality()
{
  int i1, i2;
  int l1, l2;
  // length starts at 1 and doubles every pass.
  int length;
  vtkDataObject **tmp;

  // Copy inputs over to sorted array.
  memcpy(this->SortedInputs, this->Inputs,
         this->NumberOfInputs * sizeof(void*));

  length = 1;
  while (length < this->NumberOfInputs)
    {
    i1 = 0;
    while (i1 < this->NumberOfInputs)
      {
      l1 = length;
      i2 = i1 + l1;
      if (i2 > this->NumberOfInputs)
        { // Piece one has all the remaining entries.
        l1 = this->NumberOfInputs - i1;
        i2 = this->NumberOfInputs;
        l2 = 0;
        }
      else
        { // l2 is the smaller of the remainder or the current length.
        l2 = this->NumberOfInputs - i2;
        if (l2 > length)
          {
          l2 = length;
          }
        }
      this->SortMerge(this->SortedInputs+i1, l1,
                      this->SortedInputs+i2, l2,
                      this->SortedInputs2+i1);
      i1 = i2 + l2;
      }
    // swap the two arrays
    tmp = this->SortedInputs;
    this->SortedInputs = this->SortedInputs2;
    this->SortedInputs2 = tmp;
    length *= 2;
    }
}

void vtkProcessObject::SortMerge(vtkDataObject **a1, int l1,
                                 vtkDataObject **a2, int l2,
                                 vtkDataObject **results)
{
  while (l1 > 0 || l2 > 0)
    {
    // When the second list is empty, finish the first.
    if (l2 == 0)
      {
      *results++ = *a1++;
      --l1;
      }
    // When the first list is empty, finish the second.
    else if (l1 == 0 || *a1 == NULL)
      {
      *results++ = *a2++;
      --l2;
      }
    // Handle NULL pointers (put them at the end).
    else if (*a2 == NULL)
      {
      *results++ = *a1++;
      --l1;
      }
    else if (*a1 == NULL)
      {
      *results++ = *a2++;
      --l2;
      }
    // Sort by locality.
    else if ((*a1)->GetLocality() < (*a2)->GetLocality())
      {
      *results++ = *a1++;
      --l1;
      }
    else
      {
      *results++ = *a2++;
      --l2;
      }
    }
}

void vtkProcessObject::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number Of Required Inputs: "
     << this->NumberOfRequiredInputs << endl;

  if ( this->NumberOfInputs)
    {
    int idx;
    for (idx = 0; idx < this->NumberOfInputs; ++idx)
      {
      os << indent << "Input " << idx << ": (" << this->Inputs[idx] << ")\n";
      }
    }
  else
    {
    os << indent <<"No Inputs\n";
    }

  os << indent << "AbortExecute: " << (this->AbortExecute ? "On\n" : "Off\n");
  os << indent << "Progress: " << this->Progress << "\n";
  if ( this->ProgressText )
    {
    os << indent << "Progress Text: " << this->ProgressText << "\n";
    }
  else
    {
    os << indent << "Progress Text: (None)\n";
    }

}
<commit_msg>bug fix for consumers<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkProcessObject.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkProcessObject.h"

#include "vtkObjectFactory.h"
#include "vtkOldStyleCallbackCommand.h"
#include "vtkDataObject.h"

vtkCxxRevisionMacro(vtkProcessObject, "1.30");

// Instantiate object with no start, end, or progress methods.
vtkProcessObject::vtkProcessObject()
{
  this->StartTag = 0;
  this->ProgressTag = 0;
  this->EndTag = 0;
  this->AbortExecute = 0;
  this->Progress = 0.0;
  this->ProgressText = NULL;
  this->NumberOfInputs = 0;
  this->NumberOfRequiredInputs = 0;
  this->Inputs = NULL;
  this->SortedInputs = NULL;
  this->SortedInputs2 = NULL;
}

// Destructor for the vtkProcessObject class
vtkProcessObject::~vtkProcessObject()
{
  int idx;

  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx])
      {
      this->Inputs[idx]->RemoveConsumer(this);
      this->Inputs[idx]->UnRegister(this);
      this->Inputs[idx] = NULL;
      this->SortedInputs[idx] = NULL;
      this->SortedInputs2[idx] = NULL;
      }
    }
  if (this->Inputs)
    {
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    delete [] this->SortedInputs;
    this->SortedInputs = NULL;
    delete [] this->SortedInputs2;
    this->SortedInputs2 = NULL;
    }
  delete [] this->ProgressText;
  this->ProgressText = NULL;
}

typedef vtkDataObject *vtkDataObjectPointer;
//----------------------------------------------------------------------------
// Called by constructor to set up input array.
void vtkProcessObject::SetNumberOfInputs(int num)
{
  int idx;
  vtkDataObjectPointer *inputs;

  // in case nothing has changed.
  if (num == this->NumberOfInputs)
    {
    return;
    }

  // Allocate new arrays.
  inputs = new vtkDataObjectPointer[num];

  // Initialize with NULLs.
  for (idx = 0; idx < num; ++idx)
    {
    inputs[idx] = NULL;
    }

  // Copy old inputs
  for (idx = 0; idx < num && idx < this->NumberOfInputs; ++idx)
    {
    inputs[idx] = this->Inputs[idx];
    }

  // delete the previous arrays
  if (this->Inputs)
    {
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    delete [] this->SortedInputs;
    this->SortedInputs = NULL;
    delete [] this->SortedInputs2;
    this->SortedInputs2 = NULL;
    }

  // Set the new arrays
  this->Inputs = inputs;
  this->SortedInputs = new vtkDataObjectPointer[num];
  this->SortedInputs2 = new vtkDataObjectPointer[num];

  this->NumberOfInputs = num;
  this->Modified();
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::AddInput(vtkDataObject *input)
{
  int idx;

  if (input)
    {
    input->AddConsumer(this);
    input->Register(this);
    }
  this->Modified();

  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == NULL)
      {
      this->Inputs[idx] = input;
      return;
      }
    }

  this->SetNumberOfInputs(this->NumberOfInputs + 1);
  this->Inputs[this->NumberOfInputs - 1] = input;
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::RemoveInput(vtkDataObject *input)
{
  int idx, loc;

  if (!input)
    {
    return;
    }

  // find the input in the list of inputs
  loc = -1;
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == input)
      {
      loc = idx;
      }
    }
  if (loc == -1)
    {
    vtkDebugMacro("tried to remove an input that was not in the list");
    return;
    }

  this->Inputs[loc]->RemoveConsumer(this);
  this->Inputs[loc]->UnRegister(this);
  this->Inputs[loc] = NULL;

  // if that was the last input, then shrink the list
  if (loc == this->NumberOfInputs - 1)
    {
    this->SetNumberOfInputs(this->NumberOfInputs - 1);
    }

  this->Modified();
}

//----------------------------------------------------------------------------
// Adds an input to the first null position in the input list.
// Expands the list memory if necessary
void vtkProcessObject::SqueezeInputArray()
{
  int idx, loc;

  // move NULL entries to the end
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] == NULL)
      {
      for (loc = idx+1; loc < this->NumberOfInputs; loc++)
        {
        this->Inputs[loc-1] = this->Inputs[loc];
        }
      this->Inputs[this->NumberOfInputs -1] = NULL;
      }
    }

  // adjust the size of the array
  loc = -1;
  for (idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (loc == -1 && this->Inputs[idx] == NULL)
      {
      loc = idx;
      }
    }
  if (loc > 0)
    {
    this->SetNumberOfInputs(loc);
    }
}

//----------------------------------------------------------------------------
// Set an Input of this filter.
void vtkProcessObject::SetNthInput(int idx, vtkDataObject *input)
{
  if (idx < 0)
    {
    vtkErrorMacro(<< "SetNthInput: " << idx << ", cannot set input. ");
    return;
    }
  // Expand array if necessary.
  if (idx >= this->NumberOfInputs)
    {
    this->SetNumberOfInputs(idx + 1);
    }

  // does this change anything?
  if (input == this->Inputs[idx])
    {
    return;
    }

  if (this->Inputs[idx])
    {
    this->Inputs[idx]->RemoveConsumer(this);
    this->Inputs[idx]->UnRegister(this);
    this->Inputs[idx] = NULL;
    }

  if (input)
    {
    input->AddConsumer(this);
    input->Register(this);
    }

  this->Inputs[idx] = input;
  this->Modified();
}

// Update the progress of the process object. If a ProgressMethod exists,
// executes it. Then set the Progress ivar to amount. The parameter amount
// should range between (0,1).
void vtkProcessObject::UpdateProgress(float amount)
{
  this->Progress = amount;
  this->InvokeEvent(vtkCommand::ProgressEvent,(void *)&amount);
}

// Specify function to be called before object executes.
void vtkProcessObject::SetStartMethod(void (*f)(void *), void *arg)
{
  if ( this->StartTag )
    {
    this->RemoveObserver(this->StartTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->StartTag = this->AddObserver(vtkCommand::StartEvent,cbc);
    cbc->Delete();
    }
}

// Specify function to be called to show progress of filter
void vtkProcessObject::SetProgressMethod(void (*f)(void *), void *arg)
{
  if ( this->ProgressTag )
    {
    this->RemoveObserver(this->ProgressTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->ProgressTag = this->AddObserver(vtkCommand::ProgressEvent,cbc);
    cbc->Delete();
    }
}

// Specify function to be called after object executes.
void vtkProcessObject::SetEndMethod(void (*f)(void *), void *arg)
{
  if ( this->EndTag )
    {
    this->RemoveObserver(this->EndTag);
    }

  if ( f )
    {
    vtkOldStyleCallbackCommand *cbc = vtkOldStyleCallbackCommand::New();
    cbc->Callback = f;
    cbc->ClientData = arg;
    this->EndTag = this->AddObserver(vtkCommand::EndEvent,cbc);
    cbc->Delete();
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetStartMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->StartTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetProgressMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->ProgressTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProcessObject::SetEndMethodArgDelete(void (*f)(void *))
{
  vtkOldStyleCallbackCommand *cmd =
    (vtkOldStyleCallbackCommand *)this->GetCommand(this->EndTag);
  if (cmd)
    {
    cmd->SetClientDataDeleteCallback(f);
    }
}

void vtkProcessObject::RemoveAllInputs()
{
  if ( this->Inputs )
    {
    for (int idx = 0; idx < this->NumberOfInputs; ++idx)
      {
      if ( this->Inputs[idx] )
        {
        this->Inputs[idx]->UnRegister(this);
        this->Inputs[idx] = NULL;
        }
      }
    delete [] this->Inputs;
    this->Inputs = NULL;
    this->NumberOfInputs = 0;
    this->Modified();
    }
}

void vtkProcessObject::SortInputsByLocality()
{
  int i1, i2;
  int l1, l2;
  // length starts at 1 and doubles every pass.
  int length;
  vtkDataObject **tmp;

  // Copy inputs over to sorted array.
  memcpy(this->SortedInputs, this->Inputs,
         this->NumberOfInputs * sizeof(void*));

  length = 1;
  while (length < this->NumberOfInputs)
    {
    i1 = 0;
    while (i1 < this->NumberOfInputs)
      {
      l1 = length;
      i2 = i1 + l1;
      if (i2 > this->NumberOfInputs)
        { // Piece one has all the remaining entries.
        l1 = this->NumberOfInputs - i1;
        i2 = this->NumberOfInputs;
        l2 = 0;
        }
      else
        { // l2 is the smaller of the remainder or the current length.
        l2 = this->NumberOfInputs - i2;
        if (l2 > length)
          {
          l2 = length;
          }
        }
      this->SortMerge(this->SortedInputs+i1, l1,
                      this->SortedInputs+i2, l2,
                      this->SortedInputs2+i1);
      i1 = i2 + l2;
      }
    // swap the two arrays
    tmp = this->SortedInputs;
    this->SortedInputs = this->SortedInputs2;
    this->SortedInputs2 = tmp;
    length *= 2;
    }
}

void vtkProcessObject::SortMerge(vtkDataObject **a1, int l1,
                                 vtkDataObject **a2, int l2,
                                 vtkDataObject **results)
{
  while (l1 > 0 || l2 > 0)
    {
    // When the second list is empty, finish the first.
    if (l2 == 0)
      {
      *results++ = *a1++;
      --l1;
      }
    // When the first list is empty, finish the second.
    else if (l1 == 0 || *a1 == NULL)
      {
      *results++ = *a2++;
      --l2;
      }
    // Handle NULL pointers (put them at the end).
    else if (*a2 == NULL)
      {
      *results++ = *a1++;
      --l1;
      }
    else if (*a1 == NULL)
      {
      *results++ = *a2++;
      --l2;
      }
    // Sort by locality.
    else if ((*a1)->GetLocality() < (*a2)->GetLocality())
      {
      *results++ = *a1++;
      --l1;
      }
    else
      {
      *results++ = *a2++;
      --l2;
      }
    }
}

void vtkProcessObject::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number Of Required Inputs: "
     << this->NumberOfRequiredInputs << endl;

  if ( this->NumberOfInputs)
    {
    int idx;
    for (idx = 0; idx < this->NumberOfInputs; ++idx)
      {
      os << indent << "Input " << idx << ": (" << this->Inputs[idx] << ")\n";
      }
    }
  else
    {
    os << indent <<"No Inputs\n";
    }

  os << indent << "AbortExecute: " << (this->AbortExecute ? "On\n" : "Off\n");
  os << indent << "Progress: " << this->Progress << "\n";
  if ( this->ProgressText )
    {
    os << indent << "Progress Text: " << this->ProgressText << "\n";
    }
  else
    {
    os << indent << "Progress Text: (None)\n";
    }

}
<|endoftext|>


<commit_before>//===--- Refcounting.cpp - Reference-counting for Swift -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "gtest/gtest.h"

using namespace swift;

struct TestObject : HeapObject {
  size_t *Addr;
  size_t Value;
};

static void destroyTestObject(HeapObject *_object) {
  auto object = static_cast<TestObject*>(_object);
  assert(object->Addr && "object already deallocated");
  *object->Addr = object->Value;
  object->Addr = nullptr;
  swift_deallocObject(object, sizeof(TestObject), alignof(TestObject) - 1);
}

static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
  { { &destroyTestObject }, { &_TWVBo } },
  { { { MetadataKind::Class } }, 0, /*rodata*/ 1,
  ClassFlags::UsesSwift1Refcounting, nullptr, 0, 0, 0, 0, 0 }
};

/// Create an object that, when deallocated, stores the given value to
/// the given pointer.
static TestObject *allocTestObject(size_t *addr, size_t value) {
  auto result =
    static_cast<TestObject *>(swift_allocObject(&TestClassObjectMetadata,
                                                sizeof(TestObject),
                                                alignof(TestObject) - 1));
  result->Addr = addr;
  result->Value = value;
  return result;
}

TEST(RefcountingTest, release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, retain_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_retain(object);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, pin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, pin_pin_unpin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  auto pinResult2 = swift_tryPin(object);
  EXPECT_EQ(nullptr, pinResult2);
  EXPECT_EQ(0u, value);
  swift_unpin(pinResult2);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_retain_n(object, 32);
  swift_retain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_release_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_release(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_release_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, unknown_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_unknownRetain_n(object, 32);
  swift_unknownRetain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_unknownRelease_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_unknownRelease(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_unknownRelease_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, unowned_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_unownedRetain_n(object, 32);
  swift_unownedRetain(object);
  EXPECT_EQ(34u, swift_unownedRetainCount(object));
  swift_unownedRelease_n(object, 31);
  EXPECT_EQ(3u, swift_unownedRetainCount(object));
  swift_unownedRelease(object);
  EXPECT_EQ(2u, swift_unownedRetainCount(object));
  swift_unownedRelease_n(object, 1);
  EXPECT_EQ(1u, swift_unownedRetainCount(object));
  swift_release(object);
  EXPECT_EQ(1u, value);
}

//////////////////////////////////////////
// Non-atomic referenece counting tests //
//////////////////////////////////////////

TEST(RefcountingTest, nonatomic_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_retain_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_retain(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_pin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_nonatomic_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_pin_pin_unpin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_nonatomic_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  auto pinResult2 = swift_nonatomic_tryPin(object);
  EXPECT_EQ(nullptr, pinResult2);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(pinResult2);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_retain_n(object, 32);
  swift_nonatomic_retain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_nonatomic_release_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_nonatomic_release_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, nonatomic_unknown_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unknownRetain_n(object, 32);
  swift_nonatomic_unknownRetain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_nonatomic_unknownRelease_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_nonatomic_unknownRelease(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_nonatomic_unknownRelease_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

<commit_msg>[gardening] Fix recently introduced typo: "referenece" → "reference"<commit_after>//===--- Refcounting.cpp - Reference-counting for Swift -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "gtest/gtest.h"

using namespace swift;

struct TestObject : HeapObject {
  size_t *Addr;
  size_t Value;
};

static void destroyTestObject(HeapObject *_object) {
  auto object = static_cast<TestObject*>(_object);
  assert(object->Addr && "object already deallocated");
  *object->Addr = object->Value;
  object->Addr = nullptr;
  swift_deallocObject(object, sizeof(TestObject), alignof(TestObject) - 1);
}

static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
  { { &destroyTestObject }, { &_TWVBo } },
  { { { MetadataKind::Class } }, 0, /*rodata*/ 1,
  ClassFlags::UsesSwift1Refcounting, nullptr, 0, 0, 0, 0, 0 }
};

/// Create an object that, when deallocated, stores the given value to
/// the given pointer.
static TestObject *allocTestObject(size_t *addr, size_t value) {
  auto result =
    static_cast<TestObject *>(swift_allocObject(&TestClassObjectMetadata,
                                                sizeof(TestObject),
                                                alignof(TestObject) - 1));
  result->Addr = addr;
  result->Value = value;
  return result;
}

TEST(RefcountingTest, release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, retain_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_retain(object);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, pin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, pin_pin_unpin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  auto pinResult2 = swift_tryPin(object);
  EXPECT_EQ(nullptr, pinResult2);
  EXPECT_EQ(0u, value);
  swift_unpin(pinResult2);
  EXPECT_EQ(0u, value);
  swift_release(object);
  EXPECT_EQ(0u, value);
  swift_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_retain_n(object, 32);
  swift_retain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_release_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_release(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_release_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, unknown_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_unknownRetain_n(object, 32);
  swift_unknownRetain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_unknownRelease_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_unknownRelease(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_unknownRelease_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, unowned_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_unownedRetain_n(object, 32);
  swift_unownedRetain(object);
  EXPECT_EQ(34u, swift_unownedRetainCount(object));
  swift_unownedRelease_n(object, 31);
  EXPECT_EQ(3u, swift_unownedRetainCount(object));
  swift_unownedRelease(object);
  EXPECT_EQ(2u, swift_unownedRetainCount(object));
  swift_unownedRelease_n(object, 1);
  EXPECT_EQ(1u, swift_unownedRetainCount(object));
  swift_release(object);
  EXPECT_EQ(1u, value);
}

/////////////////////////////////////////
// Non-atomic reference counting tests //
/////////////////////////////////////////

TEST(RefcountingTest, nonatomic_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_retain_release) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_retain(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_pin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_nonatomic_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_pin_pin_unpin_unpin) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  auto pinResult = swift_nonatomic_tryPin(object);
  EXPECT_EQ(object, pinResult);
  EXPECT_EQ(0u, value);
  auto pinResult2 = swift_nonatomic_tryPin(object);
  EXPECT_EQ(nullptr, pinResult2);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(pinResult2);
  EXPECT_EQ(0u, value);
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unpin(object);
  EXPECT_EQ(1u, value);
}

TEST(RefcountingTest, nonatomic_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_retain_n(object, 32);
  swift_nonatomic_retain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_nonatomic_release_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_nonatomic_release(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_nonatomic_release_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

TEST(RefcountingTest, nonatomic_unknown_retain_release_n) {
  size_t value = 0;
  auto object = allocTestObject(&value, 1);
  EXPECT_EQ(0u, value);
  swift_nonatomic_unknownRetain_n(object, 32);
  swift_nonatomic_unknownRetain(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(34u, swift_retainCount(object));
  swift_nonatomic_unknownRelease_n(object, 31);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(3u, swift_retainCount(object));
  swift_nonatomic_unknownRelease(object);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(2u, swift_retainCount(object));
  swift_nonatomic_unknownRelease_n(object, 1);
  EXPECT_EQ(0u, value);
  EXPECT_EQ(1u, swift_retainCount(object));
}

<|endoftext|>