Unreviewed revert Fujii's revert in r237214 with new WinCairo build fix.
[WebKit-https.git] / Source / JavaScriptCore / assembler / Printer.h
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
34 namespace JSC {
35
36 namespace Probe {
37 class Context;
38 } // namespace Probe
39
40 namespace Printer {
41
42 struct Context;
43
44 union 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
90 struct 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
100 typedef void (*Callback)(PrintStream&, Context&);
101
102 struct 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
124 protected:
125     PrintRecord() { }
126 };
127
128 template<typename T> struct Printer;
129
130 typedef Vector<PrintRecord> PrintRecordList;
131
132 inline void appendPrinter(PrintRecordList&) { }
133
134 template<typename First, typename... Arguments>
135 inline void appendPrinter(PrintRecordList& printRecordList, First first, Arguments&&... others)
136 {
137     printRecordList.append(Printer<First>(first));
138     appendPrinter(printRecordList, std::forward<Arguments>(others)...);
139 }
140
141 template<typename... Arguments>
142 inline 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
155 void printConstCharString(PrintStream&, Context&);
156 void printIntptr(PrintStream&, Context&);
157 void printUintptr(PrintStream&, Context&);
158 void printPointer(PrintStream&, Context&);
159
160 void setPrinter(PrintRecord&, CString&&);
161
162 // Specialized printers.
163
164 template<>
165 struct Printer<const char*> : public PrintRecord {
166     Printer(const char* str)
167         : PrintRecord(str, printConstCharString)
168     { }
169 };
170
171 template<>
172 struct Printer<char*> : public Printer<const char*> {
173     Printer(char* str)
174         : Printer<const char*>(str)
175     { }
176 };
177
178 template<>
179 struct Printer<RawPointer> : public PrintRecord {
180     Printer(RawPointer rawPointer)
181         : PrintRecord(rawPointer.value(), printPointer)
182     { }
183 };
184
185 template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && std::numeric_limits<T>::is_signed>>
186 void setPrinter(PrintRecord& record, T value, intptr_t = 0)
187 {
188     record.data.value = static_cast<uintptr_t>(value);
189     record.printer = printIntptr;
190 }
191
192 template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && !std::numeric_limits<T>::is_signed>>
193 void setPrinter(PrintRecord& record, T value, uintptr_t = 0)
194 {
195     record.data.value = static_cast<uintptr_t>(value);
196     record.printer = printUintptr;
197 }
198
199 template<typename T>
200 struct Printer : public PrintRecord {
201     Printer(T value)
202     {
203         setPrinter(*this, value);
204     }
205 };
206
207 } // namespace Printer
208
209 } // namespace JSC