tor-browser

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

Disassembler-shared.cpp (6712B)


      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 #include "jit/shared/Disassembler-shared.h"
      8 
      9 #include "jit/JitSpewer.h"
     10 #include "jit/Label.h"
     11 #include "js/Printer.h"
     12 
     13 using namespace js::jit;
     14 
     15 using js::Sprinter;
     16 
     17 #ifdef JS_DISASM_SUPPORTED
     18 // Concurrent assemblers are disambiguated by prefixing every disassembly with a
     19 // tag that is quasi-unique, and certainly unique enough in realistic cases
     20 // where we are debugging and looking at disassembler output.  The tag is a
     21 // letter or digit between brackets prefixing the disassembly, eg, [X]. This
     22 // wraps around every 62 assemblers.
     23 //
     24 // When running with --no-threads we can still have concurrent assemblers in the
     25 // form of nested assemblers, as when an IC stub is created by one assembler
     26 // while a JS compilation is going on and producing output in another assembler.
     27 //
     28 // We generate the tag for an assembler by incrementing a global mod-2^32
     29 // counter every time a new disassembler is created.
     30 
     31 mozilla::Atomic<uint32_t> DisassemblerSpew::counter_(0);
     32 #endif
     33 
     34 DisassemblerSpew::DisassemblerSpew()
     35    : printer_(nullptr)
     36 #ifdef JS_DISASM_SUPPORTED
     37      ,
     38      labelIndent_(""),
     39      targetIndent_(""),
     40      spewNext_(1000),
     41      nodes_(nullptr),
     42      tag_(0)
     43 #endif
     44 {
     45 #ifdef JS_DISASM_SUPPORTED
     46  tag_ = counter_++;
     47 #endif
     48 }
     49 
     50 DisassemblerSpew::~DisassemblerSpew() {
     51 #ifdef JS_DISASM_SUPPORTED
     52  Node* p = nodes_;
     53  while (p) {
     54    Node* victim = p;
     55    p = p->next;
     56    js_free(victim);
     57  }
     58 #endif
     59 }
     60 
     61 void DisassemblerSpew::setPrinter(Sprinter* printer) { printer_ = printer; }
     62 
     63 bool DisassemblerSpew::isDisabled() {
     64  return !(JitSpewEnabled(JitSpew_Codegen) || printer_);
     65 }
     66 
     67 void DisassemblerSpew::spew(const char* fmt, ...) {
     68 #ifdef JS_DISASM_SUPPORTED
     69  static const char prefix_chars[] =
     70      "0123456789"
     71      "abcdefghijklmnopqrstuvwxyz"
     72      "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     73  static const char prefix_fmt[] = "[%c] ";
     74 
     75  char fmt2[1024];
     76  if (sizeof(fmt2) >= strlen(fmt) + sizeof(prefix_fmt)) {
     77    snprintf(fmt2, sizeof(prefix_fmt), prefix_fmt,
     78             prefix_chars[tag_ % (sizeof(prefix_chars) - 1)]);
     79    strcat(fmt2, fmt);
     80    fmt = fmt2;
     81  }
     82 #endif
     83 
     84  va_list args;
     85  va_start(args, fmt);
     86  spewVA(fmt, args);
     87  va_end(args);
     88 }
     89 
     90 void DisassemblerSpew::spewVA(const char* fmt, va_list va) {
     91  if (printer_) {
     92    printer_->vprintf(fmt, va);
     93    printer_->put("\n");
     94  }
     95  js::jit::JitSpewVA(js::jit::JitSpew_Codegen, fmt, va);
     96 }
     97 
     98 #ifdef JS_DISASM_SUPPORTED
     99 
    100 void DisassemblerSpew::setLabelIndent(const char* s) { labelIndent_ = s; }
    101 
    102 void DisassemblerSpew::setTargetIndent(const char* s) { targetIndent_ = s; }
    103 
    104 DisassemblerSpew::LabelDoc DisassemblerSpew::refLabel(const Label* l) {
    105  return l ? LabelDoc(internalResolve(l), l->bound()) : LabelDoc();
    106 }
    107 
    108 void DisassemblerSpew::spewRef(const LabelDoc& target) {
    109  if (isDisabled()) {
    110    return;
    111  }
    112  if (!target.valid) {
    113    return;
    114  }
    115  spew("%s-> %d%s", targetIndent_, target.doc, !target.bound ? "f" : "");
    116 }
    117 
    118 void DisassemblerSpew::spewBind(const Label* label) {
    119  if (isDisabled()) {
    120    return;
    121  }
    122  uint32_t v = internalResolve(label);
    123  Node* probe = lookup(label);
    124  if (probe) {
    125    probe->bound = true;
    126  }
    127  spew("%s%d:", labelIndent_, v);
    128 }
    129 
    130 void DisassemblerSpew::spewRetarget(const Label* label, const Label* target) {
    131  if (isDisabled()) {
    132    return;
    133  }
    134  LabelDoc labelDoc = LabelDoc(internalResolve(label), label->bound());
    135  LabelDoc targetDoc = LabelDoc(internalResolve(target), target->bound());
    136  Node* probe = lookup(label);
    137  if (probe) {
    138    probe->bound = true;
    139  }
    140  spew("%s%d: .retarget -> %d%s", labelIndent_, labelDoc.doc, targetDoc.doc,
    141       !targetDoc.bound ? "f" : "");
    142 }
    143 
    144 void DisassemblerSpew::formatLiteral(const LiteralDoc& doc, char* buffer,
    145                                     size_t bufsize) {
    146  switch (doc.type) {
    147    case LiteralDoc::Type::Patchable:
    148      snprintf(buffer, bufsize, "patchable");
    149      break;
    150    case LiteralDoc::Type::I32:
    151      snprintf(buffer, bufsize, "%d", doc.value.i32);
    152      break;
    153    case LiteralDoc::Type::U32:
    154      snprintf(buffer, bufsize, "%u", doc.value.u32);
    155      break;
    156    case LiteralDoc::Type::I64:
    157      snprintf(buffer, bufsize, "%" PRIi64, doc.value.i64);
    158      break;
    159    case LiteralDoc::Type::U64:
    160      snprintf(buffer, bufsize, "%" PRIu64, doc.value.u64);
    161      break;
    162    case LiteralDoc::Type::F32:
    163      snprintf(buffer, bufsize, "%g", doc.value.f32);
    164      break;
    165    case LiteralDoc::Type::F64:
    166      snprintf(buffer, bufsize, "%g", doc.value.f64);
    167      break;
    168    default:
    169      MOZ_CRASH();
    170  }
    171 }
    172 
    173 void DisassemblerSpew::spewOrphans() {
    174  for (Node* p = nodes_; p; p = p->next) {
    175    if (!p->bound) {
    176      spew("%s%d:    ; .orphan", labelIndent_, p->value);
    177    }
    178  }
    179 }
    180 
    181 uint32_t DisassemblerSpew::internalResolve(const Label* l) {
    182  // Note, internalResolve will sometimes return 0 when it is triggered by the
    183  // profiler and not by a full disassembly, since in that case a label can be
    184  // used or bound but not previously have been defined.  In that case,
    185  // internalResolve(l) will not necessarily create a binding for l!
    186  // Consequently a subsequent lookup(l) may still return null.
    187  return l->used() || l->bound() ? probe(l) : define(l);
    188 }
    189 
    190 uint32_t DisassemblerSpew::probe(const Label* l) {
    191  Node* n = lookup(l);
    192  return n ? n->value : 0;
    193 }
    194 
    195 uint32_t DisassemblerSpew::define(const Label* l) {
    196  remove(l);
    197  uint32_t value = spewNext_++;
    198  if (!add(l, value)) {
    199    return 0;
    200  }
    201  return value;
    202 }
    203 
    204 DisassemblerSpew::Node* DisassemblerSpew::lookup(const Label* key) {
    205  Node* p;
    206  for (p = nodes_; p && p->key != key; p = p->next) {
    207    ;
    208  }
    209  return p;
    210 }
    211 
    212 DisassemblerSpew::Node* DisassemblerSpew::add(const Label* key,
    213                                              uint32_t value) {
    214  MOZ_ASSERT(!lookup(key));
    215  Node* node = js_new<Node>();
    216  if (node) {
    217    node->key = key;
    218    node->value = value;
    219    node->bound = false;
    220    node->next = nodes_;
    221    nodes_ = node;
    222  }
    223  return node;
    224 }
    225 
    226 bool DisassemblerSpew::remove(const Label* key) {
    227  // We do not require that there is a node matching the key.
    228  for (Node *p = nodes_, *pp = nullptr; p; pp = p, p = p->next) {
    229    if (p->key == key) {
    230      if (pp) {
    231        pp->next = p->next;
    232      } else {
    233        nodes_ = p->next;
    234      }
    235      js_free(p);
    236      return true;
    237    }
    238  }
    239  return false;
    240 }
    241 
    242 #else
    243 
    244 DisassemblerSpew::LabelDoc DisassemblerSpew::refLabel(const Label* l) {
    245  return LabelDoc();
    246 }
    247 
    248 #endif