<commit_before>//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCAsmStreamer : public MCStreamer {
  raw_ostream &OS;
  const MCAsmInfo &MAI;
  bool IsLittleEndian;
  MCInstPrinter *InstPrinter;
  MCCodeEmitter *Emitter;
public:
  MCAsmStreamer(MCContext &Context, raw_ostream &_OS, const MCAsmInfo &tai,
                bool isLittleEndian, MCInstPrinter *_Printer,
                MCCodeEmitter *_Emitter)
    : MCStreamer(Context), OS(_OS), MAI(tai), InstPrinter(_Printer),
      Emitter(_Emitter) {}
  ~MCAsmStreamer() {}

  bool isLittleEndian() const { return IsLittleEndian; }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);

  virtual void EmitLabel(MCSymbol *Symbol);

  virtual void EmitAssemblerFlag(AssemblerFlag Flag);

  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);

  virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute);

  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);

  virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size,
                                unsigned ByteAlignment);

  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);

  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);

  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace);

  virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
                        unsigned AddrSpace);

  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);

  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitInstruction(const MCInst &Inst);

  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
  assert(Bytes && "Invalid size!");
  return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}

static inline const MCExpr *truncateToSize(const MCExpr *Value,
                                           unsigned Bytes) {
  // FIXME: Do we really need this routine?
  return Value;
}

void MCAsmStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");
  if (Section != CurSection) {
    CurSection = Section;
    Section->PrintSwitchToSection(MAI, OS);
  }
}

void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
  assert(CurSection && "Cannot emit before setting section!");

  OS << *Symbol << ":\n";
  Symbol->setSection(*CurSection);
}

void MCAsmStreamer::EmitAssemblerFlag(AssemblerFlag Flag) {
  switch (Flag) {
  default: assert(0 && "Invalid flag!");
  case SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break;
  }
  OS << '\n';
}

void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  OS << *Symbol << " = " << *Value << '\n';

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(Value);
}

void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                        SymbolAttr Attribute) {
  switch (Attribute) {
  case Global:         OS << ".globl";           break;
  case Hidden:         OS << ".hidden";          break;
  case IndirectSymbol: OS << ".indirect_symbol"; break;
  case Internal:       OS << ".internal";        break;
  case LazyReference:  OS << ".lazy_reference";  break;
  case NoDeadStrip:    OS << ".no_dead_strip";   break;
  case PrivateExtern:  OS << ".private_extern";  break;
  case Protected:      OS << ".protected";       break;
  case Reference:      OS << ".reference";       break;
  case Weak:           OS << ".weak";            break;
  case WeakDefinition: OS << ".weak_definition"; break;
  case WeakReference:  OS << ".weak_reference";  break;
  }

  OS << ' ' << *Symbol << '\n';
}

void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  OS << ".desc" << ' ' << *Symbol << ',' << DescValue << '\n';
}

void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size,
                                     unsigned ByteAlignment) {
  OS << MAI.getCOMMDirective() << *Symbol << ',' << Size;
  if (ByteAlignment != 0 && MAI.getCOMMDirectiveTakesAlignment()) {
    if (MAI.getAlignmentIsInBytes())
      OS << ',' << ByteAlignment;
    else
      OS << ',' << Log2_32(ByteAlignment);
  }
  OS << '\n';
}

void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                 unsigned Size, unsigned ByteAlignment) {
  // Note: a .zerofill directive does not switch sections.
  OS << ".zerofill ";

  // This is a mach-o specific directive.
  const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
  OS << MOSection->getSegmentName() << "," << MOSection->getSectionName();

  if (Symbol != NULL) {
    OS << ',' << *Symbol << ',' << Size;
    if (ByteAlignment != 0)
      OS << ',' << Log2_32(ByteAlignment);
  }
  OS << '\n';
}

void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = MAI.getData8bitsDirective(AddrSpace);
  for (unsigned i = 0, e = Data.size(); i != e; ++i)
    OS << Directive << (unsigned)(unsigned char)Data[i] << '\n';
}

/// EmitIntValue - Special case of EmitValue that avoids the client having
/// to pass in a MCExpr for constant integers.
void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size,
                                 unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = 0;
  switch (Size) {
  default: break;
  case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
  case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
  case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
  case 8:
    Directive = MAI.getData64bitsDirective(AddrSpace);
    // If the target doesn't support 64-bit data, emit as two 32-bit halves.
    if (Directive) break;
    if (isLittleEndian()) {
      EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
      EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
    } else {
      EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
      EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
    }
    return;
  }

  assert(Directive && "Invalid size for machine code value!");
  OS << Directive << truncateToSize(Value, Size) << '\n';
}

void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                              unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = 0;
  switch (Size) {
  default: break;
  case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
  case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
  case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
  case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break;
  }

  assert(Directive && "Invalid size for machine code value!");
  OS << Directive << *truncateToSize(Value, Size) << '\n';
}

/// EmitFill - Emit NumBytes bytes worth of the value specified by
/// FillValue.  This implements directives such as '.space'.
void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
                             unsigned AddrSpace) {
  if (NumBytes == 0) return;

  if (AddrSpace == 0)
    if (const char *ZeroDirective = MAI.getZeroDirective()) {
      OS << ZeroDirective << NumBytes;
      if (FillValue != 0)
        OS << ',' << (int)FillValue;
      OS << '\n';
      return;
    }

  // Emit a byte at a time.
  MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace);
}

void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
                                         unsigned ValueSize,
                                         unsigned MaxBytesToEmit) {
  // Some assemblers don't support non-power of two alignments, so we always
  // emit alignments as a power of two if possible.
  if (isPowerOf2_32(ByteAlignment)) {
    switch (ValueSize) {
    default: llvm_unreachable("Invalid size for machine code value!");
    case 1: OS << MAI.getAlignDirective(); break;
    // FIXME: use MAI for this!
    case 2: OS << ".p2alignw "; break;
    case 4: OS << ".p2alignl "; break;
    case 8: llvm_unreachable("Unsupported alignment size!");
    }

    if (MAI.getAlignmentIsInBytes())
      OS << ByteAlignment;
    else
      OS << Log2_32(ByteAlignment);

    if (Value || MaxBytesToEmit) {
      OS << ", 0x";
      OS.write_hex(truncateToSize(Value, ValueSize));

      if (MaxBytesToEmit)
        OS << ", " << MaxBytesToEmit;
    }
    OS << '\n';
    return;
  }

  // Non-power of two alignment.  This is not widely supported by assemblers.
  // FIXME: Parameterize this based on MAI.
  switch (ValueSize) {
  default: llvm_unreachable("Invalid size for machine code value!");
  case 1: OS << ".balign";  break;
  case 2: OS << ".balignw"; break;
  case 4: OS << ".balignl"; break;
  case 8: llvm_unreachable("Unsupported alignment size!");
  }

  OS << ' ' << ByteAlignment;
  OS << ", " << truncateToSize(Value, ValueSize);
  if (MaxBytesToEmit)
    OS << ", " << MaxBytesToEmit;
  OS << '\n';
}

void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset,
                                      unsigned char Value) {
  // FIXME: Verify that Offset is associated with the current section.
  OS << ".org " << *Offset << ", " << (unsigned) Value << '\n';
}

void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
  assert(CurSection && "Cannot emit contents before setting section!");

  // If we have an AsmPrinter, use that to print.
  if (InstPrinter) {
    InstPrinter->printInst(&Inst);
    OS << '\n';

    // Show the encoding if we have a code emitter.
    if (Emitter) {
      SmallString<256> Code;
      raw_svector_ostream VecOS(Code);
      Emitter->EncodeInstruction(Inst, VecOS);
      VecOS.flush();

      OS.indent(20);
      OS << " # encoding: [";
      for (unsigned i = 0, e = Code.size(); i != e; ++i) {
        if (i)
          OS << ',';
        OS << format("%#04x", uint8_t(Code[i]));
      }
      OS << "]\n";
    }

    return;
  }

  // Otherwise fall back to a structural printing for now. Eventually we should
  // always have access to the target specific printer.
  Inst.print(OS, &MAI);
  OS << '\n';
}

void MCAsmStreamer::Finish() {
  OS.flush();
}

MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS,
                                    const MCAsmInfo &MAI, bool isLittleEndian,
                                    MCInstPrinter *IP,
                                    MCCodeEmitter *CE) {
  return new MCAsmStreamer(Context, OS, MAI, isLittleEndian, IP, CE);
}
<commit_msg>use getGlobalDirective(), don't hardcode .globl.  PR6093<commit_after>//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCAsmStreamer : public MCStreamer {
  raw_ostream &OS;
  const MCAsmInfo &MAI;
  bool IsLittleEndian;
  MCInstPrinter *InstPrinter;
  MCCodeEmitter *Emitter;
public:
  MCAsmStreamer(MCContext &Context, raw_ostream &_OS, const MCAsmInfo &tai,
                bool isLittleEndian, MCInstPrinter *_Printer,
                MCCodeEmitter *_Emitter)
    : MCStreamer(Context), OS(_OS), MAI(tai), InstPrinter(_Printer),
      Emitter(_Emitter) {}
  ~MCAsmStreamer() {}

  bool isLittleEndian() const { return IsLittleEndian; }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);

  virtual void EmitLabel(MCSymbol *Symbol);

  virtual void EmitAssemblerFlag(AssemblerFlag Flag);

  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);

  virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute);

  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);

  virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size,
                                unsigned ByteAlignment);

  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);

  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);

  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace);

  virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
                        unsigned AddrSpace);

  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);

  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitInstruction(const MCInst &Inst);

  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
  assert(Bytes && "Invalid size!");
  return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}

static inline const MCExpr *truncateToSize(const MCExpr *Value,
                                           unsigned Bytes) {
  // FIXME: Do we really need this routine?
  return Value;
}

void MCAsmStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");
  if (Section != CurSection) {
    CurSection = Section;
    Section->PrintSwitchToSection(MAI, OS);
  }
}

