DFGJITCodeGenerator.cpp [plain text]
#include "config.h"
#include "DFGJITCodeGenerator.h"
#if ENABLE(DFG_JIT)
#include "DFGNonSpeculativeJIT.h"
#include "DFGSpeculativeJIT.h"
#include "LinkBuffer.h"
namespace JSC { namespace DFG {
GPRReg JITCodeGenerator::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat)
{
Node& node = m_jit.graph()[nodeIndex];
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
GPRReg gpr = allocate();
if (node.isConstant()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
if (isInt32Constant(nodeIndex)) {
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
info.fillInteger(gpr);
returnFormat = DataFormatInteger;
return gpr;
}
if (isDoubleConstant(nodeIndex)) {
JSValue jsValue = jsNumber(valueOfDoubleConstant(nodeIndex));
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
}
} else {
ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
}
info.fillJSValue(gpr, DataFormatJSInteger);
unlock(gpr);
}
switch (info.registerFormat()) {
case DataFormatNone:
case DataFormatJSDouble:
case DataFormatDouble:
case DataFormatJS:
case DataFormatCell:
case DataFormatJSCell:
ASSERT_NOT_REACHED();
case DataFormatJSInteger: {
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
m_jit.jitAssertIsJSInt32(gpr);
returnFormat = DataFormatJSInteger;
return gpr;
}
case DataFormatInteger: {
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
m_jit.jitAssertIsInt32(gpr);
returnFormat = DataFormatInteger;
return gpr;
}
}
ASSERT_NOT_REACHED();
return InvalidGPRReg;
}
FPRReg JITCodeGenerator::fillDouble(NodeIndex nodeIndex)
{
Node& node = m_jit.graph()[nodeIndex];
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
GPRReg gpr = allocate();
if (node.isConstant()) {
if (isInt32Constant(nodeIndex)) {
m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
info.fillInteger(gpr);
unlock(gpr);
} else if (isDoubleConstant(nodeIndex)) {
FPRReg fpr = fprAllocate();
m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), gpr);
m_jit.movePtrToDouble(gpr, fpr);
unlock(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
info.fillDouble(fpr);
return fpr;
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
info.fillJSValue(gpr, DataFormatJS);
unlock(gpr);
}
} else {
DataFormat spillFormat = info.spillFormat();
ASSERT(spillFormat & DataFormatJS);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
unlock(gpr);
}
}
switch (info.registerFormat()) {
case DataFormatNone:
case DataFormatCell:
case DataFormatJSCell:
ASSERT_NOT_REACHED();
case DataFormatJS: {
GPRReg jsValueGpr = info.gpr();
m_gprs.lock(jsValueGpr);
FPRReg fpr = fprAllocate();
GPRReg tempGpr = allocate();
JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
m_jit.jitAssertIsJSDouble(jsValueGpr);
m_jit.move(jsValueGpr, tempGpr);
m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
m_jit.movePtrToDouble(tempGpr, fpr);
JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
isInteger.link(&m_jit);
m_jit.convertInt32ToDouble(jsValueGpr, fpr);
hasUnboxedDouble.link(&m_jit);
m_gprs.release(jsValueGpr);
m_gprs.unlock(jsValueGpr);
m_gprs.unlock(tempGpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
info.fillDouble(fpr);
return fpr;
}
case DataFormatJSInteger:
case DataFormatInteger: {
FPRReg fpr = fprAllocate();
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
m_jit.convertInt32ToDouble(gpr, fpr);
m_gprs.release(gpr);
m_gprs.unlock(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
info.fillDouble(fpr);
return fpr;
}
case DataFormatJSDouble: {
GPRReg gpr = info.gpr();
FPRReg fpr = unboxDouble(gpr);
m_gprs.release(gpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
info.fillDouble(fpr);
return fpr;
}
case DataFormatDouble: {
FPRReg fpr = info.fpr();
m_fprs.lock(fpr);
return fpr;
}
}
ASSERT_NOT_REACHED();
return InvalidFPRReg;
}
GPRReg JITCodeGenerator::fillJSValue(NodeIndex nodeIndex)
{
Node& node = m_jit.graph()[nodeIndex];
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
GPRReg gpr = allocate();
if (node.isConstant()) {
if (isInt32Constant(nodeIndex)) {
info.fillJSValue(gpr, DataFormatJSInteger);
JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
} else if (isDoubleConstant(nodeIndex)) {
info.fillJSValue(gpr, DataFormatJSDouble);
JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex));
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
info.fillJSValue(gpr, DataFormatJS);
}
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
} else {
DataFormat spillFormat = info.spillFormat();
ASSERT(spillFormat & DataFormatJS);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
}
return gpr;
}
case DataFormatInteger: {
GPRReg gpr = info.gpr();
if (m_gprs.isLocked(gpr)) {
GPRReg result = allocate();
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr, result);
return result;
}
m_gprs.lock(gpr);
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr);
info.fillJSValue(gpr, DataFormatJSInteger);
return gpr;
}
case DataFormatDouble: {
FPRReg fpr = info.fpr();
GPRReg gpr = boxDouble(fpr);
info.fillJSValue(gpr, DataFormatJSDouble);
m_fprs.release(fpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderJS);
return gpr;
}
case DataFormatCell:
case DataFormatJS:
case DataFormatJSInteger:
case DataFormatJSDouble:
case DataFormatJSCell: {
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
return gpr;
}
}
ASSERT_NOT_REACHED();
return InvalidGPRReg;
}
void JITCodeGenerator::useChildren(Node& node)
{
NodeIndex child1 = node.child1;
if (child1 == NoNode) {
ASSERT(node.child2 == NoNode && node.child3 == NoNode);
return;
}
use(child1);
NodeIndex child2 = node.child2;
if (child2 == NoNode) {
ASSERT(node.child3 == NoNode);
return;
}
use(child2);
NodeIndex child3 = node.child3;
if (child3 == NoNode)
return;
use(child3);
}
#ifndef NDEBUG
static const char* dataFormatString(DataFormat format)
{
const char* strings[] = {
"[ ]",
"[ i]",
"[ d]",
"[ c]",
"Err!",
"Err!",
"Err!",
"Err!",
"[J ]",
"[Ji]",
"[Jd]",
"[Jc]",
"Err!",
"Err!",
"Err!",
"Err!",
};
return strings[format];
}
void JITCodeGenerator::dump(const char* label)
{
if (label)
fprintf(stderr, "<%s>\n", label);
fprintf(stderr, " gprs:\n");
m_gprs.dump();
fprintf(stderr, " fprs:\n");
m_fprs.dump();
fprintf(stderr, " VirtualRegisters:\n");
for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
GenerationInfo& info = m_generationInfo[i];
if (info.alive())
fprintf(stderr, " % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
else
fprintf(stderr, " % 3d:[__][__]", i);
if (info.registerFormat() == DataFormatDouble)
fprintf(stderr, ":fpr%d\n", info.fpr());
else if (info.registerFormat() != DataFormatNone) {
ASSERT(info.gpr() != InvalidGPRReg);
fprintf(stderr, ":%s\n", GPRInfo::debugName(info.gpr()));
} else
fprintf(stderr, "\n");
}
if (label)
fprintf(stderr, "</%s>\n", label);
}
#endif
#if DFG_CONSISTENCY_CHECK
void JITCodeGenerator::checkConsistency()
{
bool failed = false;
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.isLocked()) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
failed = true;
}
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.isLocked()) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
failed = true;
}
}
for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
VirtualRegister virtualRegister = (VirtualRegister)i;
GenerationInfo& info = m_generationInfo[virtualRegister];
if (!info.alive())
continue;
switch (info.registerFormat()) {
case DataFormatNone:
break;
case DataFormatInteger:
case DataFormatCell:
case DataFormatJS:
case DataFormatJSInteger:
case DataFormatJSDouble:
case DataFormatJSCell: {
GPRReg gpr = info.gpr();
ASSERT(gpr != InvalidGPRReg);
if (m_gprs.name(gpr) != virtualRegister) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
failed = true;
}
break;
}
case DataFormatDouble: {
FPRReg fpr = info.fpr();
ASSERT(fpr != InvalidFPRReg);
if (m_fprs.name(fpr) != virtualRegister) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
failed = true;
}
break;
}
}
}
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
VirtualRegister virtualRegister = iter.name();
if (virtualRegister == InvalidVirtualRegister)
continue;
GenerationInfo& info = m_generationInfo[virtualRegister];
if (iter.regID() != info.gpr()) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
VirtualRegister virtualRegister = iter.name();
if (virtualRegister == InvalidVirtualRegister)
continue;
GenerationInfo& info = m_generationInfo[virtualRegister];
if (iter.regID() != info.fpr()) {
fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
failed = true;
}
}
if (failed) {
dump();
CRASH();
}
}
#endif
GPRTemporary::GPRTemporary(JITCodeGenerator* jit)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1, SpeculateIntegerOperand& op2)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else if (m_jit->canReuse(op2.index()))
m_gpr = m_jit->reuse(op2.gpr());
else
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1, IntegerOperand& op2)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else if (m_jit->canReuse(op2.index()))
m_gpr = m_jit->reuse(op2.gpr());
else
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateCellOperand& op1)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else
m_gpr = m_jit->allocate();
}
GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1)
: m_jit(jit)
, m_gpr(InvalidGPRReg)
{
if (m_jit->canReuse(op1.index()))
m_gpr = m_jit->reuse(op1.gpr());
else
m_gpr = m_jit->allocate();
}
FPRTemporary::FPRTemporary(JITCodeGenerator* jit)
: m_jit(jit)
, m_fpr(InvalidFPRReg)
{
m_fpr = m_jit->fprAllocate();
}
FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1)
: m_jit(jit)
, m_fpr(InvalidFPRReg)
{
if (m_jit->canReuse(op1.index()))
m_fpr = m_jit->reuse(op1.fpr());
else
m_fpr = m_jit->fprAllocate();
}
FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1, DoubleOperand& op2)
: m_jit(jit)
, m_fpr(InvalidFPRReg)
{
if (m_jit->canReuse(op1.index()))
m_fpr = m_jit->reuse(op1.fpr());
else if (m_jit->canReuse(op2.index()))
m_fpr = m_jit->reuse(op2.fpr());
else
m_fpr = m_jit->fprAllocate();
}
} }
#endif