1/*
2 * Copyright (C) 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 "CPU.h"
29
30#include <wtf/PrintStream.h>
31#include <wtf/StringPrintStream.h>
32#include <wtf/Vector.h>
33
34namespace JSC {
35
36namespace Probe {
37class Context;
38} // namespace Probe
39
40namespace Printer {
41
42struct Context;
43
44union Data {
45 Data()
46 {
47 const intptr_t uninitialized = 0xdeadb0d0;
48 memcpy(&buffer, &uninitialized, sizeof(uninitialized));
49 }
50 Data(uintptr_t value)
51 : Data(&value, sizeof(value))
52 { }
53 Data(const void* pointer)
54 : Data(&pointer, sizeof(pointer))
55 { }
56 Data(void* src, size_t size)
57 {
58 RELEASE_ASSERT(size <= sizeof(buffer));
59 memcpy(&buffer, src, size);
60 }
61
62 template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
63 T as() const
64 {
65 return static_cast<T>(value);
66 }
67
68 template<typename T, typename = typename std::enable_if<std::is_pointer<T>::value>::type>
69 const T as(int = 0) const
70 {
71 return reinterpret_cast<const T>(pointer);
72 }
73
74 template<typename T, typename = typename std::enable_if<!std::is_integral<T>::value && !std::is_pointer<T>::value>::type>
75 const T& as() const
76 {
77 static_assert(sizeof(T) <= sizeof(buffer), "size is not sane");
78 return *reinterpret_cast<const T*>(&buffer);
79 }
80
81 uintptr_t value;
82 const void* pointer;
83#if USE(JSVALUE64)
84 UCPURegister buffer[4];
85#elif USE(JSVALUE32_64)
86 UCPURegister buffer[6];
87#endif
88};
89
90struct Context {
91 Context(Probe::Context& probeContext, Data& data)
92 : probeContext(probeContext)
93 , data(data)
94 { }
95
96 Probe::Context& probeContext;
97 Data& data;
98};
99
100typedef void (*Callback)(PrintStream&, Context&);
101
102struct PrintRecord {
103 PrintRecord(Data data, Callback printer)
104 : data(data)
105 , printer(printer)
106 { }
107
108 PrintRecord(Callback printer)
109 : printer(printer)
110 { }
111
112 template<template<class> class Printer, typename T>
113 PrintRecord(const Printer<T>& other)
114 {
115 static_assert(std::is_base_of<PrintRecord, Printer<T>>::value, "Printer should extend PrintRecord");
116 static_assert(sizeof(PrintRecord) == sizeof(Printer<T>), "Printer should be the same size as PrintRecord");
117 data = other.data;
118 printer = other.printer;
119 }
120
121 Data data;
122 Callback printer;
123
124protected:
125 PrintRecord() { }
126};
127
128template<typename T> struct Printer;
129
130typedef Vector<PrintRecord> PrintRecordList;
131
132inline void appendPrinter(PrintRecordList&) { }
133
134template<typename First, typename... Arguments>
135inline void appendPrinter(PrintRecordList& printRecordList, First first, Arguments&&... others)
136{
137 printRecordList.append(Printer<First>(first));
138 appendPrinter(printRecordList, std::forward<Arguments>(others)...);
139}
140
141template<typename... Arguments>
142inline PrintRecordList* makePrintRecordList(Arguments&&... arguments)
143{
144 // FIXME: the current implementation intentionally leaks the PrintRecordList.
145 // We may want to fix this in the future if we want to use the print mechanism
146 // in tests that may compile a lot of prints.
147 // https://bugs.webkit.org/show_bug.cgi?id=171123
148 auto printRecordList = new PrintRecordList();
149 appendPrinter(*printRecordList, std::forward<Arguments>(arguments)...);
150 return printRecordList;
151}
152
153// Some utility functions for specializing printers.
154
155void printConstCharString(PrintStream&, Context&);
156void printIntptr(PrintStream&, Context&);
157void printUintptr(PrintStream&, Context&);
158void printPointer(PrintStream&, Context&);
159
160void setPrinter(PrintRecord&, CString&&);
161
162// Specialized printers.
163
164template<>
165struct Printer<const char*> : public PrintRecord {
166 Printer(const char* str)
167 : PrintRecord(str, printConstCharString)
168 { }
169};
170
171template<>
172struct Printer<char*> : public Printer<const char*> {
173 Printer(char* str)
174 : Printer<const char*>(str)
175 { }
176};
177
178template<>
179struct Printer<RawPointer> : public PrintRecord {
180 Printer(RawPointer rawPointer)
181 : PrintRecord(rawPointer.value(), printPointer)
182 { }
183};
184
185template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && std::numeric_limits<T>::is_signed>>
186void setPrinter(PrintRecord& record, T value, intptr_t = 0)
187{
188 record.data.value = static_cast<uintptr_t>(value);
189 record.printer = printIntptr;
190}
191
192template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && !std::numeric_limits<T>::is_signed>>
193void setPrinter(PrintRecord& record, T value, uintptr_t = 0)
194{
195 record.data.value = static_cast<uintptr_t>(value);
196 record.printer = printUintptr;
197}
198
199template<typename T>
200struct Printer : public PrintRecord {
201 Printer(T value)
202 {
203 setPrinter(*this, value);
204 }
205};
206
207} // namespace Printer
208
209} // namespace JSC
210