void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
  assert(CurSection && "Cannot emit before setting section!");

  OS << *Symbol << ":\n";
  Symbol->setSection(*CurSection);
}

void MCAsmStreamer::EmitAssemblerFlag(AssemblerFlag Flag) {
  switch (Flag) {
  default: assert(0 && "Invalid flag!");
  case SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break;
  }
  OS << '\n';
}

void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  OS << *Symbol << " = " << *Value << '\n';

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(Value);
}

void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                        SymbolAttr Attribute) {
  switch (Attribute) {
  case Global:         OS << MAI.getGlobalDirective(); break; // .globl
  case Hidden:         OS << ".hidden ";          break;
  case IndirectSymbol: OS << ".indirect_symbol "; break;
  case Internal:       OS << ".internal ";        break;
  case LazyReference:  OS << ".lazy_reference ";  break;
  case NoDeadStrip:    OS << ".no_dead_strip ";   break;
  case PrivateExtern:  OS << ".private_extern ";  break;
  case Protected:      OS << ".protected ";       break;
  case Reference:      OS << ".reference ";       break;
  case Weak:           OS << ".weak ";            break;
  case WeakDefinition: OS << ".weak_definition "; break;
  case WeakReference:  OS << ".weak_reference ";  break;
  }

  OS << *Symbol << '\n';
}

void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  OS << ".desc" << ' ' << *Symbol << ',' << DescValue << '\n';
}

void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size,
                                     unsigned ByteAlignment) {
  OS << MAI.getCOMMDirective() << *Symbol << ',' << Size;
  if (ByteAlignment != 0 && MAI.getCOMMDirectiveTakesAlignment()) {
    if (MAI.getAlignmentIsInBytes())
      OS << ',' << ByteAlignment;
    else
      OS << ',' << Log2_32(ByteAlignment);
  }
  OS << '\n';
}

void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                 unsigned Size, unsigned ByteAlignment) {
  // Note: a .zerofill directive does not switch sections.
  OS << ".zerofill ";

  // This is a mach-o specific directive.
  const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
  OS << MOSection->getSegmentName() << "," << MOSection->getSectionName();

  if (Symbol != NULL) {
    OS << ',' << *Symbol << ',' << Size;
    if (ByteAlignment != 0)
      OS << ',' << Log2_32(ByteAlignment);
  }
  OS << '\n';
}

void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = MAI.getData8bitsDirective(AddrSpace);
  for (unsigned i = 0, e = Data.size(); i != e; ++i)
    OS << Directive << (unsigned)(unsigned char)Data[i] << '\n';
}

/// EmitIntValue - Special case of EmitValue that avoids the client having
/// to pass in a MCExpr for constant integers.
void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size,
                                 unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = 0;
  switch (Size) {
  default: break;
  case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
  case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
  case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
  case 8:
    Directive = MAI.getData64bitsDirective(AddrSpace);
    // If the target doesn't support 64-bit data, emit as two 32-bit halves.
    if (Directive) break;
    if (isLittleEndian()) {
      EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
      EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
    } else {
      EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
      EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
    }
    return;
  }

  assert(Directive && "Invalid size for machine code value!");
  OS << Directive << truncateToSize(Value, Size) << '\n';
}

void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                              unsigned AddrSpace) {
  assert(CurSection && "Cannot emit contents before setting section!");
  const char *Directive = 0;
  switch (Size) {
  default: break;
  case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
  case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
  case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
  case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break;
  }

  assert(Directive && "Invalid size for machine code value!");
  OS << Directive << *truncateToSize(Value, Size) << '\n';
}

/// EmitFill - Emit NumBytes bytes worth of the value specified by
/// FillValue.  This implements directives such as '.space'.
void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
                             unsigned AddrSpace) {
  if (NumBytes == 0) return;

  if (AddrSpace == 0)
    if (const char *ZeroDirective = MAI.getZeroDirective()) {
      OS << ZeroDirective << NumBytes;
      if (FillValue != 0)
        OS << ',' << (int)FillValue;
      OS << '\n';
      return;
    }

  // Emit a byte at a time.
  MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace);
}

void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
                                         unsigned ValueSize,
                                         unsigned MaxBytesToEmit) {
  // Some assemblers don't support non-power of two alignments, so we always
  // emit alignments as a power of two if possible.
  if (isPowerOf2_32(ByteAlignment)) {
    switch (ValueSize) {
    default: llvm_unreachable("Invalid size for machine code value!");
    case 1: OS << MAI.getAlignDirective(); break;
    // FIXME: use MAI for this!
    case 2: OS << ".p2alignw "; break;
    case 4: OS << ".p2alignl "; break;
    case 8: llvm_unreachable("Unsupported alignment size!");
    }

    if (MAI.getAlignmentIsInBytes())
      OS << ByteAlignment;
    else
      OS << Log2_32(ByteAlignment);

    if (Value || MaxBytesToEmit) {
      OS << ", 0x";
      OS.write_hex(truncateToSize(Value, ValueSize));

      if (MaxBytesToEmit)
        OS << ", " << MaxBytesToEmit;
    }
    OS << '\n';
    return;
  }

  // Non-power of two alignment.  This is not widely supported by assemblers.
  // FIXME: Parameterize this based on MAI.
  switch (ValueSize) {
  default: llvm_unreachable("Invalid size for machine code value!");
  case 1: OS << ".balign";  break;
  case 2: OS << ".balignw"; break;
  case 4: OS << ".balignl"; break;
  case 8: llvm_unreachable("Unsupported alignment size!");
  }

  OS << ' ' << ByteAlignment;
  OS << ", " << truncateToSize(Value, ValueSize);
  if (MaxBytesToEmit)
    OS << ", " << MaxBytesToEmit;
  OS << '\n';
}

void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset,
                                      unsigned char Value) {
  // FIXME: Verify that Offset is associated with the current section.
  OS << ".org " << *Offset << ", " << (unsigned) Value << '\n';
}

void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
  assert(CurSection && "Cannot emit contents before setting section!");

  // If we have an AsmPrinter, use that to print.
  if (InstPrinter) {
    InstPrinter->printInst(&Inst);
    OS << '\n';

    // Show the encoding if we have a code emitter.
    if (Emitter) {
      SmallString<256> Code;
      raw_svector_ostream VecOS(Code);
      Emitter->EncodeInstruction(Inst, VecOS);
      VecOS.flush();

      OS.indent(20);
      OS << " # encoding: [";
      for (unsigned i = 0, e = Code.size(); i != e; ++i) {
        if (i)
          OS << ',';
        OS << format("%#04x", uint8_t(Code[i]));
      }
      OS << "]\n";
    }

    return;
  }

  // Otherwise fall back to a structural printing for now. Eventually we should
  // always have access to the target specific printer.
  Inst.print(OS, &MAI);
  OS << '\n';
}

void MCAsmStreamer::Finish() {
  OS.flush();
}

MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS,
                                    const MCAsmInfo &MAI, bool isLittleEndian,
                                    MCInstPrinter *IP,
                                    MCCodeEmitter *CE) {
  return new MCAsmStreamer(Context, OS, MAI, isLittleEndian, IP, CE);
}
<|endoftext|>


<commit_before>//===-- Writer.cpp - Library for Printing VM assembly files ------*- C++ -*--=//
//
// This library implements the functionality defined in llvm/Assembly/Writer.h
//
// This library uses the Analysis library to figure out offsets for
// variables in the method tables...
//
// TODO: print out the type name instead of the full type if a particular type
//       is in the symbol table...
//
//===----------------------------------------------------------------------===//

#include "llvm/Assembly/Writer.h"
#include "llvm/Analysis/SlotCalculator.h"
#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/ConstPoolVals.h"
#include "llvm/iOther.h"
#include "llvm/iMemory.h"

class AssemblyWriter : public ModuleAnalyzer {
  ostream &Out;
  SlotCalculator &Table;
public:
  inline AssemblyWriter(ostream &o, SlotCalculator &Tab) : Out(o), Table(Tab) {
  }

  inline void write(const Module *M)         { processModule(M);      }
  inline void write(const Method *M)         { processMethod(M);      }
  inline void write(const BasicBlock *BB)    { processBasicBlock(BB); }
  inline void write(const Instruction *I)    { processInstruction(I); }
  inline void write(const ConstPoolVal *CPV) { processConstant(CPV);  }

protected:
  virtual bool visitMethod(const Method *M);
  virtual bool processConstPool(const ConstantPool &CP, bool isMethod);
  virtual bool processConstant(const ConstPoolVal *CPV);
  virtual bool processMethod(const Method *M);
  virtual bool processMethodArgument(const MethodArgument *MA);
  virtual bool processBasicBlock(const BasicBlock *BB);
  virtual bool processInstruction(const Instruction *I);

private :
  void writeOperand(const Value *Op, bool PrintType, bool PrintName = true);
};

// visitMethod - This member is called after the above two steps, visting each
// method, because they are effectively values that go into the constant pool.
//
bool AssemblyWriter::visitMethod(const Method *M) {
  return false;
}

bool AssemblyWriter::processConstPool(const ConstantPool &CP, bool isMethod) {
  // Done printing arguments...
  if (isMethod) Out << ")\n";

  ModuleAnalyzer::processConstPool(CP, isMethod);

  if (isMethod)
    Out << "begin";
  else
    Out << "implementation\n";
  return false;
}

// processConstant - Print out a constant pool entry...
//
bool AssemblyWriter::processConstant(const ConstPoolVal *CPV) {
  Out << "\t";

  // Print out name if it exists...
  if (CPV->hasName())
    Out << "%" << CPV->getName() << " = ";

  // Print out the opcode...
  Out << CPV->getType();

  // Write the value out now...
  writeOperand(CPV, false, false);

  if (!CPV->hasName() && CPV->getType() != Type::VoidTy) {
    int Slot = Table.getValSlot(CPV); // Print out the def slot taken...
    Out << "\t\t; <" << CPV->getType() << ">:";
    if (Slot >= 0) Out << Slot;
    else Out << "<badref>";
  }

  Out << endl;
  return false;
}

