|  | /* | 
|  | * 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) |