Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/jit/shared/Disassembler-shared.h
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
#ifndef jit_shared_Disassembler_shared_h
8
#define jit_shared_Disassembler_shared_h
9
10
#include "mozilla/Atomics.h"
11
12
#include "jit/Label.h"
13
#ifdef JS_DISASM_SUPPORTED
14
# include "jit/shared/IonAssemblerBuffer.h"
15
#endif
16
17
using js::jit::Label;
18
using js::Sprinter;
19
20
#if defined(JS_DISASM_ARM) || defined(JS_DISASM_ARM64)
21
#  define JS_DISASM_SUPPORTED
22
#endif
23
24
namespace js {
25
namespace jit {
26
27
// A wrapper around spew/disassembly functionality.  The disassembler is built
28
// on a per-instruction disassembler (as in our ARM, ARM64 back-ends) and
29
// formats labels with meaningful names and literals with meaningful values, if
30
// the assembler creates documentation (with provided helpers) at appropriate
31
// points.
32
33
class DisassemblerSpew
34
{
35
#ifdef JS_DISASM_SUPPORTED
36
    struct Node
37
    {
38
        const Label* key;       // Never dereferenced, only used for its value
39
        uint32_t value;         // The printable label value
40
        bool bound;             // If the label has been seen by spewBind()
41
        Node* next;
42
    };
43
44
    Node* lookup(const Label* key);
45
    Node* add(const Label* key, uint32_t value);
46
    bool remove(const Label* key);
47
48
    uint32_t probe(const Label* l);
49
    uint32_t define(const Label* l);
50
    uint32_t internalResolve(const Label* l);
51
#endif
52
53
    void spewVA(const char* fmt, va_list args) MOZ_FORMAT_PRINTF(2, 0);
54
55
  public:
56
    DisassemblerSpew();
57
    ~DisassemblerSpew();
58
59
#ifdef JS_DISASM_SUPPORTED
60
    // Set indentation strings.  The spewer retains a reference to s.
61
    void setLabelIndent(const char* s);
62
    void setTargetIndent(const char* s);
63
#endif
64
65
    // Set the spew printer, which will always be used if it is set, regardless
66
    // of whether the system spew channel is enabled or not.  The spewer retains
67
    // a reference to sp.
68
    void setPrinter(Sprinter* sp);
69
70
    // Return true if disassembly spew is disabled and no additional printer is
71
    // set.
72
    bool isDisabled();
73
74
    // Format and print text on the spew channel; output is suppressed if spew
75
    // is disabled.  The output is not indented, and is terminated by a newline.
76
    void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
77
78
    // Documentation for a label reference.
79
    struct LabelDoc
80
    {
81
#ifdef JS_DISASM_SUPPORTED
82
  LabelDoc() : doc(0), bound(false), valid(false) {}
83
  LabelDoc(uint32_t doc, bool bound) : doc(doc), bound(bound), valid(true) {}
84
  const uint32_t doc;
85
  const bool bound;
86
  const bool valid;
87
#else
88
0
  LabelDoc() {}
89
0
  LabelDoc(uint32_t, bool) {}
90
#endif
91
    };
92
93
    // Documentation for a literal load.
94
    struct LiteralDoc
95
    {
96
#ifdef JS_DISASM_SUPPORTED
97
        enum class Type { Patchable, I32, U32, I64, U64, F32, F64 };
98
        const Type type;
99
        union {
100
            int32_t  i32;
101
            uint32_t u32;
102
            int64_t  i64;
103
            uint64_t u64;
104
            float    f32;
105
            double   f64;
106
        } value;
107
        LiteralDoc() : type(Type::Patchable) {}
108
        explicit LiteralDoc(int32_t v) : type(Type::I32) { value.i32 = v; }
109
        explicit LiteralDoc(uint32_t v) : type(Type::U32) { value.u32 = v; }
110
        explicit LiteralDoc(int64_t v) : type(Type::I64) { value.i64 = v; }
111
        explicit LiteralDoc(uint64_t v) : type(Type::U64) { value.u64 = v; }
112
        explicit LiteralDoc(float v) : type(Type::F32) { value.f32 = v; }
113
        explicit LiteralDoc(double v) : type(Type::F64) { value.f64 = v; }
114
#else
115
0
        LiteralDoc() {}
116
0
        explicit LiteralDoc(int32_t) {}
117
0
        explicit LiteralDoc(uint32_t) {}
118
0
        explicit LiteralDoc(int64_t) {}
119
0
        explicit LiteralDoc(uint64_t) {}
120
0
        explicit LiteralDoc(float) {}
121
0
        explicit LiteralDoc(double) {}
122
#endif
123
    };
124
125
    // Reference a label, resolving it to a printable representation.
126
    //
127
    // NOTE: The printable representation depends on the state of the label, so
128
    // if we call resolve() when emitting & disassembling a branch instruction
129
    // then it should be called before the label becomes Used, if emitting the
130
    // branch can change the label's state.
131
    //
132
    // If the disassembler is not defined this returns a structure that is
133
    // marked not valid.
134
    LabelDoc refLabel(const Label* l);
135
136
#ifdef JS_DISASM_SUPPORTED
137
    // Spew the label information previously gathered by refLabel(), at a point
138
    // where the label is referenced.  The output is indented by targetIndent_
139
    // and terminated by a newline.
140
    void spewRef(const LabelDoc& target);
141
142
    // Spew the label at the point where the label is bound.  The output is
143
    // indented by labelIndent_ and terminated by a newline.
144
    void spewBind(const Label* label);
145
146
    // Spew a retarget directive at the point where the retarget is recorded.
147
    // The output is indented by labelIndent_ and terminated by a newline.
148
    void spewRetarget(const Label* label, const Label* target);
149
150
    // Format a literal value into the buffer.  The buffer is always
151
    // NUL-terminated even if this chops the formatted value.
152
    void formatLiteral(const LiteralDoc& doc, char* buffer, size_t bufsize);
153
154
    // Print any unbound labels, one per line, with normal label indent and with
155
    // a comment indicating the label is not defined.  Labels can be referenced
156
    // but unbound in some legitimate cases, normally for traps.  Printing them
157
    // reduces confusion.
158
    void spewOrphans();
159
#endif
160
161
  private:
162
    Sprinter* printer_;
163
#ifdef JS_DISASM_SUPPORTED
164
    const char* labelIndent_;
165
    const char* targetIndent_;
166
    uint32_t spewNext_;
167
    Node* nodes_;
168
    uint32_t tag_;
169
170
    // This global is used to disambiguate concurrently live assemblers, see
171
    // comments in Disassembler-shared.cpp for why this is desirable.
172
    //
173
    // The variable is atomic to avoid any kind of complaint from thread
174
    // sanitizers etc.  However, trying to look at disassembly without using
175
    // --no-threads is basically insane, so you can ignore the multi-threading
176
    // implications here.
177
    static mozilla::Atomic<uint32_t> counter_;
178
#endif
179
};
180
181
}
182
}
183
184
#endif // jit_shared_Disassembler_shared_h