// processMethod - Process all aspects of a method.
//
bool AssemblyWriter::processMethod(const Method *M) {
  // Print out the return type and name...
  Out << "\n" << M->getReturnType() << " \"" << M->getName() << "\"(";
  Table.incorporateMethod(M);
  ModuleAnalyzer::processMethod(M);
  Table.purgeMethod();
  Out << "end\n";
  return false;
}

// processMethodArgument - This member is called for every argument that
// is passed into the method.  Simply print it out
//
bool AssemblyWriter::processMethodArgument(const MethodArgument *Arg) {
  // Insert commas as we go... the first arg doesn't get a comma
  if (Arg != Arg->getParent()->getArgumentList().front()) Out << ", ";

  // Output type...
  Out << Arg->getType();

  // Output name, if available...
  if (Arg->hasName())
    Out << " %" << Arg->getName();
  else if (Table.getValSlot(Arg) < 0)
    Out << "<badref>";

  return false;
}

// processBasicBlock - This member is called for each basic block in a methd.
//
bool AssemblyWriter::processBasicBlock(const BasicBlock *BB) {
  if (BB->hasName()) {              // Print out the label if it exists...
    Out << "\n" << BB->getName() << ":";
  } else {
    int Slot = Table.getValSlot(BB);
    Out << "\n; <label>:";
    if (Slot >= 0)
      Out << Slot;         // Extra newline seperates out label's
    else
      Out << "<badref>";
  }
  Out << "\t\t\t\t\t;[#uses=" << BB->use_size() << "]\n";  // Output # uses

  ModuleAnalyzer::processBasicBlock(BB);
  return false;
}

// processInstruction - This member is called for each Instruction in a methd.
//
bool AssemblyWriter::processInstruction(const Instruction *I) {
  Out << "\t";

  // Print out name if it exists...
  if (I && I->hasName())
    Out << "%" << I->getName() << " = ";

  // Print out the opcode...
  Out << I->getOpcodeName();

  // Print out the type of the operands...
  const Value *Operand = I->getNumOperands() ? I->getOperand(0) : 0;

  // Special case conditional branches to swizzle the condition out to the front
  if (I->getOpcode() == Instruction::Br && I->getNumOperands() > 1) {
    writeOperand(I->getOperand(2), true);
    Out << ",";
    writeOperand(Operand, true);
    Out << ",";
    writeOperand(I->getOperand(1), true);

  } else if (I->getOpcode() == Instruction::Switch) {
    // Special case switch statement to get formatting nice and correct...
    writeOperand(Operand         , true); Out << ",";
    writeOperand(I->getOperand(1), true); Out << " [";

    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; op += 2) {
      Out << "\n\t\t";
      writeOperand(I->getOperand(op  ), true); Out << ",";
      writeOperand(I->getOperand(op+1), true);
    }
    Out << "\n\t]";
  } else if (I->isPHINode()) {
    Out << " " << Operand->getType();

    Out << " [";  writeOperand(Operand, false); Out << ",";
    writeOperand(I->getOperand(1), false); Out << " ]";
    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; op += 2) {
      Out << ", [";
      writeOperand(I->getOperand(op  ), false); Out << ",";
      writeOperand(I->getOperand(op+1), false); Out << " ]";
    }
  } else if (I->getOpcode() == Instruction::Ret && !Operand) {
    Out << " void";
  } else if (I->getOpcode() == Instruction::Call) {
    writeOperand(Operand, true);
    Out << "(";
    if (I->getNumOperands() > 1) writeOperand(I->getOperand(1), true);
    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; ++op) {
      Out << ",";
      writeOperand(I->getOperand(op), true);
    }

    Out << " )";
  } else if (I->getOpcode() == Instruction::Malloc ||
	     I->getOpcode() == Instruction::Alloca) {
    Out << " " << ((const PointerType*)I->getType())->getValueType();
    if (I->getNumOperands()) {
      Out << ",";
      writeOperand(I->getOperand(0), true);
    }
  } else if (I->getOpcode() == Instruction::Cast) {
    writeOperand(Operand, true);
    Out << " to " << I->getType();
  } else if (Operand) {   // Print the normal way...

    // PrintAllTypes - Instructions who have operands of all the same type
    // omit the type from all but the first operand.  If the instruction has
    // different type operands (for example br), then they are all printed.
    bool PrintAllTypes = false;
    const Type *TheType = Operand->getType();

    for (unsigned i = 1, E = I->getNumOperands(); i != E; ++i) {
      Operand = I->getOperand(i);
      if (Operand->getType() != TheType) {
	PrintAllTypes = true;       // We have differing types!  Print them all!
	break;
      }
    }

    if (!PrintAllTypes)
      Out << " " << I->getOperand(0)->getType();

    for (unsigned i = 0, E = I->getNumOperands(); i != E; ++i) {
      if (i) Out << ",";
      writeOperand(I->getOperand(i), PrintAllTypes);
    }
  }

  // Print a little comment after the instruction indicating which slot it
  // occupies.
  //
  if (I->getType() != Type::VoidTy) {
    Out << "\t\t; <" << I->getType() << ">";

    if (!I->hasName()) {
      int Slot = Table.getValSlot(I); // Print out the def slot taken...
      if (Slot >= 0) Out << ":" << Slot;
      else Out << ":<badref>";
    }
    Out << "\t[#uses=" << I->use_size() << "]";  // Output # uses
  }
  Out << endl;

  return false;
}

void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType,
				  bool PrintName) {
  if (PrintType)
    Out << " " << Operand->getType();

  if (Operand->hasName() && PrintName) {
    Out << " %" << Operand->getName();
  } else {
    int Slot = Table.getValSlot(Operand);

    if (const ConstPoolVal *CPV = Operand->castConstant()) {
      Out << " " << CPV->getStrValue();
    } else {
      if (Slot >= 0)  Out << " %" << Slot;
      else if (PrintName)
        Out << "<badref>";     // Not embeded into a location?
    }
  }
}

//===----------------------------------------------------------------------===//
//                       External Interface declarations
//===----------------------------------------------------------------------===//

void WriteToAssembly(const Module *M, ostream &o) {
  if (M == 0) { o << "<null> module\n"; return; }
  SlotCalculator SlotTable(M, true);
  AssemblyWriter W(o, SlotTable);

  W.write(M);
}

void WriteToAssembly(const Method *M, ostream &o) {
  if (M == 0) { o << "<null> method\n"; return; }
  SlotCalculator SlotTable(M->getParent(), true);
  AssemblyWriter W(o, SlotTable);

  W.write(M);
}

void WriteToAssembly(const BasicBlock *BB, ostream &o) {
  if (BB == 0) { o << "<null> basic block\n"; return; }

  SlotCalculator SlotTable(BB->getParent(), true);
  AssemblyWriter W(o, SlotTable);

  W.write(BB);
}

void WriteToAssembly(const ConstPoolVal *CPV, ostream &o) {
  if (CPV == 0) { o << "<null> constant pool value\n"; return; }

  SlotCalculator *SlotTable;

  // A Constant pool value may have a parent that is either a method or a
  // module.  Untangle this now...
  //
  if (CPV->getParent() == 0 || CPV->getParent()->isMethod()) {
    SlotTable = new SlotCalculator((Method*)CPV->getParent(), true);
  } else {
    SlotTable =
      new SlotCalculator(CPV->getParent()->castModuleAsserting(), true);
  }

  AssemblyWriter W(o, *SlotTable);
  W.write(CPV);

  delete SlotTable;
}

void WriteToAssembly(const Instruction *I, ostream &o) {
  if (I == 0) { o << "<null> instruction\n"; return; }

  SlotCalculator SlotTable(I->getParent() ? I->getParent()->getParent() : 0,
			   true);
  AssemblyWriter W(o, SlotTable);

  W.write(I);
}
<commit_msg>Add DebugValue member.<commit_after>//===-- Writer.cpp - Library for Printing VM assembly files ------*- C++ -*--=//
//
// This library implements the functionality defined in llvm/Assembly/Writer.h
//
// This library uses the Analysis library to figure out offsets for
// variables in the method tables...
//
// TODO: print out the type name instead of the full type if a particular type
//       is in the symbol table...
//
//===----------------------------------------------------------------------===//

#include "llvm/Assembly/Writer.h"
#include "llvm/Analysis/SlotCalculator.h"
#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/ConstPoolVals.h"
#include "llvm/iOther.h"
#include "llvm/iMemory.h"

void DebugValue(const Value *V) {
  cerr << V << endl;
}

class AssemblyWriter : public ModuleAnalyzer {
  ostream &Out;
  SlotCalculator &Table;
public:
  inline AssemblyWriter(ostream &o, SlotCalculator &Tab) : Out(o), Table(Tab) {
  }

  inline void write(const Module *M)         { processModule(M);      }
  inline void write(const Method *M)         { processMethod(M);      }
  inline void write(const BasicBlock *BB)    { processBasicBlock(BB); }
  inline void write(const Instruction *I)    { processInstruction(I); }
  inline void write(const ConstPoolVal *CPV) { processConstant(CPV);  }

protected:
  virtual bool visitMethod(const Method *M);
  virtual bool processConstPool(const ConstantPool &CP, bool isMethod);
  virtual bool processConstant(const ConstPoolVal *CPV);
  virtual bool processMethod(const Method *M);
  virtual bool processMethodArgument(const MethodArgument *MA);
  virtual bool processBasicBlock(const BasicBlock *BB);
  virtual bool processInstruction(const Instruction *I);

private :
  void writeOperand(const Value *Op, bool PrintType, bool PrintName = true);
};

// visitMethod - This member is called after the above two steps, visting each
// method, because they are effectively values that go into the constant pool.
//
bool AssemblyWriter::visitMethod(const Method *M) {
  return false;
}

bool AssemblyWriter::processConstPool(const ConstantPool &CP, bool isMethod) {
  // Done printing arguments...
  if (isMethod) Out << ")\n";

  ModuleAnalyzer::processConstPool(CP, isMethod);

  if (isMethod)
    Out << "begin";
  else
    Out << "implementation\n";
  return false;
}

