Coverage Report

Created: 2018-09-25 14:53

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