1/*
2 * Copyright (C) 2012 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#if ENABLE(DFG_JIT)
29
30#include "DFGMinifiedID.h"
31#include "DataFormat.h"
32#include "MacroAssembler.h"
33#include "VirtualRegister.h"
34#include <stdio.h>
35
36namespace JSC { namespace DFG {
37
38enum VariableEventKind : uint8_t {
39 // Marks the beginning of a checkpoint. If you interpret the variable
40 // events starting at a Reset point then you'll get everything you need.
41 Reset,
42
43 // Node births. Points in the code where a node becomes relevant for OSR.
44 // It may be the point where it is actually born (i.e. assigned) or it may
45 // be a later point, if it's only later in the sequence of instructions
46 // that we start to care about this node.
47 BirthToFill,
48 BirthToSpill,
49 Birth,
50
51 // Events related to how a node is represented.
52 Fill,
53 Spill,
54
55 // Death of a node - after this we no longer care about this node.
56 Death,
57
58 // A MovHintEvent means that a node is being associated with a bytecode operand,
59 // but that it has not been stored into that operand.
60 MovHintEvent,
61
62 // A SetLocalEvent means that a node's value has been stored into the stack.
63 SetLocalEvent,
64
65 // Used to indicate an uninitialized VariableEvent. Don't use for other
66 // purposes.
67 InvalidEventKind
68};
69
70union VariableRepresentation {
71 MacroAssembler::RegisterID gpr;
72 MacroAssembler::FPRegisterID fpr;
73#if USE(JSVALUE32_64)
74 struct {
75 MacroAssembler::RegisterID tagGPR;
76 MacroAssembler::RegisterID payloadGPR;
77 } pair;
78#endif
79 int32_t virtualReg;
80};
81
82class VariableEvent {
83public:
84 VariableEvent()
85 : m_kind(InvalidEventKind)
86 {
87 }
88
89 static VariableEvent reset()
90 {
91 VariableEvent event;
92 event.m_kind = Reset;
93 return event;
94 }
95
96 static VariableEvent fillGPR(VariableEventKind kind, MinifiedID id, MacroAssembler::RegisterID gpr, DataFormat dataFormat)
97 {
98 ASSERT(kind == BirthToFill || kind == Fill);
99 ASSERT(dataFormat != DataFormatDouble);
100#if USE(JSVALUE32_64)
101 ASSERT(!(dataFormat & DataFormatJS));
102#endif
103 VariableEvent event;
104 WhichType which;
105 which.id = id.bits();
106 VariableRepresentation representation;
107 representation.gpr = gpr;
108 event.m_kind = kind;
109 event.m_dataFormat = dataFormat;
110 event.m_which = WTFMove(which);
111 event.m_representation = WTFMove(representation);
112 return event;
113 }
114
115#if USE(JSVALUE32_64)
116 static VariableEvent fillPair(VariableEventKind kind, MinifiedID id, MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
117 {
118 ASSERT(kind == BirthToFill || kind == Fill);
119 VariableEvent event;
120 WhichType which;
121 which.id = id.bits();
122 VariableRepresentation representation;
123 representation.pair.tagGPR = tagGPR;
124 representation.pair.payloadGPR = payloadGPR;
125 event.m_kind = kind;
126 event.m_dataFormat = DataFormatJS;
127 event.m_which = WTFMove(which);
128 event.m_representation = WTFMove(representation);
129 return event;
130 }
131#endif // USE(JSVALUE32_64)
132
133 static VariableEvent fillFPR(VariableEventKind kind, MinifiedID id, MacroAssembler::FPRegisterID fpr)
134 {
135 ASSERT(kind == BirthToFill || kind == Fill);
136 VariableEvent event;
137 WhichType which;
138 which.id = id.bits();
139 VariableRepresentation representation;
140 representation.fpr = fpr;
141 event.m_kind = kind;
142 event.m_dataFormat = DataFormatDouble;
143 event.m_which = WTFMove(which);
144 event.m_representation = WTFMove(representation);
145 return event;
146 }
147
148 static VariableEvent birth(MinifiedID id)
149 {
150 VariableEvent event;
151 WhichType which;
152 which.id = id.bits();
153 event.m_kind = Birth;
154 event.m_which = WTFMove(which);
155 return event;
156 }
157
158 static VariableEvent spill(VariableEventKind kind, MinifiedID id, VirtualRegister virtualRegister, DataFormat format)
159 {
160 ASSERT(kind == BirthToSpill || kind == Spill);
161 VariableEvent event;
162 WhichType which;
163 which.id = id.bits();
164 VariableRepresentation representation;
165 representation.virtualReg = virtualRegister.offset();
166 event.m_kind = kind;
167 event.m_dataFormat = format;
168 event.m_which = WTFMove(which);
169 event.m_representation = WTFMove(representation);
170 return event;
171 }
172
173 static VariableEvent death(MinifiedID id)
174 {
175 VariableEvent event;
176 WhichType which;
177 which.id = id.bits();
178 event.m_kind = Death;
179 event.m_which = WTFMove(which);
180 return event;
181 }
182
183 static VariableEvent setLocal(
184 VirtualRegister bytecodeReg, VirtualRegister machineReg, DataFormat format)
185 {
186 VariableEvent event;
187 WhichType which;
188 which.virtualReg = machineReg.offset();
189 VariableRepresentation representation;
190 representation.virtualReg = bytecodeReg.offset();
191 event.m_kind = SetLocalEvent;
192 event.m_dataFormat = format;
193 event.m_which = WTFMove(which);
194 event.m_representation = WTFMove(representation);
195 return event;
196 }
197
198 static VariableEvent movHint(MinifiedID id, VirtualRegister bytecodeReg)
199 {
200 VariableEvent event;
201 WhichType which;
202 which.id = id.bits();
203 VariableRepresentation representation;
204 representation.virtualReg = bytecodeReg.offset();
205 event.m_kind = MovHintEvent;
206 event.m_which = WTFMove(which);
207 event.m_representation = WTFMove(representation);
208 return event;
209 }
210
211 VariableEventKind kind() const
212 {
213 return static_cast<VariableEventKind>(m_kind);
214 }
215
216 MinifiedID id() const
217 {
218 ASSERT(
219 m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill
220 || m_kind == Death || m_kind == MovHintEvent || m_kind == Birth);
221 return MinifiedID::fromBits(m_which.get().id);
222 }
223
224 DataFormat dataFormat() const
225 {
226 ASSERT(
227 m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill
228 || m_kind == SetLocalEvent);
229 return m_dataFormat;
230 }
231
232 MacroAssembler::RegisterID gpr() const
233 {
234 ASSERT(m_kind == BirthToFill || m_kind == Fill);
235 ASSERT(m_dataFormat);
236 ASSERT(m_dataFormat != DataFormatDouble);
237#if USE(JSVALUE32_64)
238 ASSERT(!(m_dataFormat & DataFormatJS));
239#endif
240 return m_representation.get().gpr;
241 }
242
243#if USE(JSVALUE32_64)
244 MacroAssembler::RegisterID tagGPR() const
245 {
246 ASSERT(m_kind == BirthToFill || m_kind == Fill);
247 ASSERT(m_dataFormat & DataFormatJS);
248 return m_representation.get().pair.tagGPR;
249 }
250 MacroAssembler::RegisterID payloadGPR() const
251 {
252 ASSERT(m_kind == BirthToFill || m_kind == Fill);
253 ASSERT(m_dataFormat & DataFormatJS);
254 return m_representation.get().pair.payloadGPR;
255 }
256#endif // USE(JSVALUE32_64)
257
258 MacroAssembler::FPRegisterID fpr() const
259 {
260 ASSERT(m_kind == BirthToFill || m_kind == Fill);
261 ASSERT(m_dataFormat == DataFormatDouble);
262 return m_representation.get().fpr;
263 }
264
265 VirtualRegister spillRegister() const
266 {
267 ASSERT(m_kind == BirthToSpill || m_kind == Spill);
268 return VirtualRegister(m_representation.get().virtualReg);
269 }
270
271 VirtualRegister bytecodeRegister() const
272 {
273 ASSERT(m_kind == SetLocalEvent || m_kind == MovHintEvent);
274 return VirtualRegister(m_representation.get().virtualReg);
275 }
276
277 VirtualRegister machineRegister() const
278 {
279 ASSERT(m_kind == SetLocalEvent);
280 return VirtualRegister(m_which.get().virtualReg);
281 }
282
283 VariableRepresentation variableRepresentation() const { return m_representation.get(); }
284
285 void dump(PrintStream&) const;
286
287private:
288 void dumpFillInfo(const char* name, PrintStream&) const;
289 void dumpSpillInfo(const char* name, PrintStream&) const;
290
291 union WhichType {
292 int virtualReg;
293 unsigned id;
294 };
295 Packed<WhichType> m_which;
296
297 // For BirthToFill, Fill:
298 // - The GPR or FPR, or a GPR pair.
299 // For BirthToSpill, Spill:
300 // - The virtual register.
301 // For MovHintEvent, SetLocalEvent:
302 // - The bytecode operand.
303 // For Death:
304 // - Unused.
305 Packed<VariableRepresentation> m_representation;
306
307 VariableEventKind m_kind;
308 DataFormat m_dataFormat { DataFormatNone };
309};
310
311} } // namespace JSC::DFG
312
313#endif // ENABLE(DFG_JIT)
314