// processConstant - Print out a constant pool entry...
//
bool AssemblyWriter::processConstant(const ConstPoolVal *CPV) {
  Out << "\t";

  // Print out name if it exists...
  if (CPV->hasName())
    Out << "%" << CPV->getName() << " = ";

  // Print out the opcode...
  Out << CPV->getType();

  // Write the value out now...
  writeOperand(CPV, false, false);

  if (!CPV->hasName() && CPV->getType() != Type::VoidTy) {
    int Slot = Table.getValSlot(CPV); // Print out the def slot taken...
    Out << "\t\t; <" << CPV->getType() << ">:";
    if (Slot >= 0) Out << Slot;
    else Out << "<badref>";
  }

  Out << endl;
  return false;
}

// processMethod - Process all aspects of a method.
//
bool AssemblyWriter::processMethod(const Method *M) {
  // Print out the return type and name...
  Out << "\n" << M->getReturnType() << " \"" << M->getName() << "\"(";
  Table.incorporateMethod(M);
  ModuleAnalyzer::processMethod(M);
  Table.purgeMethod();
  Out << "end\n";
  return false;
}

// processMethodArgument - This member is called for every argument that
// is passed into the method.  Simply print it out
//
bool AssemblyWriter::processMethodArgument(const MethodArgument *Arg) {
  // Insert commas as we go... the first arg doesn't get a comma
  if (Arg != Arg->getParent()->getArgumentList().front()) Out << ", ";

  // Output type...
  Out << Arg->getType();

  // Output name, if available...
  if (Arg->hasName())
    Out << " %" << Arg->getName();
  else if (Table.getValSlot(Arg) < 0)
    Out << "<badref>";

  return false;
}

// processBasicBlock - This member is called for each basic block in a methd.
//
bool AssemblyWriter::processBasicBlock(const BasicBlock *BB) {
  if (BB->hasName()) {              // Print out the label if it exists...
    Out << "\n" << BB->getName() << ":";
  } else {
    int Slot = Table.getValSlot(BB);
    Out << "\n; <label>:";
    if (Slot >= 0)
      Out << Slot;         // Extra newline seperates out label's
    else
      Out << "<badref>";
  }
  Out << "\t\t\t\t\t;[#uses=" << BB->use_size() << "]\n";  // Output # uses

  ModuleAnalyzer::processBasicBlock(BB);
  return false;
}

// processInstruction - This member is called for each Instruction in a methd.
//
bool AssemblyWriter::processInstruction(const Instruction *I) {
  Out << "\t";

  // Print out name if it exists...
  if (I && I->hasName())
    Out << "%" << I->getName() << " = ";

  // Print out the opcode...
  Out << I->getOpcodeName();

  // Print out the type of the operands...
  const Value *Operand = I->getNumOperands() ? I->getOperand(0) : 0;

  // Special case conditional branches to swizzle the condition out to the front
  if (I->getOpcode() == Instruction::Br && I->getNumOperands() > 1) {
    writeOperand(I->getOperand(2), true);
    Out << ",";
    writeOperand(Operand, true);
    Out << ",";
    writeOperand(I->getOperand(1), true);

  } else if (I->getOpcode() == Instruction::Switch) {
    // Special case switch statement to get formatting nice and correct...
    writeOperand(Operand         , true); Out << ",";
    writeOperand(I->getOperand(1), true); Out << " [";

    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; op += 2) {
      Out << "\n\t\t";
      writeOperand(I->getOperand(op  ), true); Out << ",";
      writeOperand(I->getOperand(op+1), true);
    }
    Out << "\n\t]";
  } else if (I->isPHINode()) {
    Out << " " << Operand->getType();

    Out << " [";  writeOperand(Operand, false); Out << ",";
    writeOperand(I->getOperand(1), false); Out << " ]";
    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; op += 2) {
      Out << ", [";
      writeOperand(I->getOperand(op  ), false); Out << ",";
      writeOperand(I->getOperand(op+1), false); Out << " ]";
    }
  } else if (I->getOpcode() == Instruction::Ret && !Operand) {
    Out << " void";
  } else if (I->getOpcode() == Instruction::Call) {
    writeOperand(Operand, true);
    Out << "(";
    if (I->getNumOperands() > 1) writeOperand(I->getOperand(1), true);
    for (unsigned op = 2, Eop = I->getNumOperands(); op < Eop; ++op) {
      Out << ",";
      writeOperand(I->getOperand(op), true);
    }

    Out << " )";
  } else if (I->getOpcode() == Instruction::Malloc ||
	     I->getOpcode() == Instruction::Alloca) {
    Out << " " << ((const PointerType*)I->getType())->getValueType();
    if (I->getNumOperands()) {
      Out << ",";
      writeOperand(I->getOperand(0), true);
    }
  } else if (I->getOpcode() == Instruction::Cast) {
    writeOperand(Operand, true);
    Out << " to " << I->getType();
  } else if (Operand) {   // Print the normal way...

    // PrintAllTypes - Instructions who have operands of all the same type
    // omit the type from all but the first operand.  If the instruction has
    // different type operands (for example br), then they are all printed.
    bool PrintAllTypes = false;
    const Type *TheType = Operand->getType();

    for (unsigned i = 1, E = I->getNumOperands(); i != E; ++i) {
      Operand = I->getOperand(i);
      if (Operand->getType() != TheType) {
	PrintAllTypes = true;       // We have differing types!  Print them all!
	break;
      }
    }

    if (!PrintAllTypes)
      Out << " " << I->getOperand(0)->getType();

    for (unsigned i = 0, E = I->getNumOperands(); i != E; ++i) {
      if (i) Out << ",";
      writeOperand(I->getOperand(i), PrintAllTypes);
    }
  }

  // Print a little comment after the instruction indicating which slot it
  // occupies.
  //
  if (I->getType() != Type::VoidTy) {
    Out << "\t\t; <" << I->getType() << ">";

    if (!I->hasName()) {
      int Slot = Table.getValSlot(I); // Print out the def slot taken...
      if (Slot >= 0) Out << ":" << Slot;
      else Out << ":<badref>";
    }
    Out << "\t[#uses=" << I->use_size() << "]";  // Output # uses
  }
  Out << endl;

  return false;
}

void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType,
				  bool PrintName) {
  if (PrintType)
    Out << " " << Operand->getType();

  if (Operand->hasName() && PrintName) {
    Out << " %" << Operand->getName();
  } else {
    int Slot = Table.getValSlot(Operand);

    if (const ConstPoolVal *CPV = Operand->castConstant()) {
      Out << " " << CPV->getStrValue();
    } else {
      if (Slot >= 0)  Out << " %" << Slot;
      else if (PrintName)
        Out << "<badref>";     // Not embeded into a location?
    }
  }
}

//===----------------------------------------------------------------------===//
//                       External Interface declarations
//===----------------------------------------------------------------------===//

void WriteToAssembly(const Module *M, ostream &o) {
  if (M == 0) { o << "<null> module\n"; return; }
  SlotCalculator SlotTable(M, true);
  AssemblyWriter W(o, SlotTable);

  W.write(M);
}

void WriteToAssembly(const Method *M, ostream &o) {
  if (M == 0) { o << "<null> method\n"; return; }
  SlotCalculator SlotTable(M->getParent(), true);
  AssemblyWriter W(o, SlotTable);

  W.write(M);
}

void WriteToAssembly(const BasicBlock *BB, ostream &o) {
  if (BB == 0) { o << "<null> basic block\n"; return; }

  SlotCalculator SlotTable(BB->getParent(), true);
  AssemblyWriter W(o, SlotTable);

  W.write(BB);
}

void WriteToAssembly(const ConstPoolVal *CPV, ostream &o) {
  if (CPV == 0) { o << "<null> constant pool value\n"; return; }

  SlotCalculator *SlotTable;

  // A Constant pool value may have a parent that is either a method or a
  // module.  Untangle this now...
  //
  if (CPV->getParent() == 0 || CPV->getParent()->isMethod()) {
    SlotTable = new SlotCalculator((Method*)CPV->getParent(), true);
  } else {
    SlotTable =
      new SlotCalculator(CPV->getParent()->castModuleAsserting(), true);
  }

  AssemblyWriter W(o, *SlotTable);
  W.write(CPV);

  delete SlotTable;
}

