/*
* Copyright (C) 2011 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.
*/
#ifndef DFGNonSpeculativeJIT_h
#define DFGNonSpeculativeJIT_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGJITCodeGenerator.h>
namespace JSC { namespace DFG {
class SpeculationCheckIndexIterator;
// === EntryLocation ===
//
// This structure describes an entry point into the non-speculative
// code path. This is used in linking bail-outs from the speculative path.
struct EntryLocation {
EntryLocation(MacroAssembler::Label, NonSpeculativeJIT*);
// The node this entry point corresponds to, and the label
// marking the start of code for the given node.
MacroAssembler::Label m_entry;
NodeIndex m_nodeIndex;
// For every entry point we record a map recording for every
// machine register which, if any, values it contains. For
// GPR registers we must also record the format of the value.
struct RegisterInfo {
NodeIndex nodeIndex;
DataFormat format;
};
RegisterInfo m_gprInfo[numberOfGPRs];
NodeIndex m_fprInfo[numberOfFPRs];
};
// === NonSpeculativeJIT ===
//
// This class is used to generate code for the non-speculative path.
// Code generation will take advantage of static information available
// in the dataflow to perform safe optimizations - for example, avoiding
// boxing numeric values between arithmetic operations, but will not
// perform any unsafe optimizations that would render the code unable
// to produce the correct results for any possible input.
class NonSpeculativeJIT : public JITCodeGenerator {
friend struct EntryLocation;
public:
NonSpeculativeJIT(JITCompiler& jit)
: JITCodeGenerator(jit, false)
{
}
void compile(SpeculationCheckIndexIterator&);
typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
EntryLocationVector& entryLocations() { return m_entryLocations; }
private:
void compile(SpeculationCheckIndexIterator&, Node&);
void compile(SpeculationCheckIndexIterator&, BasicBlock&);
bool isKnownInteger(NodeIndex);
bool isKnownNumeric(NodeIndex);
// These methods are used when generating 'unexpected'
// calls out from JIT code to C++ helper routines -
// they spill all live values to the appropriate
// slots in the RegisterFile without changing any state
// in the GenerationInfo.
void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
if (!info.needsSpill() || (info.gpr() == exclude))
return;
DataFormat registerFormat = info.registerFormat();
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
if (registerFormat == DataFormatInteger) {
m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
} else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
}
}
void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() == DataFormatDouble);
if (!info.needsSpill() || (info.fpr() == exclude))
return;
boxDouble(info.fpr(), canTrample);
m_jit.storePtr(JITCompiler::gprToRegisterID(canTrample), JITCompiler::addressFor(spillMe));
}
void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
if (info.gpr() == exclude)
return;
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
DataFormat registerFormat = info.registerFormat();
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
if (registerFormat == DataFormatInteger) {
if (node.isConstant()) {
ASSERT(isInt32Constant(nodeIndex));
m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), reg);
} else
m_jit.load32(JITCompiler::addressFor(spillMe), reg);
return;
}
if (node.isConstant())
m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), reg);
}
}
void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
if (info.fpr() == exclude)
return;
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
ASSERT(info.registerFormat() == DataFormatDouble);
if (node.isConstant()) {
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
} else {
m_jit.loadPtr(JITCompiler::addressFor(spillMe), JITCompiler::gprToRegisterID(canTrample));
unboxDouble(canTrample, info.fpr());
}
}
void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
{
GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentSpillGPR(name, exclude);
}
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister)
silentSpillFPR(name, canTrample);
}
}
void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
{
GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentSpillGPR(name);
}
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister)
silentSpillFPR(name, canTrample, exclude);
}
}
void silentFillAllRegisters(GPRReg exclude)
{
GPRReg canTrample = (exclude == gpr0) ? gpr1 : gpr0;
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister)
silentFillFPR(name, canTrample);
}
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentFillGPR(name, exclude);
}
}
void silentFillAllRegisters(FPRReg exclude)
{
GPRReg canTrample = gpr0;
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister) {
#ifndef NDEBUG
ASSERT(fpr != exclude);
#else
UNUSED_PARAM(exclude);
#endif
silentFillFPR(name, canTrample, exclude);
}
}
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentFillGPR(name);
}
}
// These methods are used to plant calls out to C++
// helper routines to convert between types.
void valueToNumber(JSValueOperand&, FPRReg result);
void valueToInt32(JSValueOperand&, GPRReg result);
void numberToInt32(FPRReg, GPRReg result);
// Record an entry location into the non-speculative code path;
// for every bail-out on the speculative path we record information
// to be able to re-enter into the non-speculative one.
void trackEntry(MacroAssembler::Label entry)
{
m_entryLocations.append(EntryLocation(entry, this));
}
EntryLocationVector m_entryLocations;
};
} } // namespace JSC::DFG
#endif
#endif