1/*
2 * Copyright (C) 2015-2017 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#pragma once
27
28#include "MacroAssembler.h"
29#include "Printer.h"
30#include "ProbeContext.h"
31
32namespace JSC {
33
34#if ENABLE(ASSEMBLER)
35#if ENABLE(MASM_PROBE)
36
37// What is MacroAssembler::print()?
38// ===============================
39// The MacroAsssembler::print() makes it easy to add print logging
40// from JIT compiled code, and can be used to print all types of values
41// at runtime e.g. CPU register values being operated on by the compiled
42// code.
43//
44// print() is built on top of MacroAsssembler::probe(), and hence
45// inserting logging in JIT compiled code will not perturb register values.
46// The only register value that is perturbed is the PC (program counter)
47// since there is now more compiled code to do the printing.
48//
49// How to use the MacroAssembler print()?
50// =====================================
51// 1. #include "MacroAssemblerPrinter.h" in the JIT file where you want to use print().
52//
53// 2. Add print() calls like these in your JIT code:
54//
55// jit.print("Hello world\n"); // Emits code to print the string.
56//
57// CodeBlock* cb = ...;
58// jit.print(cb, "\n"); // Emits code to print the codeBlock value.
59// jit.print(RawPointer(cb), "\n"); // Emits code to print the pointer value.
60//
61// RegisterID regID = ...;
62// jit.print(regID, "\n"); // Emits code to print the register value (not the id).
63//
64// // Emits code to print all registers. Unlike other items, this prints
65// // multiple lines as follows:
66// // cpu {
67// // eax: 0x123456789
68// // ebx: 0x000000abc
69// // ...
70// // }
71// unsigned indentation = 4;
72// jit.print(AllRegisters(indentation));
73//
74// jit.print(MemWord<uint8_t>(regID), "\n"); // Emits code to print a byte pointed to by the register.
75// jit.print(MemWord<uint32_t>(regID), "\n"); // Emits code to print a 32-bit word pointed to by the register.
76//
77// jit.print(MemWord<uint8_t>(Address(regID, 23), "\n"); // Emits code to print a byte at the address.
78// jit.print(MemWord<intptr_t>(AbsoluteAddress(&cb), "\n"); // Emits code to print an intptr_t sized word at the address.
79//
80// jit.print(Memory(reg, 100), "\n"); // Emits code to print a 100 bytes at the address pointed by the register.
81// jit.print(Memory(Address(reg, 4), 100), "\n"); // Emits code to print a 100 bytes at the address.
82//
83// // Print multiple things at once. This incurs the probe overhead only once
84// // to print all the items.
85// jit.print("cb:", cb, " regID:", regID, " cpu:\n", AllRegisters());
86//
87// The type of values that can be printed is determine by the availability of a
88// specialized Printer template, or a setPrinter() function for the value type.
89//
90// Note: print() does not automatically insert a '\n' at the end of the line.
91// If you want a '\n', you'll have to add it explicitly (as in the examples above).
92
93
94struct AllRegisters {
95 explicit AllRegisters(unsigned charsToIndent = 0)
96 : charsToIndent(charsToIndent)
97 { }
98 unsigned charsToIndent;
99};
100struct PCRegister { };
101
102struct Memory {
103 using Address = MacroAssembler::Address;
104 using AbsoluteAddress = MacroAssembler::AbsoluteAddress;
105 using RegisterID = MacroAssembler::RegisterID;
106
107 enum class AddressType {
108 Address,
109 AbsoluteAddress,
110 };
111
112 enum DumpStyle {
113 SingleWordDump,
114 GenericDump,
115 };
116
117 explicit Memory(RegisterID& reg, size_t bytes, DumpStyle style = GenericDump)
118 : addressType(AddressType::Address)
119 , dumpStyle(style)
120 , numBytes(bytes)
121 {
122 u.address = Address(reg, 0);
123 }
124
125 explicit Memory(const Address& address, size_t bytes, DumpStyle style = GenericDump)
126 : addressType(AddressType::Address)
127 , dumpStyle(style)
128 , numBytes(bytes)
129 {
130 u.address = address;
131 }
132
133 explicit Memory(const AbsoluteAddress& address, size_t bytes, DumpStyle style = GenericDump)
134 : addressType(AddressType::AbsoluteAddress)
135 , dumpStyle(style)
136 , numBytes(bytes)
137 {
138 u.absoluteAddress = address;
139 }
140
141 AddressType addressType;
142 DumpStyle dumpStyle;
143 size_t numBytes;
144 union UnionedAddress {
145 UnionedAddress() { }
146
147 Address address;
148 AbsoluteAddress absoluteAddress;
149 } u;
150};
151
152template <typename IntType>
153struct MemWord : public Memory {
154 explicit MemWord(RegisterID& reg)
155 : Memory(reg, sizeof(IntType), Memory::SingleWordDump)
156 { }
157
158 explicit MemWord(const Address& address)
159 : Memory(address, sizeof(IntType), Memory::SingleWordDump)
160 { }
161
162 explicit MemWord(const AbsoluteAddress& address)
163 : Memory(address, sizeof(IntType), Memory::SingleWordDump)
164 { }
165};
166
167namespace Printer {
168
169// Add some specialized printers.
170
171void printAllRegisters(PrintStream&, Context&);
172void printPCRegister(PrintStream&, Context&);
173void printRegisterID(PrintStream&, Context&);
174void printFPRegisterID(PrintStream&, Context&);
175void printAddress(PrintStream&, Context&);
176void printMemory(PrintStream&, Context&);
177
178template<>
179struct Printer<AllRegisters> : public PrintRecord {
180 Printer(AllRegisters allRegisters)
181 : PrintRecord(static_cast<uintptr_t>(allRegisters.charsToIndent), printAllRegisters)
182 { }
183};
184
185template<>
186struct Printer<PCRegister> : public PrintRecord {
187 Printer(PCRegister&)
188 : PrintRecord(printPCRegister)
189 { }
190};
191
192template<>
193struct Printer<MacroAssembler::RegisterID> : public PrintRecord {
194 Printer(MacroAssembler::RegisterID id)
195 : PrintRecord(static_cast<uintptr_t>(id), printRegisterID)
196 { }
197};
198
199template<>
200struct Printer<MacroAssembler::FPRegisterID> : public PrintRecord {
201 Printer(MacroAssembler::FPRegisterID id)
202 : PrintRecord(static_cast<uintptr_t>(id), printFPRegisterID)
203 { }
204};
205
206template<>
207struct Printer<MacroAssembler::Address> : public PrintRecord {
208 Printer(MacroAssembler::Address address)
209 : PrintRecord(Data(&address, sizeof(address)), printAddress)
210 { }
211};
212
213template<>
214struct Printer<Memory> : public PrintRecord {
215 Printer(Memory memory)
216 : PrintRecord(Data(&memory, sizeof(memory)), printMemory)
217 { }
218};
219
220template<typename IntType>
221struct Printer<MemWord<IntType>> : public Printer<Memory> {
222 Printer(MemWord<IntType> word)
223 : Printer<Memory>(word)
224 { }
225};
226
227void printCallback(Probe::Context&);
228
229} // namespace Printer
230
231template<typename... Arguments>
232inline void MacroAssembler::print(Arguments&&... arguments)
233{
234 auto printRecordList = Printer::makePrintRecordList(std::forward<Arguments>(arguments)...);
235 probe(Printer::printCallback, printRecordList);
236}
237
238inline void MacroAssembler::print(Printer::PrintRecordList* printRecordList)
239{
240 probe(Printer::printCallback, printRecordList);
241}
242
243#endif // ENABLE(MASM_PROBE)
244#endif // ENABLE(ASSEMBLER)
245
246} // namespace JSC
247