void WriteToAssembly(const Instruction *I, ostream &o) {
  if (I == 0) { o << "<null> instruction\n"; return; }

  SlotCalculator SlotTable(I->getParent() ? I->getParent()->getParent() : 0,
			   true);
  AssemblyWriter W(o, SlotTable);

  W.write(I);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/lib/cpp2/Object.h>
#include <thrift/lib/cpp2/frozen/FrozenUtil.h>
#include <thrift/lib/cpp2/protocol/Serializer.h>
#include <thrift/lib/cpp2/test/Structs.h>

#include <glog/logging.h>
#include <folly/Benchmark.h>
#include <folly/Optional.h>
#include <folly/portability/GFlags.h>

#include <vector>

using namespace std;
using namespace folly;
using namespace apache::thrift;
using namespace thrift::benchmark;

template <class>
struct SerializerTraits;
template <class ReaderType, class WriterType>
struct SerializerTraits<Serializer<ReaderType, WriterType>> {
  using Reader = ReaderType;
  using Writer = WriterType;
};

template <class T>
using GetReader = typename SerializerTraits<T>::Reader;
template <class T>
using GetWriter = typename SerializerTraits<T>::Writer;

struct FrozenSerializer {
  template <class T>
  static void serialize(const T& obj, folly::IOBufQueue* out) {
    auto p = new string(frozen::freezeToString(obj));
    out->append(folly::IOBuf::takeOwnership(
        p->data(),
        p->size(),
        [](void*, void* p) { delete static_cast<string*>(p); },
        static_cast<void*>(p)));
  }
  template <class T>
  static size_t deserialize(folly::IOBuf* iobuf, T& t) {
    auto view = frozen::mapFrozen<T>(iobuf->coalesce());
    t = view.thaw();
    return 0;
  }
};

enum class SerializerMethod {
  Codegen,
  Object,
};

// The benckmark is to measure single struct use case, the iteration here is
// more like a benchmark artifact, so avoid doing optimizationon iteration
// usecase in this benchmark (e.g. move string definition out of while loop)

template <
    SerializerMethod kSerializerMethod,
    typename Serializer,
    typename Struct,
    typename Counter>
void writeBench(size_t iters, Counter&&) {
  BenchmarkSuspender susp;
  auto strct = create<Struct>();
  protocol::Object obj;
  if constexpr (kSerializerMethod == SerializerMethod::Object) {
    IOBufQueue q;
    Serializer::serialize(strct, &q);
    obj = protocol::parseObject<GetReader<Serializer>>(*q.move());
  }
  susp.dismiss();

  while (iters--) {
    if constexpr (kSerializerMethod == SerializerMethod::Object) {
      auto q = protocol::serializeObject<GetWriter<Serializer>>(obj);
    } else {
      IOBufQueue q;
      Serializer::serialize(strct, &q);
    }
  }
  susp.rehire();
}

template <
    SerializerMethod kSerializerMethod,
    typename Serializer,
    typename Struct,
    typename Counter>
void readBench(size_t iters, Counter&& counter) {
  BenchmarkSuspender susp;
  auto strct = create<Struct>();
  IOBufQueue q;
  Serializer::serialize(strct, &q);
  auto buf = q.move();
  // coalesce the IOBuf chain to test fast path
  buf->coalesce();
  susp.dismiss();

  while (iters--) {
    if constexpr (kSerializerMethod == SerializerMethod::Object) {
      auto obj = protocol::parseObject<GetReader<Serializer>>(*buf);
    } else {
      Struct data;
      Serializer::deserialize(buf.get(), data);
    }
  }
  susp.rehire();
  counter["serialized_size"] = buf->computeChainDataLength();
}

constexpr SerializerMethod getSerializerMethod(std::string_view prefix) {
  return prefix == "" ? SerializerMethod::Codegen
      : prefix == "Object"
      ? SerializerMethod::Object
      : throw std::invalid_argument(std::string(prefix) + " is invalid");
}

#define X1(Prefix, proto, rdwr, bench)                                   \
  BENCHMARK_COUNTERS(                                                    \
      Prefix##proto##Protocol_##rdwr##_##bench, counter, iters) {        \
    rdwr##Bench<getSerializerMethod(#Prefix), proto##Serializer, bench>( \
        iters, counter);                                                 \
  }

#define X2(Prefix, proto, bench)  \
  X1(Prefix, proto, write, bench) \
  X1(Prefix, proto, read, bench)

#define X(Prefix, proto)             \
  X2(Prefix, proto, Empty)           \
  X2(Prefix, proto, SmallInt)        \
  X2(Prefix, proto, BigInt)          \
  X2(Prefix, proto, SmallString)     \
  X2(Prefix, proto, BigString)       \
  X2(Prefix, proto, BigBinary)       \
  X2(Prefix, proto, LargeBinary)     \
  X2(Prefix, proto, Mixed)           \
  X2(Prefix, proto, MixedInt)        \
  X2(Prefix, proto, SmallListInt)    \
  X2(Prefix, proto, BigListInt)      \
  X2(Prefix, proto, BigListMixed)    \
  X2(Prefix, proto, BigListMixedInt) \
  X2(Prefix, proto, LargeListMixed)  \
  X2(Prefix, proto, LargeMapInt)     \
  X2(Prefix, proto, NestedMap)       \
  X2(Prefix, proto, ComplexStruct)

X(, Binary)
X(, Compact)
X(, SimpleJSON)
X(, JSON)
X(, Frozen)
X(Object, Binary)
X(Object, Compact)

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  runBenchmarks();
  return 0;
}
<commit_msg>call folly::init in ProtocolBench benchmark code<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/lib/cpp2/Object.h>
#include <thrift/lib/cpp2/frozen/FrozenUtil.h>
#include <thrift/lib/cpp2/protocol/Serializer.h>
#include <thrift/lib/cpp2/test/Structs.h>

#include <glog/logging.h>
#include <folly/Benchmark.h>
#include <folly/Optional.h>
#include <folly/init/Init.h>
#include <folly/portability/GFlags.h>

#include <vector>

using namespace std;
using namespace folly;
using namespace apache::thrift;
using namespace thrift::benchmark;

template <class>
struct SerializerTraits;
template <class ReaderType, class WriterType>
struct SerializerTraits<Serializer<ReaderType, WriterType>> {
  using Reader = ReaderType;
  using Writer = WriterType;
};

template <class T>
using GetReader = typename SerializerTraits<T>::Reader;
template <class T>
using GetWriter = typename SerializerTraits<T>::Writer;

struct FrozenSerializer {
  template <class T>
  static void serialize(const T& obj, folly::IOBufQueue* out) {
    auto p = new string(frozen::freezeToString(obj));
    out->append(folly::IOBuf::takeOwnership(
        p->data(),
        p->size(),
        [](void*, void* p) { delete static_cast<string*>(p); },
        static_cast<void*>(p)));
  }
  template <class T>
  static size_t deserialize(folly::IOBuf* iobuf, T& t) {
    auto view = frozen::mapFrozen<T>(iobuf->coalesce());
    t = view.thaw();
    return 0;
  }
};

enum class SerializerMethod {
  Codegen,
  Object,
};

// The benckmark is to measure single struct use case, the iteration here is
// more like a benchmark artifact, so avoid doing optimizationon iteration
// usecase in this benchmark (e.g. move string definition out of while loop)

template <
    SerializerMethod kSerializerMethod,
    typename Serializer,
    typename Struct,
    typename Counter>
void writeBench(size_t iters, Counter&&) {
  BenchmarkSuspender susp;
  auto strct = create<Struct>();
  protocol::Object obj;
  if constexpr (kSerializerMethod == SerializerMethod::Object) {
    IOBufQueue q;
    Serializer::serialize(strct, &q);
    obj = protocol::parseObject<GetReader<Serializer>>(*q.move());
  }
  susp.dismiss();

  while (iters--) {
    if constexpr (kSerializerMethod == SerializerMethod::Object) {
      auto q = protocol::serializeObject<GetWriter<Serializer>>(obj);
    } else {
      IOBufQueue q;
      Serializer::serialize(strct, &q);
    }
  }
  susp.rehire();
}

template <
    SerializerMethod kSerializerMethod,
    typename Serializer,
    typename Struct,
    typename Counter>
void readBench(size_t iters, Counter&& counter) {
  BenchmarkSuspender susp;
  auto strct = create<Struct>();
  IOBufQueue q;
  Serializer::serialize(strct, &q);
  auto buf = q.move();
  // coalesce the IOBuf chain to test fast path
  buf->coalesce();
  susp.dismiss();

  while (iters--) {
    if constexpr (kSerializerMethod == SerializerMethod::Object) {
      auto obj = protocol::parseObject<GetReader<Serializer>>(*buf);
    } else {
      Struct data;
      Serializer::deserialize(buf.get(), data);
    }
  }
  susp.rehire();
  counter["serialized_size"] = buf->computeChainDataLength();
}

constexpr SerializerMethod getSerializerMethod(std::string_view prefix) {
  return prefix == "" ? SerializerMethod::Codegen
      : prefix == "Object"
      ? SerializerMethod::Object
      : throw std::invalid_argument(std::string(prefix) + " is invalid");
}

#define X1(Prefix, proto, rdwr, bench)                                   \
  BENCHMARK_COUNTERS(                                                    \
      Prefix##proto##Protocol_##rdwr##_##bench, counter, iters) {        \
    rdwr##Bench<getSerializerMethod(#Prefix), proto##Serializer, bench>( \
        iters, counter);                                                 \
  }

#define X2(Prefix, proto, bench)  \
  X1(Prefix, proto, write, bench) \
  X1(Prefix, proto, read, bench)

#define X(Prefix, proto)             \
  X2(Prefix, proto, Empty)           \
  X2(Prefix, proto, SmallInt)        \
  X2(Prefix, proto, BigInt)          \
  X2(Prefix, proto, SmallString)     \
  X2(Prefix, proto, BigString)       \
  X2(Prefix, proto, BigBinary)       \
  X2(Prefix, proto, LargeBinary)     \
  X2(Prefix, proto, Mixed)           \
  X2(Prefix, proto, MixedInt)        \
  X2(Prefix, proto, SmallListInt)    \
  X2(Prefix, proto, BigListInt)      \
  X2(Prefix, proto, BigListMixed)    \
  X2(Prefix, proto, BigListMixedInt) \
  X2(Prefix, proto, LargeListMixed)  \
  X2(Prefix, proto, LargeMapInt)     \
  X2(Prefix, proto, NestedMap)       \
  X2(Prefix, proto, ComplexStruct)

X(, Binary)
X(, Compact)
X(, SimpleJSON)
X(, JSON)
X(, Frozen)
X(Object, Binary)
X(Object, Compact)

int main(int argc, char** argv) {
  folly::Init init(&argc, &argv);
  runBenchmarks();
  return 0;
}
<|endoftext|>


<commit_before>#include "context.h"
#include "runtime.h"
#include "value.h"
#include "function_arguments.h"

// The class of the global object.
static JSClass globalClass = {
    "global",
    JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub,
    JS_DeletePropertyStub,
    JS_PropertyStub,
    JS_StrictPropertyStub,
    JS_EnumerateStub,
    JS_ResolveStub,
    JS_ConvertStub,
    nullptr, nullptr, nullptr, nullptr,
    JS_GlobalObjectTraceHook
};

