| /* |
| * Copyright (C) 2012 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #if ENABLE(DFG_JIT) |
| |
| #include "DFGMinifiedID.h" |
| #include "DataFormat.h" |
| #include "MacroAssembler.h" |
| #include "Operands.h" |
| #include "VirtualRegister.h" |
| #include <stdio.h> |
| |
| namespace JSC { namespace DFG { |
| |
| enum VariableEventKind : uint8_t { |
| // Marks the beginning of a checkpoint. If you interpret the variable |
| // events starting at a Reset point then you'll get everything you need. |
| Reset, |
| |
| // Node births. Points in the code where a node becomes relevant for OSR. |
| // It may be the point where it is actually born (i.e. assigned) or it may |
| // be a later point, if it's only later in the sequence of instructions |
| // that we start to care about this node. |
| BirthToFill, |
| BirthToSpill, |
| Birth, |
| |
| // Events related to how a node is represented. |
| Fill, |
| Spill, |
| |
| // Death of a node - after this we no longer care about this node. |
| Death, |
| |
| // A MovHintEvent means that a node is being associated with a bytecode operand, |
| // but that it has not been stored into that operand. |
| MovHintEvent, |
| |
| // A SetLocalEvent means that a node's value has been stored into the stack. |
| SetLocalEvent, |
| |
| // Used to indicate an uninitialized VariableEvent. Don't use for other |
| // purposes. |
| InvalidEventKind |
| }; |
| |
| union VariableRepresentation { |
| VariableRepresentation() |
| : operand() |
| { } |
| |
| MacroAssembler::RegisterID gpr; |
| MacroAssembler::FPRegisterID fpr; |
| #if USE(JSVALUE32_64) |
| struct { |
| MacroAssembler::RegisterID tagGPR; |
| MacroAssembler::RegisterID payloadGPR; |
| } pair; |
| #endif |
| Operand operand; |
| }; |
| |
| class VariableEvent { |
| public: |
| VariableEvent() |
| : m_kind(InvalidEventKind) |
| { |
| } |
| |
| static VariableEvent reset() |
| { |
| VariableEvent event; |
| event.m_kind = Reset; |
| return event; |
| } |
| |
| static VariableEvent fillGPR(VariableEventKind kind, MinifiedID id, MacroAssembler::RegisterID gpr, DataFormat dataFormat) |
| { |
| ASSERT(kind == BirthToFill || kind == Fill); |
| ASSERT(dataFormat != DataFormatDouble); |
| #if USE(JSVALUE32_64) |
| ASSERT(!(dataFormat & DataFormatJS)); |
| #endif |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| VariableRepresentation representation; |
| representation.gpr = gpr; |
| event.m_kind = kind; |
| event.m_dataFormat = dataFormat; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| |
| #if USE(JSVALUE32_64) |
| static VariableEvent fillPair(VariableEventKind kind, MinifiedID id, MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR) |
| { |
| ASSERT(kind == BirthToFill || kind == Fill); |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| VariableRepresentation representation; |
| representation.pair.tagGPR = tagGPR; |
| representation.pair.payloadGPR = payloadGPR; |
| event.m_kind = kind; |
| event.m_dataFormat = DataFormatJS; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| #endif // USE(JSVALUE32_64) |
| |
| static VariableEvent fillFPR(VariableEventKind kind, MinifiedID id, MacroAssembler::FPRegisterID fpr) |
| { |
| ASSERT(kind == BirthToFill || kind == Fill); |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| VariableRepresentation representation; |
| representation.fpr = fpr; |
| event.m_kind = kind; |
| event.m_dataFormat = DataFormatDouble; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| |
| static VariableEvent birth(MinifiedID id) |
| { |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| event.m_kind = Birth; |
| event.m_which = WTFMove(which); |
| return event; |
| } |
| |
| static VariableEvent spill(VariableEventKind kind, MinifiedID id, VirtualRegister virtualRegister, DataFormat format) |
| { |
| ASSERT(kind == BirthToSpill || kind == Spill); |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| VariableRepresentation representation; |
| representation.operand = virtualRegister; |
| event.m_kind = kind; |
| event.m_dataFormat = format; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| |
| static VariableEvent death(MinifiedID id) |
| { |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| event.m_kind = Death; |
| event.m_which = WTFMove(which); |
| return event; |
| } |
| |
| static VariableEvent setLocal( |
| Operand bytecodeOperand, VirtualRegister machineReg, DataFormat format) |
| { |
| VariableEvent event; |
| WhichType which; |
| which.virtualReg = machineReg.offset(); |
| VariableRepresentation representation; |
| representation.operand = bytecodeOperand; |
| event.m_kind = SetLocalEvent; |
| event.m_dataFormat = format; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| |
| static VariableEvent movHint(MinifiedID id, Operand bytecodeReg) |
| { |
| VariableEvent event; |
| WhichType which; |
| which.id = id.bits(); |
| VariableRepresentation representation; |
| representation.operand = bytecodeReg; |
| event.m_kind = MovHintEvent; |
| event.m_which = WTFMove(which); |
| event.m_representation = WTFMove(representation); |
| return event; |
| } |
| |
| VariableEventKind kind() const |
| { |
| return static_cast<VariableEventKind>(m_kind); |
| } |
| |
| MinifiedID id() const |
| { |
| ASSERT( |
| m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill |
| || m_kind == Death || m_kind == MovHintEvent || m_kind == Birth); |
| return MinifiedID::fromBits(m_which.get().id); |
| } |
| |
| DataFormat dataFormat() const |
| { |
| ASSERT( |
| m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill |
| || m_kind == SetLocalEvent); |
| return m_dataFormat; |
| } |
| |
| MacroAssembler::RegisterID gpr() const |
| { |
| ASSERT(m_kind == BirthToFill || m_kind == Fill); |
| ASSERT(m_dataFormat); |
| ASSERT(m_dataFormat != DataFormatDouble); |
| #if USE(JSVALUE32_64) |
| ASSERT(!(m_dataFormat & DataFormatJS)); |
| #endif |
| return m_representation.get().gpr; |
| } |
| |
| #if USE(JSVALUE32_64) |
| MacroAssembler::RegisterID tagGPR() const |
| { |
| ASSERT(m_kind == BirthToFill || m_kind == Fill); |
| ASSERT(m_dataFormat & DataFormatJS); |
| return m_representation.get().pair.tagGPR; |
| } |
| MacroAssembler::RegisterID payloadGPR() const |
| { |
| ASSERT(m_kind == BirthToFill || m_kind == Fill); |
| ASSERT(m_dataFormat & DataFormatJS); |
| return m_representation.get().pair.payloadGPR; |
| } |
| #endif // USE(JSVALUE32_64) |
| |
| MacroAssembler::FPRegisterID fpr() const |
| { |
| ASSERT(m_kind == BirthToFill || m_kind == Fill); |
| ASSERT(m_dataFormat == DataFormatDouble); |
| return m_representation.get().fpr; |
| } |
| |
| VirtualRegister spillRegister() const |
| { |
| ASSERT(m_kind == BirthToSpill || m_kind == Spill); |
| return m_representation.get().operand.virtualRegister(); |
| } |
| |
| Operand operand() const |
| { |
| ASSERT(m_kind == SetLocalEvent || m_kind == MovHintEvent); |
| return m_representation.get().operand; |
| } |
| |
| VirtualRegister machineRegister() const |
| { |
| ASSERT(m_kind == SetLocalEvent); |
| return VirtualRegister(m_which.get().virtualReg); |
| } |
| |
| VariableRepresentation variableRepresentation() const { return m_representation.get(); } |
| |
| void dump(PrintStream&) const; |
| |
| private: |
| void dumpFillInfo(const char* name, PrintStream&) const; |
| void dumpSpillInfo(const char* name, PrintStream&) const; |
| |
| union WhichType { |
| int virtualReg; |
| unsigned id; |
| }; |
| Packed<WhichType> m_which; |
| |
| // For BirthToFill, Fill: |
| // - The GPR or FPR, or a GPR pair. |
| // For BirthToSpill, Spill: |
| // - The virtual register. |
| // For MovHintEvent, SetLocalEvent: |
| // - The bytecode operand. |
| // For Death: |
| // - Unused. |
| Packed<VariableRepresentation> m_representation; |
| |
| VariableEventKind m_kind; |
| DataFormat m_dataFormat { DataFormatNone }; |
| }; |
| |
| } } // namespace JSC::DFG |
| |
| #endif // ENABLE(DFG_JIT) |