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#ifndef DFGVariableEvent_h
27#define DFGVariableEvent_h
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGCommon.h"
32#include "DFGMinifiedID.h"
33#include "DataFormat.h"
34#include "MacroAssembler.h"
35#include <stdio.h>
36
37namespace JSC { namespace DFG {
38
39enum VariableEventKind {
40    // Marks the beginning of a checkpoint. If you interpret the variable
41    // events starting at a Reset point then you'll get everything you need.
42    Reset,
43
44    // Node births. Points in the code where a node becomes relevant for OSR.
45    // It may be the point where it is actually born (i.e. assigned) or it may
46    // be a later point, if it's only later in the sequence of instructions
47    // that we start to care about this node.
48    BirthToFill,
49    BirthToSpill,
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        event.m_which.id = id.bits();
105        event.m_representation.gpr = gpr;
106        event.m_kind = kind;
107        event.m_dataFormat = dataFormat;
108        return event;
109    }
110
111#if USE(JSVALUE32_64)
112    static VariableEvent fillPair(VariableEventKind kind, MinifiedID id, MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
113    {
114        ASSERT(kind == BirthToFill || kind == Fill);
115        VariableEvent event;
116        event.m_which.id = id.bits();
117        event.m_representation.pair.tagGPR = tagGPR;
118        event.m_representation.pair.payloadGPR = payloadGPR;
119        event.m_kind = kind;
120        event.m_dataFormat = DataFormatJS;
121        return event;
122    }
123#endif // USE(JSVALUE32_64)
124
125    static VariableEvent fillFPR(VariableEventKind kind, MinifiedID id, MacroAssembler::FPRegisterID fpr)
126    {
127        ASSERT(kind == BirthToFill || kind == Fill);
128        VariableEvent event;
129        event.m_which.id = id.bits();
130        event.m_representation.fpr = fpr;
131        event.m_kind = kind;
132        event.m_dataFormat = DataFormatDouble;
133        return event;
134    }
135
136    static VariableEvent spill(VariableEventKind kind, MinifiedID id, VirtualRegister virtualRegister, DataFormat format)
137    {
138        ASSERT(kind == BirthToSpill || kind == Spill);
139        VariableEvent event;
140        event.m_which.id = id.bits();
141        event.m_representation.virtualReg = virtualRegister.offset();
142        event.m_kind = kind;
143        event.m_dataFormat = format;
144        return event;
145    }
146
147    static VariableEvent death(MinifiedID id)
148    {
149        VariableEvent event;
150        event.m_which.id = id.bits();
151        event.m_kind = Death;
152        return event;
153    }
154
155    static VariableEvent setLocal(
156        VirtualRegister bytecodeReg, VirtualRegister machineReg, DataFormat format)
157    {
158        VariableEvent event;
159        event.m_which.virtualReg = machineReg.offset();
160        event.m_representation.virtualReg = bytecodeReg.offset();
161        event.m_kind = SetLocalEvent;
162        event.m_dataFormat = format;
163        return event;
164    }
165
166    static VariableEvent movHint(MinifiedID id, VirtualRegister bytecodeReg)
167    {
168        VariableEvent event;
169        event.m_which.id = id.bits();
170        event.m_representation.virtualReg = bytecodeReg.offset();
171        event.m_kind = MovHintEvent;
172        return event;
173    }
174
175    VariableEventKind kind() const
176    {
177        return static_cast<VariableEventKind>(m_kind);
178    }
179
180    MinifiedID id() const
181    {
182        ASSERT(m_kind == BirthToFill || m_kind == Fill
183               || m_kind == BirthToSpill || m_kind == Spill
184               || m_kind == Death || m_kind == MovHintEvent);
185        return MinifiedID::fromBits(m_which.id);
186    }
187
188    DataFormat dataFormat() const
189    {
190        ASSERT(m_kind == BirthToFill || m_kind == Fill
191               || m_kind == BirthToSpill || m_kind == Spill
192               || m_kind == SetLocalEvent);
193        return static_cast<DataFormat>(m_dataFormat);
194    }
195
196    MacroAssembler::RegisterID gpr() const
197    {
198        ASSERT(m_kind == BirthToFill || m_kind == Fill);
199        ASSERT(m_dataFormat);
200        ASSERT(m_dataFormat != DataFormatDouble);
201#if USE(JSVALUE32_64)
202        ASSERT(!(m_dataFormat & DataFormatJS));
203#endif
204        return m_representation.gpr;
205    }
206
207#if USE(JSVALUE32_64)
208    MacroAssembler::RegisterID tagGPR() const
209    {
210        ASSERT(m_kind == BirthToFill || m_kind == Fill);
211        ASSERT(m_dataFormat & DataFormatJS);
212        return m_representation.pair.tagGPR;
213    }
214    MacroAssembler::RegisterID payloadGPR() const
215    {
216        ASSERT(m_kind == BirthToFill || m_kind == Fill);
217        ASSERT(m_dataFormat & DataFormatJS);
218        return m_representation.pair.payloadGPR;
219    }
220#endif // USE(JSVALUE32_64)
221
222    MacroAssembler::FPRegisterID fpr() const
223    {
224        ASSERT(m_kind == BirthToFill || m_kind == Fill);
225        ASSERT(m_dataFormat == DataFormatDouble);
226        return m_representation.fpr;
227    }
228
229    VirtualRegister spillRegister() const
230    {
231        ASSERT(m_kind == BirthToSpill || m_kind == Spill);
232        return VirtualRegister(m_representation.virtualReg);
233    }
234
235    VirtualRegister bytecodeRegister() const
236    {
237        ASSERT(m_kind == SetLocalEvent || m_kind == MovHintEvent);
238        return VirtualRegister(m_representation.virtualReg);
239    }
240
241    VirtualRegister machineRegister() const
242    {
243        ASSERT(m_kind == SetLocalEvent);
244        return VirtualRegister(m_which.virtualReg);
245    }
246
247    const VariableRepresentation& variableRepresentation() const { return m_representation; }
248
249    void dump(PrintStream&) const;
250
251private:
252    void dumpFillInfo(const char* name, PrintStream&) const;
253    void dumpSpillInfo(const char* name, PrintStream&) const;
254
255    union {
256        int virtualReg;
257        uintptr_t id;
258    } m_which;
259
260    // For BirthToFill, Fill:
261    //   - The GPR or FPR, or a GPR pair.
262    // For BirthToSpill, Spill:
263    //   - The virtual register.
264    // For MovHintEvent, SetLocalEvent:
265    //   - The bytecode operand.
266    // For Death:
267    //   - Unused.
268    VariableRepresentation m_representation;
269
270    int8_t m_kind;
271    int8_t m_dataFormat;
272};
273
274} } // namespace JSC::DFG
275
276#endif // ENABLE(DFG_JIT)
277
278#endif // DFGVariableEvent_h
279
280