rs::jsapi::Context::Context(Runtime& rt) :
        cx_(JS_NewContext(rt.getRuntime(), 8192)),
        global_(cx_, JS_NewGlobalObject(cx_, &globalClass, nullptr, JS::DontFireOnNewGlobalHook)),
        oldCompartment_(nullptr) {
    oldCompartment_ = JS_EnterCompartment(cx_, global_);
    JS_InitStandardClasses(cx_, global_);

    JS_SetContextPrivate(cx_, this);
    JS_SetErrorReporter(cx_, &ReportError);
}

rs::jsapi::Context::~Context() {
    DestroyContext();
}

void rs::jsapi::Context::ReportError(JSContext* cx, const char* message, JSErrorReport* report) {
    auto that = static_cast<Context*>(JS_GetContextPrivate(cx));
    if (that != nullptr) {
        that->exception_.reset(new ScriptException(message, report));
    }
}

std::unique_ptr<rs::jsapi::ScriptException> rs::jsapi::Context::getError() {
    return std::move(exception_);
}

void rs::jsapi::Context::DestroyContext() {
    if (cx_) {
        JS_SetErrorReporter(cx_, nullptr);
        JS_SetContextPrivate(cx_, nullptr);

        JS_LeaveCompartment(cx_, oldCompartment_);
        oldCompartment_ = nullptr;

        JS_DestroyContext(cx_);
        cx_ = nullptr;
    }
}

bool rs::jsapi::Context::Evaluate(const char* script) {
    Value result(*this);
    return Evaluate(script, result);
}

