tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

JitSpewer.cpp (20302B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifdef JS_JITSPEW
      8 
      9 #  include "jit/JitSpewer.h"
     10 
     11 #  include "mozilla/Atomics.h"
     12 #  include "mozilla/Sprintf.h"
     13 
     14 #  include "jit/MIR.h"
     15 #  include "jit/MIRGenerator.h"
     16 #  include "jit/MIRGraph.h"
     17 #  include "threading/LockGuard.h"
     18 #  include "util/GetPidProvider.h"  // getpid()
     19 #  include "vm/MutexIDs.h"
     20 
     21 #  ifndef JIT_SPEW_DIR
     22 #    if defined(_WIN32)
     23 #      define JIT_SPEW_DIR "."
     24 #    elif defined(__ANDROID__)
     25 #      define JIT_SPEW_DIR "/data/local/tmp"
     26 #    else
     27 #      define JIT_SPEW_DIR "/tmp"
     28 #    endif
     29 #  endif
     30 
     31 using namespace js;
     32 using namespace js::jit;
     33 using namespace js::jitspew::detail;
     34 
     35 class JitSpewGraphOutput {
     36 private:
     37  Mutex outputLock_ MOZ_UNANNOTATED;
     38  Fprinter jsonOutput_;
     39  GraphSpewer graphSpewer_;
     40  bool firstFunction_;
     41  bool asyncLogging_;
     42  bool inited_;
     43 
     44  void release();
     45 
     46 public:
     47  JitSpewGraphOutput()
     48      : outputLock_(mutexid::JitSpewGraphOutput),
     49        graphSpewer_(jsonOutput_),
     50        firstFunction_(false),
     51        asyncLogging_(false),
     52        inited_(false) {}
     53 
     54  // File output is terminated safely upon destruction.
     55  ~JitSpewGraphOutput();
     56 
     57  bool init();
     58  bool isEnabled() { return inited_; }
     59  void setAsyncLogging(bool incremental) { asyncLogging_ = incremental; }
     60  bool getAsyncLogging() { return asyncLogging_; }
     61 
     62  void beginFunction();
     63  void spewPass(JitSpewGraphSpewer* gs);
     64  void endFunction(JitSpewGraphSpewer* gs);
     65 };
     66 
     67 // JitSpewGraphOutput singleton.
     68 MOZ_RUNINIT static JitSpewGraphOutput jitSpewGraphOutput;
     69 
     70 bool jitspew::detail::LoggingChecked = false;
     71 static_assert(JitSpew_Terminator <= 64,
     72              "Increase the size of the LoggingBits global.");
     73 uint64_t jitspew::detail::LoggingBits = 0;
     74 mozilla::Atomic<uint32_t, mozilla::Relaxed>
     75    jitspew::detail::filteredOutCompilations(0);
     76 
     77 static const char* const ChannelNames[] = {
     78 #  define JITSPEW_CHANNEL(name) #name,
     79    JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL)
     80 #  undef JITSPEW_CHANNEL
     81 };
     82 
     83 static size_t ChannelIndentLevel[] = {
     84 #  define JITSPEW_CHANNEL(name) 0,
     85    JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL)
     86 #  undef JITSPEW_CHANNEL
     87 };
     88 
     89 // The IONFILTER environment variable specifies an expression to select only
     90 // certain functions for spewing to reduce amount of log data generated.
     91 static const char* gSpewFilter = nullptr;
     92 
     93 static bool FilterContainsLocation(JSScript* function) {
     94  // If there is no filter we accept all outputs.
     95  if (!gSpewFilter || !gSpewFilter[0]) {
     96    return true;
     97  }
     98 
     99  // Disable wasm output when filter is set.
    100  if (!function) {
    101    return false;
    102  }
    103 
    104  const char* filename = function->filename();
    105  const size_t line = function->lineno();
    106  const size_t filelen = strlen(filename);
    107  const char* index = strstr(gSpewFilter, filename);
    108  while (index) {
    109    if (index == gSpewFilter || index[-1] == ',') {
    110      if (index[filelen] == 0 || index[filelen] == ',') {
    111        return true;
    112      }
    113      if (index[filelen] == ':' && line != size_t(-1)) {
    114        size_t read_line = strtoul(&index[filelen + 1], nullptr, 10);
    115        if (read_line == line) {
    116          return true;
    117        }
    118      }
    119    }
    120    index = strstr(index + filelen, filename);
    121  }
    122  return false;
    123 }
    124 
    125 void jit::EnableIonDebugSyncLogging() {
    126  jitSpewGraphOutput.init();
    127  jitSpewGraphOutput.setAsyncLogging(false);
    128  EnableChannel(JitSpew_IonSyncLogs);
    129 }
    130 
    131 void jit::EnableIonDebugAsyncLogging() {
    132  jitSpewGraphOutput.init();
    133  jitSpewGraphOutput.setAsyncLogging(true);
    134 }
    135 
    136 void JitSpewGraphOutput::release() {
    137  if (jsonOutput_.isInitialized()) {
    138    jsonOutput_.finish();
    139  }
    140  inited_ = false;
    141 }
    142 
    143 bool JitSpewGraphOutput::init() {
    144  if (inited_) {
    145    return true;
    146  }
    147 
    148  // Filter expression for spewing
    149  gSpewFilter = getenv("IONFILTER");
    150 
    151  const size_t bufferLength = 256;
    152  char jsonBuffer[bufferLength];
    153  const char* jsonFilename = JIT_SPEW_DIR "/ion.json";
    154 
    155  const char* usePid = getenv("ION_SPEW_BY_PID");
    156  if (usePid && *usePid != 0) {
    157    uint32_t pid = getpid();
    158    size_t len;
    159    len = SprintfLiteral(jsonBuffer, JIT_SPEW_DIR "/ion%" PRIu32 ".json", pid);
    160    if (bufferLength <= len) {
    161      fprintf(stderr,
    162              "Warning: JitSpewGraphOutput::init: Cannot serialize file name.");
    163      return false;
    164    }
    165    jsonFilename = jsonBuffer;
    166  }
    167 
    168  if (!jsonOutput_.init(jsonFilename)) {
    169    release();
    170    return false;
    171  }
    172 
    173  graphSpewer_.begin();
    174  firstFunction_ = true;
    175 
    176  inited_ = true;
    177  return true;
    178 }
    179 
    180 void JitSpewGraphOutput::beginFunction() {
    181  // If we are doing a synchronous logging then we spew everything as we go,
    182  // as this is useful in case of failure during the compilation. On the other
    183  // hand, it is recommended to disable off thread compilation.
    184  if (!getAsyncLogging() && !firstFunction_) {
    185    LockGuard<Mutex> guard(outputLock_);
    186    jsonOutput_.put(",");  // separate functions
    187  }
    188 }
    189 
    190 void JitSpewGraphOutput::spewPass(JitSpewGraphSpewer* gs) {
    191  if (!getAsyncLogging()) {
    192    LockGuard<Mutex> guard(outputLock_);
    193    gs->dump(jsonOutput_);
    194  }
    195 }
    196 
    197 void JitSpewGraphOutput::endFunction(JitSpewGraphSpewer* gs) {
    198  LockGuard<Mutex> guard(outputLock_);
    199  if (getAsyncLogging() && !firstFunction_) {
    200    jsonOutput_.put(",");  // separate functions
    201  }
    202 
    203  gs->dump(jsonOutput_);
    204  firstFunction_ = false;
    205 }
    206 
    207 JitSpewGraphOutput::~JitSpewGraphOutput() {
    208  if (!inited_) {
    209    return;
    210  }
    211 
    212  graphSpewer_.end();
    213  release();
    214 }
    215 
    216 JitSpewGraphSpewer::JitSpewGraphSpewer(TempAllocator* alloc,
    217                                       const wasm::CodeMetadata* wasmCodeMeta)
    218    : graph_(nullptr),
    219      jsonPrinter_(alloc->lifoAlloc()),
    220      graphSpewer_(jsonPrinter_, wasmCodeMeta) {}
    221 
    222 void JitSpewGraphSpewer::init(MIRGraph* graph, JSScript* function) {
    223  MOZ_ASSERT(!isSpewing());
    224  if (!jitSpewGraphOutput.isEnabled()) {
    225    return;
    226  }
    227 
    228  if (!FilterContainsLocation(function)) {
    229    // filter out logs during the compilation.
    230    filteredOutCompilations++;
    231    MOZ_ASSERT(!isSpewing());
    232    return;
    233  }
    234 
    235  graph_ = graph;
    236  MOZ_ASSERT(isSpewing());
    237 }
    238 
    239 void JitSpewGraphSpewer::beginFunction(JSScript* function) {
    240  if (!isSpewing()) {
    241    return;
    242  }
    243  graphSpewer_.beginFunction(function);
    244  jitSpewGraphOutput.beginFunction();
    245 }
    246 
    247 void JitSpewGraphSpewer::beginWasmFunction(unsigned funcIndex) {
    248  if (!isSpewing()) {
    249    return;
    250  }
    251  graphSpewer_.beginWasmFunction(funcIndex);
    252  jitSpewGraphOutput.beginFunction();
    253 }
    254 
    255 void JitSpewGraphSpewer::spewPass(const char* pass, BacktrackingAllocator* ra) {
    256  if (!isSpewing()) {
    257    return;
    258  }
    259 
    260  graphSpewer_.spewPass(pass, graph_, ra);
    261  jitSpewGraphOutput.spewPass(this);
    262 
    263  // As this function is used for debugging, we ignore any of the previous
    264  // failures and ensure there is enough ballast space, such that we do not
    265  // exhaust the ballast space before running the next phase.
    266  AutoEnterOOMUnsafeRegion oomUnsafe;
    267  if (!graph_->alloc().ensureBallast()) {
    268    oomUnsafe.crash(
    269        "Could not ensure enough ballast space after spewing graph "
    270        "information.");
    271  }
    272 }
    273 
    274 void JitSpewGraphSpewer::endFunction() {
    275  if (!jitSpewGraphOutput.isEnabled()) {
    276    return;
    277  }
    278 
    279  if (!isSpewing()) {
    280    MOZ_ASSERT(filteredOutCompilations != 0);
    281    filteredOutCompilations--;
    282    return;
    283  }
    284 
    285  graphSpewer_.endFunction();
    286 
    287  jitSpewGraphOutput.endFunction(this);
    288  graph_ = nullptr;
    289 }
    290 
    291 void JitSpewGraphSpewer::dump(Fprinter& jsonOut) {
    292  if (!jsonPrinter_.hadOutOfMemory()) {
    293    jsonPrinter_.exportInto(jsonOut);
    294  } else {
    295    jsonOut.put("{}");
    296  }
    297  jsonOut.flush();
    298  jsonPrinter_.clear();
    299 }
    300 
    301 Fprinter& jit::JitSpewPrinter() {
    302  static Fprinter out;
    303  return out;
    304 }
    305 
    306 static void PrintHelpAndExit(int status = 0) {
    307  fflush(nullptr);
    308  printf(
    309      "\n"
    310      "usage: IONFLAGS=option,option,option,... where options can be:\n"
    311      "\n"
    312      "  aborts        Compilation abort messages\n"
    313      "  scripts       Compiled scripts\n"
    314      "  mir           MIR information\n"
    315      "  prune         Prune unused branches\n"
    316      "  escape        Escape analysis\n"
    317      "  alias         Alias analysis\n"
    318      "  alias-sum     Alias analysis: shows summaries for every block\n"
    319      "  gvn           Global Value Numbering\n"
    320      "  licm          Loop invariant code motion\n"
    321      "  flac          Fold linear arithmetic constants\n"
    322      "  eaa           Effective address analysis\n"
    323      "  sink          Sink transformation\n"
    324      "  regalloc      Register allocation\n"
    325      "  inline        Inlining\n"
    326      "  snapshots     Snapshot information\n"
    327      "  codegen       Native code generation\n"
    328      "  bailouts      Bailouts\n"
    329      "  caches        Inline caches\n"
    330      "  osi           Invalidation\n"
    331      "  safepoints    Safepoints\n"
    332      "  pools         Literal Pools (ARM only for now)\n"
    333      "  cacheflush    Instruction Cache flushes (ARM only for now)\n"
    334      "  range         Range Analysis\n"
    335      "  branch-hint   Wasm Branch Hinting\n"
    336      "  wasmbce       Wasm Bounds Check Elimination\n"
    337      "  shapeguards   Redundant shape guard elimination\n"
    338      "  gcbarriers    Redundant GC barrier elimination\n"
    339      "  loadkeys      Loads used as property keys\n"
    340      "  stubfolding   CacheIR stub folding\n"
    341      "  stubfolding-details   Same as stubfolding, but with spewing of stub "
    342      "content.\n"
    343      "  logs          JSON visualization logging\n"
    344      "  logs-sync     Same as logs, but flushes between each pass (sync. "
    345      "compiled functions only).\n"
    346      "  profiling     Profiling-related information\n"
    347      "  dump-mir-expr Dump the MIR expressions\n"
    348      "  unroll        Wasm loop unrolling and peeling -- summary info\n"
    349      "  unroll-details  Wasm loop unrolling and peeling -- details\n"
    350      "  warp-snapshots WarpSnapshots created by WarpOracle\n"
    351      "  warp-transpiler Warp CacheIR transpiler\n"
    352      "  warp-trial-inlining Trial inlining for Warp\n"
    353      "  all           Everything\n"
    354      "\n"
    355      "  bl-aborts     Baseline compiler abort messages\n"
    356      "  bl-scripts    Baseline script-compilation\n"
    357      "  bl-op         Baseline compiler detailed op-specific messages\n"
    358      "  bl-ic         Baseline inline-cache messages\n"
    359      "  bl-ic-fb      Baseline IC fallback stub messages\n"
    360      "  bl-osr        Baseline IC OSR messages\n"
    361      "  bl-bails      Baseline bailouts\n"
    362      "  bl-dbg-osr    Baseline debug mode on stack recompile messages\n"
    363      "  bl-all        All baseline spew\n"
    364      "\n"
    365      "See also SPEW=help for information on the Structured Spewer."
    366      "\n");
    367  exit(status);
    368 }
    369 
    370 static bool IsFlag(const char* found, const char* flag) {
    371  return strlen(found) == strlen(flag) && strcmp(found, flag) == 0;
    372 }
    373 
    374 void jit::CheckLogging() {
    375  if (LoggingChecked) {
    376    return;
    377  }
    378 
    379  LoggingChecked = true;
    380 
    381  char* env = getenv("IONFLAGS");
    382  if (!env) {
    383    return;
    384  }
    385 
    386  const char* found = strtok(env, ",");
    387  while (found) {
    388    fprintf(stderr, "found tag: %s\n", found);
    389    // We're at the end of a flag; check if the previous substring was a
    390    // known flag (i-1 is the last character of the flag we just read).
    391    if (IsFlag(found, "help")) {
    392      PrintHelpAndExit();
    393    } else if (IsFlag(found, "aborts")) {
    394      EnableChannel(JitSpew_IonAbort);
    395    } else if (IsFlag(found, "prune")) {
    396      EnableChannel(JitSpew_Prune);
    397    } else if (IsFlag(found, "escape")) {
    398      EnableChannel(JitSpew_Escape);
    399    } else if (IsFlag(found, "alias")) {
    400      EnableChannel(JitSpew_Alias);
    401    } else if (IsFlag(found, "alias-sum")) {
    402      EnableChannel(JitSpew_AliasSummaries);
    403    } else if (IsFlag(found, "scripts")) {
    404      EnableChannel(JitSpew_IonScripts);
    405    } else if (IsFlag(found, "mir")) {
    406      EnableChannel(JitSpew_IonMIR);
    407    } else if (IsFlag(found, "gvn")) {
    408      EnableChannel(JitSpew_GVN);
    409    } else if (IsFlag(found, "range")) {
    410      EnableChannel(JitSpew_Range);
    411    } else if (IsFlag(found, "wasmbce")) {
    412      EnableChannel(JitSpew_WasmBCE);
    413    } else if (IsFlag(found, "branch-hint")) {
    414      EnableChannel(JitSpew_BranchHint);
    415    } else if (IsFlag(found, "licm")) {
    416      EnableChannel(JitSpew_LICM);
    417    } else if (IsFlag(found, "flac")) {
    418      EnableChannel(JitSpew_FLAC);
    419    } else if (IsFlag(found, "eaa")) {
    420      EnableChannel(JitSpew_EAA);
    421    } else if (IsFlag(found, "sink")) {
    422      EnableChannel(JitSpew_Sink);
    423    } else if (IsFlag(found, "regalloc")) {
    424      EnableChannel(JitSpew_RegAlloc);
    425    } else if (IsFlag(found, "inline")) {
    426      EnableChannel(JitSpew_Inlining);
    427    } else if (IsFlag(found, "snapshots")) {
    428      EnableChannel(JitSpew_IonSnapshots);
    429    } else if (IsFlag(found, "codegen")) {
    430      EnableChannel(JitSpew_Codegen);
    431    } else if (IsFlag(found, "bailouts")) {
    432      EnableChannel(JitSpew_IonBailouts);
    433    } else if (IsFlag(found, "osi")) {
    434      EnableChannel(JitSpew_IonInvalidate);
    435    } else if (IsFlag(found, "caches")) {
    436      EnableChannel(JitSpew_IonIC);
    437    } else if (IsFlag(found, "safepoints")) {
    438      EnableChannel(JitSpew_Safepoints);
    439    } else if (IsFlag(found, "pools")) {
    440      EnableChannel(JitSpew_Pools);
    441    } else if (IsFlag(found, "cacheflush")) {
    442      EnableChannel(JitSpew_CacheFlush);
    443    } else if (IsFlag(found, "shapeguards")) {
    444      EnableChannel(JitSpew_RedundantShapeGuards);
    445    } else if (IsFlag(found, "gcbarriers")) {
    446      EnableChannel(JitSpew_RedundantGCBarriers);
    447    } else if (IsFlag(found, "loadkeys")) {
    448      EnableChannel(JitSpew_MarkLoadsUsedAsPropertyKeys);
    449    } else if (IsFlag(found, "stubfolding")) {
    450      EnableChannel(JitSpew_StubFolding);
    451    } else if (IsFlag(found, "stubfolding-details")) {
    452      EnableChannel(JitSpew_StubFolding);
    453      EnableChannel(JitSpew_StubFoldingDetails);
    454    } else if (IsFlag(found, "logs")) {
    455      EnableIonDebugAsyncLogging();
    456    } else if (IsFlag(found, "logs-sync")) {
    457      EnableIonDebugSyncLogging();
    458    } else if (IsFlag(found, "profiling")) {
    459      EnableChannel(JitSpew_Profiling);
    460    } else if (IsFlag(found, "dump-mir-expr")) {
    461      EnableChannel(JitSpew_MIRExpressions);
    462    } else if (IsFlag(found, "unroll")) {
    463      EnableChannel(JitSpew_Unroll);
    464    } else if (IsFlag(found, "unroll-details")) {
    465      EnableChannel(JitSpew_Unroll);
    466      EnableChannel(JitSpew_UnrollDetails);
    467    } else if (IsFlag(found, "warp-snapshots")) {
    468      EnableChannel(JitSpew_WarpSnapshots);
    469    } else if (IsFlag(found, "warp-transpiler")) {
    470      EnableChannel(JitSpew_WarpTranspiler);
    471    } else if (IsFlag(found, "warp-trial-inlining")) {
    472      EnableChannel(JitSpew_WarpTrialInlining);
    473    } else if (IsFlag(found, "all")) {
    474      LoggingBits = uint64_t(-1);
    475    } else if (IsFlag(found, "bl-aborts")) {
    476      EnableChannel(JitSpew_BaselineAbort);
    477    } else if (IsFlag(found, "bl-scripts")) {
    478      EnableChannel(JitSpew_BaselineScripts);
    479    } else if (IsFlag(found, "bl-op")) {
    480      EnableChannel(JitSpew_BaselineOp);
    481    } else if (IsFlag(found, "bl-ic")) {
    482      EnableChannel(JitSpew_BaselineIC);
    483    } else if (IsFlag(found, "bl-ic-fb")) {
    484      EnableChannel(JitSpew_BaselineICFallback);
    485    } else if (IsFlag(found, "bl-osr")) {
    486      EnableChannel(JitSpew_BaselineOSR);
    487    } else if (IsFlag(found, "bl-bails")) {
    488      EnableChannel(JitSpew_BaselineBailouts);
    489    } else if (IsFlag(found, "bl-dbg-osr")) {
    490      EnableChannel(JitSpew_BaselineDebugModeOSR);
    491    } else if (IsFlag(found, "bl-all")) {
    492      EnableChannel(JitSpew_BaselineAbort);
    493      EnableChannel(JitSpew_BaselineScripts);
    494      EnableChannel(JitSpew_BaselineOp);
    495      EnableChannel(JitSpew_BaselineIC);
    496      EnableChannel(JitSpew_BaselineICFallback);
    497      EnableChannel(JitSpew_BaselineOSR);
    498      EnableChannel(JitSpew_BaselineBailouts);
    499      EnableChannel(JitSpew_BaselineDebugModeOSR);
    500    } else {
    501      fprintf(stderr, "Unknown flag.\n");
    502      PrintHelpAndExit(64);
    503    }
    504    found = strtok(nullptr, ",");
    505  }
    506 
    507  FILE* spewfh = stderr;
    508  const char* filename = getenv("ION_SPEW_FILENAME");
    509  if (filename && *filename) {
    510    char actual_filename[2048] = {0};
    511    SprintfLiteral(actual_filename, "%s.%d", filename, getpid());
    512    spewfh = fopen(actual_filename, "w");
    513    MOZ_RELEASE_ASSERT(spewfh);
    514    setbuf(spewfh, nullptr);  // Make unbuffered
    515  }
    516  JitSpewPrinter().init(spewfh);
    517 }
    518 
    519 JitSpewIndent::JitSpewIndent(JitSpewChannel channel) : channel_(channel) {
    520  ChannelIndentLevel[channel]++;
    521 }
    522 
    523 JitSpewIndent::~JitSpewIndent() { ChannelIndentLevel[channel_]--; }
    524 
    525 void jit::JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap) {
    526  if (!JitSpewEnabled(channel)) {
    527    return;
    528  }
    529 
    530  JitSpewHeader(channel);
    531  Fprinter& out = JitSpewPrinter();
    532  out.vprintf(fmt, ap);
    533 }
    534 
    535 void jit::JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap) {
    536  if (!JitSpewEnabled(channel)) {
    537    return;
    538  }
    539 
    540  Fprinter& out = JitSpewPrinter();
    541  out.vprintf(fmt, ap);
    542 }
    543 
    544 void jit::JitSpewFin(JitSpewChannel channel) {
    545  if (!JitSpewEnabled(channel)) {
    546    return;
    547  }
    548 
    549  Fprinter& out = JitSpewPrinter();
    550  out.put("\n");
    551 }
    552 
    553 void jit::JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap) {
    554  JitSpewStartVA(channel, fmt, ap);
    555  JitSpewFin(channel);
    556 }
    557 
    558 void jit::JitSpew(JitSpewChannel channel, const char* fmt, ...) {
    559  va_list ap;
    560  va_start(ap, fmt);
    561  JitSpewVA(channel, fmt, ap);
    562 
    563  // Suppress hazard analysis on logPrintVA function pointer.
    564  JS::AutoSuppressGCAnalysis suppress;
    565 
    566  switch (channel) {
    567 #  define SpewChannel(x)                                                      \
    568    case JitSpew_##x:                                                         \
    569      if (x##Module.shouldLog(js::LogLevel::Debug)) {                         \
    570        x##Module.interface.logPrintVA(x##Module.logger, js::LogLevel::Debug, \
    571                                       fmt, ap);                              \
    572      }                                                                       \
    573      break;
    574 
    575    JITSPEW_CHANNEL_LIST(SpewChannel)
    576 
    577 #  undef SpewChannel
    578    case JitSpew_Terminator:
    579      MOZ_CRASH("Unexpected JitSpew");
    580  }
    581 
    582  va_end(ap);
    583 }
    584 
    585 void jit::JitSpewDef(JitSpewChannel channel, const char* str,
    586                     MDefinition* def) {
    587  if (!JitSpewEnabled(channel)) {
    588    return;
    589  }
    590 
    591  JitSpewHeader(channel);
    592  Fprinter& out = JitSpewPrinter();
    593  out.put(str);
    594  def->dump(out);
    595  def->dumpLocation(out);
    596 }
    597 
    598 void jit::JitSpewStart(JitSpewChannel channel, const char* fmt, ...) {
    599  va_list ap;
    600  va_start(ap, fmt);
    601  JitSpewStartVA(channel, fmt, ap);
    602  va_end(ap);
    603 }
    604 void jit::JitSpewCont(JitSpewChannel channel, const char* fmt, ...) {
    605  va_list ap;
    606  va_start(ap, fmt);
    607  JitSpewContVA(channel, fmt, ap);
    608  va_end(ap);
    609 }
    610 
    611 void jit::JitSpewHeader(JitSpewChannel channel) {
    612  if (!JitSpewEnabled(channel)) {
    613    return;
    614  }
    615 
    616  Fprinter& out = JitSpewPrinter();
    617  out.printf("[%s] ", ChannelNames[channel]);
    618  for (size_t i = ChannelIndentLevel[channel]; i != 0; i--) {
    619    out.put("  ");
    620  }
    621 }
    622 
    623 void jit::EnableChannel(JitSpewChannel channel) {
    624  MOZ_ASSERT(LoggingChecked);
    625  LoggingBits |= uint64_t(1) << uint32_t(channel);
    626 }
    627 
    628 void jit::DisableChannel(JitSpewChannel channel) {
    629  MOZ_ASSERT(LoggingChecked);
    630  LoggingBits &= ~(uint64_t(1) << uint32_t(channel));
    631 }
    632 
    633 #endif /* JS_JITSPEW */
    634 
    635 #if defined(JS_JITSPEW) || defined(ENABLE_JS_AOT_ICS)
    636 
    637 const char* js::jit::ValTypeToString(JSValueType type) {
    638  switch (type) {
    639    case JSVAL_TYPE_DOUBLE:
    640      return "Double";
    641    case JSVAL_TYPE_INT32:
    642      return "Int32";
    643    case JSVAL_TYPE_BOOLEAN:
    644      return "Boolean";
    645    case JSVAL_TYPE_UNDEFINED:
    646      return "Undefined";
    647    case JSVAL_TYPE_NULL:
    648      return "Null";
    649    case JSVAL_TYPE_MAGIC:
    650      return "Magic";
    651    case JSVAL_TYPE_STRING:
    652      return "String";
    653    case JSVAL_TYPE_SYMBOL:
    654      return "Symbol";
    655    case JSVAL_TYPE_PRIVATE_GCTHING:
    656      return "PrivateGCThing";
    657    case JSVAL_TYPE_BIGINT:
    658      return "BigInt";
    659    case JSVAL_TYPE_OBJECT:
    660      return "Object";
    661    case JSVAL_TYPE_UNKNOWN:
    662      return "None";
    663    default:
    664      MOZ_CRASH("Unknown JSValueType");
    665  }
    666 }
    667 
    668 #endif /* defined(JS_JITSPEW) || defined(ENABLE_JS_AOT_ICS) */