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