bool rs::jsapi::Context::Evaluate(const char* script, Value& result) {
    JS::CompileOptions options(cx_);
    auto status = JS::Evaluate(cx_, global_, options, script, ::strlen(script), result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}

bool rs::jsapi::Context::Call(const char* name) {
    Value result(*this);
    return Call(name, result);
}

bool rs::jsapi::Context::Call(const char* name, Value& result) {
    auto status = JS_CallFunctionName(cx_, global_, name, JS::HandleValueArray::empty(), result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}

bool rs::jsapi::Context::Call(const char* name, const FunctionArguments& args) {
    Value result(*this);
    return Call(name, args, result);
}

bool rs::jsapi::Context::Call(const char* name, const FunctionArguments& args, Value& result) {
    auto status = JS_CallFunctionName(cx_, global_, name, args, result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}<commit_msg>Increase the context stack size to 32k<commit_after>#include "context.h"
#include "runtime.h"
#include "value.h"
#include "function_arguments.h"

// The class of the global object.
static JSClass globalClass = {
    "global",
    JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub,
    JS_DeletePropertyStub,
    JS_PropertyStub,
    JS_StrictPropertyStub,
    JS_EnumerateStub,
    JS_ResolveStub,
    JS_ConvertStub,
    nullptr, nullptr, nullptr, nullptr,
    JS_GlobalObjectTraceHook
};

rs::jsapi::Context::Context(Runtime& rt) :
        cx_(JS_NewContext(rt.getRuntime(), 32 * 1024)),
        global_(cx_, JS_NewGlobalObject(cx_, &globalClass, nullptr, JS::DontFireOnNewGlobalHook)),
        oldCompartment_(nullptr) {
    oldCompartment_ = JS_EnterCompartment(cx_, global_);
    JS_InitStandardClasses(cx_, global_);

    JS_SetContextPrivate(cx_, this);
    JS_SetErrorReporter(cx_, &ReportError);
}

rs::jsapi::Context::~Context() {
    DestroyContext();
}

void rs::jsapi::Context::ReportError(JSContext* cx, const char* message, JSErrorReport* report) {
    auto that = static_cast<Context*>(JS_GetContextPrivate(cx));
    if (that != nullptr) {
        that->exception_.reset(new ScriptException(message, report));
    }
}

std::unique_ptr<rs::jsapi::ScriptException> rs::jsapi::Context::getError() {
    return std::move(exception_);
}

void rs::jsapi::Context::DestroyContext() {
    if (cx_) {
        JS_SetErrorReporter(cx_, nullptr);
        JS_SetContextPrivate(cx_, nullptr);

        JS_LeaveCompartment(cx_, oldCompartment_);
        oldCompartment_ = nullptr;

        JS_DestroyContext(cx_);
        cx_ = nullptr;
    }
}

bool rs::jsapi::Context::Evaluate(const char* script) {
    Value result(*this);
    return Evaluate(script, result);
}

bool rs::jsapi::Context::Evaluate(const char* script, Value& result) {
    JS::CompileOptions options(cx_);
    auto status = JS::Evaluate(cx_, global_, options, script, ::strlen(script), result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}

bool rs::jsapi::Context::Call(const char* name) {
    Value result(*this);
    return Call(name, result);
}

bool rs::jsapi::Context::Call(const char* name, Value& result) {
    auto status = JS_CallFunctionName(cx_, global_, name, JS::HandleValueArray::empty(), result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}

bool rs::jsapi::Context::Call(const char* name, const FunctionArguments& args) {
    Value result(*this);
    return Call(name, args, result);
}

bool rs::jsapi::Context::Call(const char* name, const FunctionArguments& args, Value& result) {
    auto status = JS_CallFunctionName(cx_, global_, name, args, result);

    auto error = getError();
    if (!!error) {
        throw *error;
    }

    return status;
}<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright (C) 2004 David Faure <faure@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

// Test program for libkdepim/email.h
#include "email.h"

#include <kcmdlineargs.h>
#include <kapplication.h>
#include <kdebug.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

using namespace KPIM;

static bool check(const QString& txt, const QString& a, const QString& b)
{
  if (a == b) {
    kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
  }
  else {
    kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
    exit(1);
  }
  return true;
}

static bool checkGetNameAndEmail(const QString& input, const QString& expName, const QString& expEmail, bool expRetVal)
{
  QString name, email;
  bool retVal = KPIM::getNameAndMail(input, name, email);
  check( "getNameAndMail " + input + " retVal", retVal?"true":"false", expRetVal?"true":"false" );
  check( "getNameAndMail " + input + " name", name, expName );
  check( "getNameAndMail " + input + " email", email, expEmail );
  return true;
}

// convert this to a switch instead but hey, nothing speedy in here is needed but still.. it would be nice
static QString emailTestParseResultToString( EmailParseResult errorCode )
{
  if( errorCode == TooManyAts ) {
    return "TooManyAts";
  } else if( errorCode == TooFewAts ) {
    return "TooFewAts";
  } else if( errorCode == AddressEmpty ) {
    return "AddressEmpty";
  } else if( errorCode == MissingLocalPart ) {
    return "MissingLocalPart";
  } else if( errorCode == MissingDomainPart ) {
    return "MissingDomainPart";
  } else if( errorCode == UnbalancedParens ) {
    return "UnbalancedParens";
  } else if( errorCode == AddressOk ) {
    return "AddressOk";
  } else if( errorCode == UnclosedAngleAddr ) {
    return "UnclosedAngleAddr";
  } else if( errorCode == UnexpectedEnd ) {
    return "UnexpectedEnd";
  } else if( errorCode == UnopenedAngleAddr ) {
    return "UnopenedAngleAddr";
  }
  return "unknown errror code";
}

static QString simpleEmailTestParseResultToString( bool validEmail )
{
  if ( validEmail ) {
    return "true";
  }
  return "false";
}

static QString getEmailParseResultToString( QCString emailAddress )
{
  return QString( emailAddress );
}

static QString getSplitEmailParseResultToString( QStringList emailAddresses )
{
  return QString( emailAddresses.join( "," ) );
}

static bool checkIsValidEmailAddress( const QString& input, const QString&  expErrorCode )
{
  EmailParseResult errorCode = KPIM::isValidEmailAddress( input );
  QString errorC = emailTestParseResultToString( errorCode );
  check( "isValidEmailAddress " + input + " errorCode ", errorC , expErrorCode );
  return true;
}

static bool checkIsValidSimpleEmailAddress( const QString& input, const QString& expResult )
{
  bool validEmail = KPIM::isValidSimpleEmailAddress( input );
  QString result = simpleEmailTestParseResultToString( validEmail );
  check( "isValidSimpleEmailAddress " + input + " result ", result, expResult );
  return true;
}

static bool checkGetEmailAddress( const QString& input, const QString& expResult )
{
  QString emailAddress = KPIM::getEmailAddress( input );
  QString result = emailAddress;
  check( "getEmailAddress " + input + " result ", result, expResult );
  return true;
}

static bool checkSplitEmailAddrList( const QString& input, const QString& expResult )
{
  QStringList emailAddresses = KPIM::splitEmailAddrList( input );
  QString result = getSplitEmailParseResultToString( emailAddresses );
  check( "splitEmailAddrList " + input + " result ", result, expResult );
  return true;
}

int main(int argc, char *argv[])
{
  KApplication::disableAutoDcopRegistration();
  KCmdLineArgs::init( argc, argv, "testemail", 0, 0, 0, 0 );
  KApplication app( false, false );

  // Empty input
  checkGetNameAndEmail( QString::null, QString::null, QString::null, false );

  // Email only
  checkGetNameAndEmail( "faure@kde.org", QString::null, "faure@kde.org", false );

  // Normal case
  checkGetNameAndEmail( "David Faure <faure@kde.org>", "David Faure", "faure@kde.org", true );

  // Double-quotes
  checkGetNameAndEmail( "\"Faure, David\" <faure@kde.org>", "Faure, David", "faure@kde.org", true );
  checkGetNameAndEmail( "<faure@kde.org> \"David Faure\"", "David Faure", "faure@kde.org", true );

  // Parenthesis
  checkGetNameAndEmail( "faure@kde.org (David Faure)", "David Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "(David Faure) faure@kde.org", "David Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "My Name (me) <me@home.net>", "My Name (me)", "me@home.net", true ); // #93513

  // Double-quotes inside parenthesis
  checkGetNameAndEmail( "faure@kde.org (David \"Crazy\" Faure)", "David \"Crazy\" Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "(David \"Crazy\" Faure) faure@kde.org", "David \"Crazy\" Faure", "faure@kde.org", true );

  // Parenthesis inside double-quotes
  checkGetNameAndEmail( "\"Faure (David)\" <faure@kde.org>", "Faure (David)", "faure@kde.org", true );
  checkGetNameAndEmail( "<faure@kde.org> \"Faure (David)\"", "Faure (David)", "faure@kde.org", true );

  // Space in email
  checkGetNameAndEmail( "David Faure < faure@kde.org >", "David Faure", "faure@kde.org", true );

  // Check that '@' in name doesn't confuse it
  checkGetNameAndEmail( "faure@kde.org (a@b)", "a@b", "faure@kde.org", true );
  // Interestingly, this isn't supported.
  //checkGetNameAndEmail( "\"a@b\" <faure@kde.org>", "a@b", "faure@kde.org", true );

  // While typing, when there's no '@' yet
  checkGetNameAndEmail( "foo", "foo", QString::null, false );
  checkGetNameAndEmail( "foo <", "foo", QString::null, false );
  checkGetNameAndEmail( "foo <b", "foo", "b", true );

  // If multiple emails are there, only return the first one
  checkGetNameAndEmail( "\"Faure, David\" <faure@kde.org>, KHZ <khz@khz.khz>", "Faure, David", "faure@kde.org", true );

  // domain literals also need to work
  checkGetNameAndEmail( "Matt Douhan <matt@[123.123.123.123]>", "Matt Douhan", "matt@[123.123.123.123]", true );

  // No '@'
  checkGetNameAndEmail(  "foo <distlist>", "foo", "distlist", true );

  // To many @'s
  checkIsValidEmailAddress( "matt@@fruitsalad.org", "TooManyAts" );

  // To few @'s
  checkIsValidEmailAddress( "mattfruitsalad.org", "TooFewAts" );

  // An empty string
  checkIsValidEmailAddress( QString::null , "AddressEmpty" );

  // email address starting with a @
  checkIsValidEmailAddress( "@mattfruitsalad.org", "MissingLocalPart" );

  // make sure that starting @ and an additional @ in the same email address don't conflict
  // trap the starting @ first and break
  checkIsValidEmailAddress( "@matt@fruitsalad.org", "MissingLocalPart" );

  // email address ending with a @
  checkIsValidEmailAddress( "mattfruitsalad.org@", "MissingDomainPart" );

  // make sure that ending with@ and an additional @ in the email address don't conflict
  checkIsValidEmailAddress( "matt@fruitsalad.org@", "MissingDomainPart" );

  // unbalanced Parens
  checkIsValidEmailAddress( "mattjongel)@fruitsalad.org", "UnbalancedParens" );

  // unbalanced Parens the other way around
  checkIsValidEmailAddress( "mattjongel(@fruitsalad.org", "UnbalancedParens" );

  // Correct parens just to make sure it works
  checkIsValidEmailAddress( "matt(jongel)@fruitsalad.org", "AddressOk" );

  // Check that anglebrackets are closed
  checkIsValidEmailAddress( "matt douhan<matt@fruitsalad.org", "UnclosedAngleAddr" );

  // Check that angle brackets are closed the other way around
  checkIsValidEmailAddress( "matt douhan>matt@fruitsalad.org", "UnopenedAngleAddr" );

  // Check that angle brackets are closed the other way around, and anglebrackets in domainpart
  // instead of local part
  // checkIsValidEmailAddress( "matt douhanmatt@<fruitsalad.org", "UnclosedAngleAddr" );

  // check that a properly formated anglebrackets situation is OK
  checkIsValidEmailAddress( "matt douhan<matt@fruitsalad.org>", "AddressOk" );

  // a full email address with comments angle brackets and the works should be valid too
  checkIsValidEmailAddress( "Matt (jongel) Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Double quotes
  checkIsValidEmailAddress( "\"Matt Douhan\" <matt@fruitsalad.org>", "AddressOk" );

  // Double quotes inside parens
  checkIsValidEmailAddress( "Matt (\"jongel\") Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Parens inside double quotes
  checkIsValidEmailAddress( "Matt \"(jongel)\" Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Space in email
  checkIsValidEmailAddress( "Matt Douhan < matt@fruitsalad.org >", "AddressOk" );

  // @ is allowed inisde doublequotes
  checkIsValidEmailAddress( "\"matt@jongel\" <matt@fruitsalad.org>", "AddressOk" );

  // anglebrackets inside dbl quotes
  checkIsValidEmailAddress( "\"matt<blah blah>\" <matt@fruitsalad.org>", "AddressOk" );

  // a , inside a double quoted string is OK, how do I know this? well Ingo says so
  // and it makes sense since it is also a seperator of email addresses
  checkIsValidEmailAddress( "\"Douhan, Matt\" <matt@fruitsalad.org>", "AddressOk" );

  // Domains literals also need to work
  checkIsValidEmailAddress( "Matt Douhan <matt@[123.123.123.123]>", "AddressOk" );

  // Some more insane tests but still valid so they must work
  checkIsValidEmailAddress( "Matt Douhan <\"m@att\"@jongel.com>", "AddressOk" );

  // checks for "pure" email addresses in the form of xxx@yyy.tld
  checkIsValidSimpleEmailAddress( "matt@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( QString::fromUtf8("test@täst.invalid"), "true" );
  // non-ASCII char as first char of IDN
  checkIsValidSimpleEmailAddress( QString::fromUtf8("i_want@øl.invalid"), "true" );
  checkIsValidSimpleEmailAddress( "matt@[123.123.123.123]", "true" );
  checkIsValidSimpleEmailAddress( "\"matt\"@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( "-matt@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( "\"-matt\"@fruitsalad.org", "true" );

  // check if the pure email address is wrong
  checkIsValidSimpleEmailAddress( "mattfruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( "matt@[123.123.123.123", "false" );
  checkIsValidSimpleEmailAddress( "matt@123.123.123.123]", "false" );
  checkIsValidSimpleEmailAddress( "\"matt@fruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( "matt\"@fruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( QString::null, "false" );

  // and here some insane but still valid cases
  checkIsValidSimpleEmailAddress( "\"m@tt\"@fruitsalad.org", "true" );

  // check the getEmailAddress address method
  checkGetEmailAddress( "matt@fruitsalad.org", "matt@fruitsalad.org" );
  checkGetEmailAddress( "Matt Douhan <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan <blah blah>\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt <blah blah>\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "Matt Douhan (jongel) <matt@fruitsalad.org", QString() );
  checkGetEmailAddress( "Matt Douhan (m@tt) <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Douhan, Matt\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan (m@tt)\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan\" (matt <matt@fruitsalad.org>", QString() );
  checkGetEmailAddress( "Matt Douhan <matt@[123.123.123.123]>", "matt@[123.123.123.123]" );

  // check the splitEmailAddrList method
  checkSplitEmailAddrList( "Matt Douhan <matt@fruitsalad.org>, Foo Bar <foo@bar.com>", "Matt Douhan <matt@fruitsalad.org>,Foo Bar <foo@bar.com>" );
  checkSplitEmailAddrList( "\"Matt, Douhan\" <matt@fruitsalad.org>, Foo Bar <foo@bar.com>", "\"Matt, Douhan\" <matt@fruitsalad.org>,Foo Bar <foo@bar.com>" );

  printf("\nTest OK !\n");

  return 0;
}

<commit_msg>Make sure that the isValidSImpleEmail method does not allow proper "full" email addresses, i,e "Matt Douhan" <matt@foo.tld>" is a valid "full" email address but not a valid "simple" email address.<commit_after>/* This file is part of the KDE project
   Copyright (C) 2004 David Faure <faure@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

// Test program for libkdepim/email.h
#include "email.h"

#include <kcmdlineargs.h>
#include <kapplication.h>
#include <kdebug.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

using namespace KPIM;

static bool check(const QString& txt, const QString& a, const QString& b)
{
  if (a == b) {
    kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
  }
  else {
    kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
    exit(1);
  }
  return true;
}

static bool checkGetNameAndEmail(const QString& input, const QString& expName, const QString& expEmail, bool expRetVal)
{
  QString name, email;
  bool retVal = KPIM::getNameAndMail(input, name, email);
  check( "getNameAndMail " + input + " retVal", retVal?"true":"false", expRetVal?"true":"false" );
  check( "getNameAndMail " + input + " name", name, expName );
  check( "getNameAndMail " + input + " email", email, expEmail );
  return true;
}

// convert this to a switch instead but hey, nothing speedy in here is needed but still.. it would be nice
static QString emailTestParseResultToString( EmailParseResult errorCode )
{
  if( errorCode == TooManyAts ) {
    return "TooManyAts";
  } else if( errorCode == TooFewAts ) {
    return "TooFewAts";
  } else if( errorCode == AddressEmpty ) {
    return "AddressEmpty";
  } else if( errorCode == MissingLocalPart ) {
    return "MissingLocalPart";
  } else if( errorCode == MissingDomainPart ) {
    return "MissingDomainPart";
  } else if( errorCode == UnbalancedParens ) {
    return "UnbalancedParens";
  } else if( errorCode == AddressOk ) {
    return "AddressOk";
  } else if( errorCode == UnclosedAngleAddr ) {
    return "UnclosedAngleAddr";
  } else if( errorCode == UnexpectedEnd ) {
    return "UnexpectedEnd";
  } else if( errorCode == UnopenedAngleAddr ) {
    return "UnopenedAngleAddr";
  }
  return "unknown errror code";
}

static QString simpleEmailTestParseResultToString( bool validEmail )
{
  if ( validEmail ) {
    return "true";
  }
  return "false";
}

static QString getEmailParseResultToString( QCString emailAddress )
{
  return QString( emailAddress );
}

static QString getSplitEmailParseResultToString( QStringList emailAddresses )
{
  return QString( emailAddresses.join( "," ) );
}

static bool checkIsValidEmailAddress( const QString& input, const QString&  expErrorCode )
{
  EmailParseResult errorCode = KPIM::isValidEmailAddress( input );
  QString errorC = emailTestParseResultToString( errorCode );
  check( "isValidEmailAddress " + input + " errorCode ", errorC , expErrorCode );
  return true;
}

static bool checkIsValidSimpleEmailAddress( const QString& input, const QString& expResult )
{
  bool validEmail = KPIM::isValidSimpleEmailAddress( input );
  QString result = simpleEmailTestParseResultToString( validEmail );
  check( "isValidSimpleEmailAddress " + input + " result ", result, expResult );
  return true;
}

static bool checkGetEmailAddress( const QString& input, const QString& expResult )
{
  QString emailAddress = KPIM::getEmailAddress( input );
  QString result = emailAddress;
  check( "getEmailAddress " + input + " result ", result, expResult );
  return true;
}

static bool checkSplitEmailAddrList( const QString& input, const QString& expResult )
{
  QStringList emailAddresses = KPIM::splitEmailAddrList( input );
  QString result = getSplitEmailParseResultToString( emailAddresses );
  check( "splitEmailAddrList " + input + " result ", result, expResult );
  return true;
}

int main(int argc, char *argv[])
{
  KApplication::disableAutoDcopRegistration();
  KCmdLineArgs::init( argc, argv, "testemail", 0, 0, 0, 0 );
  KApplication app( false, false );

  // Empty input
  checkGetNameAndEmail( QString::null, QString::null, QString::null, false );

  // Email only
  checkGetNameAndEmail( "faure@kde.org", QString::null, "faure@kde.org", false );

  // Normal case
  checkGetNameAndEmail( "David Faure <faure@kde.org>", "David Faure", "faure@kde.org", true );

  // Double-quotes
  checkGetNameAndEmail( "\"Faure, David\" <faure@kde.org>", "Faure, David", "faure@kde.org", true );
  checkGetNameAndEmail( "<faure@kde.org> \"David Faure\"", "David Faure", "faure@kde.org", true );

  // Parenthesis
  checkGetNameAndEmail( "faure@kde.org (David Faure)", "David Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "(David Faure) faure@kde.org", "David Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "My Name (me) <me@home.net>", "My Name (me)", "me@home.net", true ); // #93513

  // Double-quotes inside parenthesis
  checkGetNameAndEmail( "faure@kde.org (David \"Crazy\" Faure)", "David \"Crazy\" Faure", "faure@kde.org", true );
  checkGetNameAndEmail( "(David \"Crazy\" Faure) faure@kde.org", "David \"Crazy\" Faure", "faure@kde.org", true );

  // Parenthesis inside double-quotes
  checkGetNameAndEmail( "\"Faure (David)\" <faure@kde.org>", "Faure (David)", "faure@kde.org", true );
  checkGetNameAndEmail( "<faure@kde.org> \"Faure (David)\"", "Faure (David)", "faure@kde.org", true );

  // Space in email
  checkGetNameAndEmail( "David Faure < faure@kde.org >", "David Faure", "faure@kde.org", true );

  // Check that '@' in name doesn't confuse it
  checkGetNameAndEmail( "faure@kde.org (a@b)", "a@b", "faure@kde.org", true );
  // Interestingly, this isn't supported.
  //checkGetNameAndEmail( "\"a@b\" <faure@kde.org>", "a@b", "faure@kde.org", true );

  // While typing, when there's no '@' yet
  checkGetNameAndEmail( "foo", "foo", QString::null, false );
  checkGetNameAndEmail( "foo <", "foo", QString::null, false );
  checkGetNameAndEmail( "foo <b", "foo", "b", true );

  // If multiple emails are there, only return the first one
  checkGetNameAndEmail( "\"Faure, David\" <faure@kde.org>, KHZ <khz@khz.khz>", "Faure, David", "faure@kde.org", true );

  // domain literals also need to work
  checkGetNameAndEmail( "Matt Douhan <matt@[123.123.123.123]>", "Matt Douhan", "matt@[123.123.123.123]", true );

  // No '@'
  checkGetNameAndEmail(  "foo <distlist>", "foo", "distlist", true );

  // To many @'s
  checkIsValidEmailAddress( "matt@@fruitsalad.org", "TooManyAts" );

  // To few @'s
  checkIsValidEmailAddress( "mattfruitsalad.org", "TooFewAts" );

  // An empty string
  checkIsValidEmailAddress( QString::null , "AddressEmpty" );

  // email address starting with a @
  checkIsValidEmailAddress( "@mattfruitsalad.org", "MissingLocalPart" );

  // make sure that starting @ and an additional @ in the same email address don't conflict
  // trap the starting @ first and break
  checkIsValidEmailAddress( "@matt@fruitsalad.org", "MissingLocalPart" );

  // email address ending with a @
  checkIsValidEmailAddress( "mattfruitsalad.org@", "MissingDomainPart" );

  // make sure that ending with@ and an additional @ in the email address don't conflict
  checkIsValidEmailAddress( "matt@fruitsalad.org@", "MissingDomainPart" );

  // unbalanced Parens
  checkIsValidEmailAddress( "mattjongel)@fruitsalad.org", "UnbalancedParens" );

  // unbalanced Parens the other way around
  checkIsValidEmailAddress( "mattjongel(@fruitsalad.org", "UnbalancedParens" );

  // Correct parens just to make sure it works
  checkIsValidEmailAddress( "matt(jongel)@fruitsalad.org", "AddressOk" );

  // Check that anglebrackets are closed
  checkIsValidEmailAddress( "matt douhan<matt@fruitsalad.org", "UnclosedAngleAddr" );

  // Check that angle brackets are closed the other way around
  checkIsValidEmailAddress( "matt douhan>matt@fruitsalad.org", "UnopenedAngleAddr" );

  // Check that angle brackets are closed the other way around, and anglebrackets in domainpart
  // instead of local part
  // checkIsValidEmailAddress( "matt douhanmatt@<fruitsalad.org", "UnclosedAngleAddr" );

  // check that a properly formated anglebrackets situation is OK
  checkIsValidEmailAddress( "matt douhan<matt@fruitsalad.org>", "AddressOk" );

  // a full email address with comments angle brackets and the works should be valid too
  checkIsValidEmailAddress( "Matt (jongel) Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Double quotes
  checkIsValidEmailAddress( "\"Matt Douhan\" <matt@fruitsalad.org>", "AddressOk" );

  // Double quotes inside parens
  checkIsValidEmailAddress( "Matt (\"jongel\") Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Parens inside double quotes
  checkIsValidEmailAddress( "Matt \"(jongel)\" Douhan <matt@fruitsalad.org>", "AddressOk" );

  // Space in email
  checkIsValidEmailAddress( "Matt Douhan < matt@fruitsalad.org >", "AddressOk" );

  // @ is allowed inisde doublequotes
  checkIsValidEmailAddress( "\"matt@jongel\" <matt@fruitsalad.org>", "AddressOk" );

  // anglebrackets inside dbl quotes
  checkIsValidEmailAddress( "\"matt<blah blah>\" <matt@fruitsalad.org>", "AddressOk" );

  // a , inside a double quoted string is OK, how do I know this? well Ingo says so
  // and it makes sense since it is also a seperator of email addresses
  checkIsValidEmailAddress( "\"Douhan, Matt\" <matt@fruitsalad.org>", "AddressOk" );

  // Domains literals also need to work
  checkIsValidEmailAddress( "Matt Douhan <matt@[123.123.123.123]>", "AddressOk" );

  // Some more insane tests but still valid so they must work
  checkIsValidEmailAddress( "Matt Douhan <\"m@att\"@jongel.com>", "AddressOk" );

  // checks for "pure" email addresses in the form of xxx@yyy.tld
  checkIsValidSimpleEmailAddress( "matt@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( QString::fromUtf8("test@täst.invalid"), "true" );
  // non-ASCII char as first char of IDN
  checkIsValidSimpleEmailAddress( QString::fromUtf8("i_want@øl.invalid"), "true" );
  checkIsValidSimpleEmailAddress( "matt@[123.123.123.123]", "true" );
  checkIsValidSimpleEmailAddress( "\"matt\"@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( "-matt@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( "\"-matt\"@fruitsalad.org", "true" );
  checkIsValidSimpleEmailAddress( "Matt Douhan <matt@fruitsalad.org>", "false" );

  // check if the pure email address is wrong
  checkIsValidSimpleEmailAddress( "mattfruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( "matt@[123.123.123.123", "false" );
  checkIsValidSimpleEmailAddress( "matt@123.123.123.123]", "false" );
  checkIsValidSimpleEmailAddress( "\"matt@fruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( "matt\"@fruitsalad.org", "false" );
  checkIsValidSimpleEmailAddress( QString::null, "false" );

  // and here some insane but still valid cases
  checkIsValidSimpleEmailAddress( "\"m@tt\"@fruitsalad.org", "true" );

  // check the getEmailAddress address method
  checkGetEmailAddress( "matt@fruitsalad.org", "matt@fruitsalad.org" );
  checkGetEmailAddress( "Matt Douhan <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan <blah blah>\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt <blah blah>\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "Matt Douhan (jongel) <matt@fruitsalad.org", QString() );
  checkGetEmailAddress( "Matt Douhan (m@tt) <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Douhan, Matt\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan (m@tt)\" <matt@fruitsalad.org>", "matt@fruitsalad.org" );
  checkGetEmailAddress( "\"Matt Douhan\" (matt <matt@fruitsalad.org>", QString() );
  checkGetEmailAddress( "Matt Douhan <matt@[123.123.123.123]>", "matt@[123.123.123.123]" );

  // check the splitEmailAddrList method
  checkSplitEmailAddrList( "Matt Douhan <matt@fruitsalad.org>, Foo Bar <foo@bar.com>", "Matt Douhan <matt@fruitsalad.org>,Foo Bar <foo@bar.com>" );
  checkSplitEmailAddrList( "\"Matt, Douhan\" <matt@fruitsalad.org>, Foo Bar <foo@bar.com>", "\"Matt, Douhan\" <matt@fruitsalad.org>,Foo Bar <foo@bar.com>" );

  printf("\nTest OK !\n");

  return 0;
}

<|endoftext|>