1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "YarrDisassembler.h"
28
29#if ENABLE(JIT)
30
31#include "Disassembler.h"
32#include "LinkBuffer.h"
33#include <wtf/StringPrintStream.h>
34
35namespace JSC { namespace Yarr {
36
37static constexpr char s_spaces[] = " ";
38static constexpr unsigned s_maxIndent = sizeof(s_spaces) - 1;
39
40const char* YarrDisassembler::indentString(unsigned level)
41{
42 unsigned indent = 6 + level * 2;
43 indent = std::min(indent, s_maxIndent);
44
45 return s_spaces + s_maxIndent - indent;
46}
47
48YarrDisassembler::YarrDisassembler(YarrJITInfo* yarrJITInfo)
49 : m_jitInfo(yarrJITInfo)
50 , m_labelForGenerateYarrOp(yarrJITInfo->opCount())
51 , m_labelForBacktrackYarrOp(yarrJITInfo->opCount())
52{
53}
54
55YarrDisassembler::~YarrDisassembler()
56{
57}
58
59void YarrDisassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
60{
61 dumpHeader(out, linkBuffer);
62 dumpDisassembly(out, indentString(), linkBuffer, m_startOfCode, m_labelForGenerateYarrOp[0]);
63
64 out.print(" == Matching ==\n");
65 dumpForInstructions(out, linkBuffer, m_labelForGenerateYarrOp, m_endOfGenerate);
66 out.print(" == Backtracking ==\n");
67 dumpForInstructions(out, linkBuffer, m_labelForBacktrackYarrOp, m_endOfBacktrack, VectorOrder::IterateReverse);
68
69 if (!(m_endOfBacktrack == m_endOfCode)) {
70 out.print(" == Helpers ==\n");
71
72 dumpDisassembly(out, indentString(), linkBuffer, m_endOfBacktrack, m_endOfCode);
73 }
74
75 linkBuffer.didAlreadyDisassemble();
76}
77
78void YarrDisassembler::dump(LinkBuffer& linkBuffer)
79{
80 dump(WTF::dataFile(), linkBuffer);
81}
82
83void YarrDisassembler::dumpHeader(PrintStream& out, LinkBuffer& linkBuffer)
84{
85 out.print("Generated JIT code for ", m_jitInfo->variant(), " ");
86 m_jitInfo->dumpPatternString(out);
87 out.print(":\n");
88 out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.size()), "):\n");
89}
90
91Vector<YarrDisassembler::DumpedOp> YarrDisassembler::dumpVectorForInstructions(LinkBuffer& linkBuffer, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel, YarrDisassembler::VectorOrder vectorOrder)
92{
93 StringPrintStream out;
94 Vector<DumpedOp> result;
95
96 unsigned directionBias = (vectorOrder == VectorOrder::IterateForward) ? 0 : labels.size() - 1;
97
98 auto realIndex = [&](unsigned rawIndex) {
99 if (directionBias)
100 return directionBias - rawIndex;
101 return rawIndex;
102 };
103
104 for (unsigned i = 0; i < labels.size();) {
105 if (!labels[realIndex(i)].isSet()) {
106 i++;
107 continue;
108 }
109 out.reset();
110 result.append(DumpedOp());
111 result.last().index = realIndex(i);
112
113 int delta = m_jitInfo->dumpFor(out, realIndex(i));
114 m_indentLevel += (vectorOrder == VectorOrder::IterateForward) ? delta : -delta;
115
116 for (unsigned nextIndex = i + 1; ; nextIndex++) {
117 if (nextIndex >= labels.size()) {
118 dumpDisassembly(out, indentString(), linkBuffer, labels[realIndex(i)], endLabel);
119 result.last().disassembly = out.toCString();
120 return result;
121 }
122 if (labels[realIndex(nextIndex)].isSet()) {
123 dumpDisassembly(out, indentString(), linkBuffer, labels[realIndex(i)], labels[realIndex(nextIndex)]);
124 result.last().disassembly = out.toCString();
125 i = nextIndex;
126 break;
127 }
128 }
129 }
130
131 return result;
132}
133
134void YarrDisassembler::dumpForInstructions(PrintStream& out, LinkBuffer& linkBuffer, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel, YarrDisassembler::VectorOrder vectorOrder)
135{
136 Vector<DumpedOp> dumpedOps = dumpVectorForInstructions(linkBuffer, labels, endLabel, vectorOrder);
137
138 for (unsigned i = 0; i < dumpedOps.size(); ++i)
139 out.print(dumpedOps[i].disassembly);
140}
141
142void YarrDisassembler::dumpDisassembly(PrintStream& out, const char* prefix, LinkBuffer& linkBuffer, MacroAssembler::Label from, MacroAssembler::Label to)
143{
144 CodeLocationLabel<DisassemblyPtrTag> fromLocation = linkBuffer.locationOf<DisassemblyPtrTag>(from);
145 CodeLocationLabel<DisassemblyPtrTag> toLocation = linkBuffer.locationOf<DisassemblyPtrTag>(to);
146 disassemble(fromLocation, toLocation.dataLocation<uintptr_t>() - fromLocation.dataLocation<uintptr_t>(), prefix, out);
147}
148
149}} // namespace Yarr namespace JSC
150
151#endif // ENABLE(JIT)
152
153