summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-05-25 15:09:11 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-05-25 15:09:11 +0200
commita89b2ebb8e192c5e8cea21079bda2ee2c0c7dddd (patch)
treeb7abd9f49ae1d4d2e426a5883bfccd42b8e2ee12 /Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
parent8d473cf9743f1d30a16a27114e93bd5af5648d23 (diff)
downloadqtwebkit-a89b2ebb8e192c5e8cea21079bda2ee2c0c7dddd.tar.gz
Imported WebKit commit eb5c1b8fe4d4b1b90b5137433fc58a91da0e6878 (http://svn.webkit.org/repository/webkit/trunk@118516)
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h686
1 files changed, 486 insertions, 200 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 6f8dc1156..912078a79 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -33,12 +33,14 @@
#include "DFGJITCompiler.h"
#include "DFGOSRExit.h"
#include "DFGOperations.h"
+#include "DFGSilentRegisterSavePlan.h"
#include "MarkedAllocator.h"
#include "ValueRecovery.h"
namespace JSC { namespace DFG {
class JSValueOperand;
+class SlowPathGenerator;
class SpeculativeJIT;
class SpeculateIntegerOperand;
class SpeculateStrictInt32Operand;
@@ -54,6 +56,7 @@ enum ValueSourceKind {
CellInRegisterFile,
BooleanInRegisterFile,
DoubleInRegisterFile,
+ ArgumentsSource,
SourceIsDead,
HaveNode
};
@@ -176,6 +179,7 @@ private:
public:
SpeculativeJIT(JITCompiler&);
+ ~SpeculativeJIT();
bool compile();
void createOSREntries();
@@ -190,6 +194,16 @@ public:
return at(nodeUse.index());
}
+ BlockIndex nextBlock()
+ {
+ for (BlockIndex result = m_block + 1; ; result++) {
+ if (result >= m_jit.graph().m_blocks.size())
+ return NoBlock;
+ if (m_jit.graph().m_blocks[result])
+ return result;
+ }
+ }
+
GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
FPRReg fillDouble(NodeIndex);
#if USE(JSVALUE64)
@@ -304,7 +318,10 @@ public:
// Called on an operand once it has been consumed by a parent node.
void use(NodeIndex nodeIndex)
{
- VirtualRegister virtualRegister = at(nodeIndex).virtualRegister();
+ Node& node = at(nodeIndex);
+ if (!node.hasResult())
+ return;
+ VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
// use() returns true when the value becomes dead, and any
@@ -355,7 +372,9 @@ public:
GPRReg fillSpeculateBoolean(NodeIndex);
GeneratedOperandType checkGeneratedTypeForToInt32(NodeIndex);
-private:
+ void addSlowPathGenerator(PassOwnPtr<SlowPathGenerator>);
+ void runSlowPathGenerators();
+
void compile(Node&);
void compileMovHint(Node&);
void compile(BasicBlock&);
@@ -369,243 +388,355 @@ private:
// they spill all live values to the appropriate
// slots in the RegisterFile without changing any state
// in the GenerationInfo.
- void silentSpillGPR(VirtualRegister spillMe, GPRReg source)
+ SilentRegisterSavePlan silentSavePlanForGPR(VirtualRegister spillMe, GPRReg source)
{
GenerationInfo& info = m_generationInfo[spillMe];
- ASSERT(info.registerFormat() != DataFormatNone);
- ASSERT(info.registerFormat() != DataFormatDouble);
-
- if (!info.needsSpill())
- return;
-
+ NodeIndex nodeIndex = info.nodeIndex();
+ Node& node = at(nodeIndex);
DataFormat registerFormat = info.registerFormat();
-
-#if USE(JSVALUE64)
- ASSERT(info.gpr() == source);
- if (registerFormat == DataFormatInteger)
- m_jit.store32(source, JITCompiler::addressFor(spillMe));
+ ASSERT(registerFormat != DataFormatNone);
+ ASSERT(registerFormat != DataFormatDouble);
+
+ SilentSpillAction spillAction;
+ SilentFillAction fillAction;
+
+ if (!info.needsSpill())
+ spillAction = DoNothingForSpill;
else {
- ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage);
- m_jit.storePtr(source, JITCompiler::addressFor(spillMe));
- }
-#elif USE(JSVALUE32_64)
- if (registerFormat & DataFormatJS) {
- ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
- m_jit.store32(source, source == info.tagGPR() ? JITCompiler::tagFor(spillMe) : JITCompiler::payloadFor(spillMe));
- } else {
+#if USE(JSVALUE64)
ASSERT(info.gpr() == source);
- m_jit.store32(source, JITCompiler::payloadFor(spillMe));
- }
+ if (registerFormat == DataFormatInteger)
+ spillAction = Store32Payload;
+ else {
+ ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage);
+ spillAction = StorePtr;
+ }
+#elif USE(JSVALUE32_64)
+ if (registerFormat & DataFormatJS) {
+ ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
+ spillAction = source == info.tagGPR() ? Store32Tag : Store32Payload;
+ } else {
+ ASSERT(info.gpr() == source);
+ spillAction = Store32Payload;
+ }
#endif
- }
- void silentSpillFPR(VirtualRegister spillMe, FPRReg source)
- {
- GenerationInfo& info = m_generationInfo[spillMe];
- ASSERT(info.registerFormat() == DataFormatDouble);
-
- if (!info.needsSpill()) {
- // it's either a constant or it's already been spilled
- ASSERT(at(info.nodeIndex()).hasConstant() || info.spillFormat() != DataFormatNone);
- return;
}
- // it's neither a constant nor has it been spilled.
- ASSERT(!at(info.nodeIndex()).hasConstant());
- ASSERT(info.spillFormat() == DataFormatNone);
- ASSERT(info.fpr() == source);
-
- m_jit.storeDouble(source, JITCompiler::addressFor(spillMe));
- }
-
- void silentFillGPR(VirtualRegister spillMe, GPRReg target)
- {
- GenerationInfo& info = m_generationInfo[spillMe];
-
- NodeIndex nodeIndex = info.nodeIndex();
- Node& node = at(nodeIndex);
- ASSERT(info.registerFormat() != DataFormatNone);
- ASSERT(info.registerFormat() != DataFormatDouble);
- DataFormat registerFormat = info.registerFormat();
-
if (registerFormat == DataFormatInteger) {
- ASSERT(info.gpr() == target);
+ ASSERT(info.gpr() == source);
ASSERT(isJSInteger(info.registerFormat()));
if (node.hasConstant()) {
ASSERT(isInt32Constant(nodeIndex));
- m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), target);
+ fillAction = SetInt32Constant;
} else
- m_jit.load32(JITCompiler::payloadFor(spillMe), target);
- return;
- }
-
- if (registerFormat == DataFormatBoolean) {
+ fillAction = Load32Payload;
+ } else if (registerFormat == DataFormatBoolean) {
#if USE(JSVALUE64)
ASSERT_NOT_REACHED();
+ fillAction = DoNothingForFill;
#elif USE(JSVALUE32_64)
- ASSERT(info.gpr() == target);
+ ASSERT(info.gpr() == source);
if (node.hasConstant()) {
ASSERT(isBooleanConstant(nodeIndex));
- m_jit.move(TrustedImm32(valueOfBooleanConstant(nodeIndex)), target);
+ fillAction = SetBooleanConstant;
} else
- m_jit.load32(JITCompiler::payloadFor(spillMe), target);
+ fillAction = Load32Payload;
#endif
- return;
- }
-
- if (registerFormat == DataFormatCell) {
- ASSERT(info.gpr() == target);
+ } else if (registerFormat == DataFormatCell) {
+ ASSERT(info.gpr() == source);
if (node.hasConstant()) {
JSValue value = valueOfJSConstant(nodeIndex);
- ASSERT(value.isCell());
- m_jit.move(TrustedImmPtr(value.asCell()), target);
- } else
- m_jit.loadPtr(JITCompiler::payloadFor(spillMe), target);
- return;
- }
-
- if (registerFormat == DataFormatStorage) {
- ASSERT(info.gpr() == target);
- m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
- return;
- }
-
- ASSERT(registerFormat & DataFormatJS);
+ ASSERT_UNUSED(value, value.isCell());
+ fillAction = SetCellConstant;
+ } else {
#if USE(JSVALUE64)
- ASSERT(info.gpr() == target);
- if (node.hasConstant()) {
- if (valueOfJSConstant(nodeIndex).isCell())
- m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex).asTrustedImmPtr(), target);
- else
- m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), target);
- } else if (info.spillFormat() == DataFormatInteger) {
- ASSERT(registerFormat == DataFormatJSInteger);
- m_jit.load32(JITCompiler::payloadFor(spillMe), target);
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, target);
- } else if (info.spillFormat() == DataFormatDouble) {
- ASSERT(registerFormat == DataFormatJSDouble);
- m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
- m_jit.subPtr(GPRInfo::tagTypeNumberRegister, target);
- } else
- m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
+ fillAction = LoadPtr;
#else
- ASSERT(info.tagGPR() == target || info.payloadGPR() == target);
- if (node.hasConstant()) {
- JSValue v = valueOfJSConstant(nodeIndex);
- m_jit.move(info.tagGPR() == target ? Imm32(v.tag()) : Imm32(v.payload()), target);
- } else if (info.payloadGPR() == target)
- m_jit.load32(JITCompiler::payloadFor(spillMe), target);
- else { // Fill the Tag
- switch (info.spillFormat()) {
- case DataFormatInteger:
+ fillAction = Load32Payload;
+#endif
+ }
+ } else if (registerFormat == DataFormatStorage) {
+ ASSERT(info.gpr() == source);
+ fillAction = LoadPtr;
+ } else {
+ ASSERT(registerFormat & DataFormatJS);
+#if USE(JSVALUE64)
+ ASSERT(info.gpr() == source);
+ if (node.hasConstant()) {
+ if (valueOfJSConstant(nodeIndex).isCell())
+ fillAction = SetTrustedJSConstant;
+ else
+ fillAction = SetJSConstant;
+ } else if (info.spillFormat() == DataFormatInteger) {
ASSERT(registerFormat == DataFormatJSInteger);
- m_jit.move(TrustedImm32(JSValue::Int32Tag), target);
- break;
- case DataFormatCell:
- ASSERT(registerFormat == DataFormatJSCell);
- m_jit.move(TrustedImm32(JSValue::CellTag), target);
- break;
- case DataFormatBoolean:
- ASSERT(registerFormat == DataFormatJSBoolean);
- m_jit.move(TrustedImm32(JSValue::BooleanTag), target);
- break;
- default:
- m_jit.load32(JITCompiler::tagFor(spillMe), target);
- break;
+ fillAction = Load32PayloadBoxInt;
+ } else if (info.spillFormat() == DataFormatDouble) {
+ ASSERT(registerFormat == DataFormatJSDouble);
+ fillAction = LoadDoubleBoxDouble;
+ } else
+ fillAction = LoadPtr;
+#else
+ ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
+ if (node.hasConstant())
+ fillAction = info.tagGPR() == source ? SetJSConstantTag : SetJSConstantPayload;
+ else if (info.payloadGPR() == source)
+ fillAction = Load32Payload;
+ else { // Fill the Tag
+ switch (info.spillFormat()) {
+ case DataFormatInteger:
+ ASSERT(registerFormat == DataFormatJSInteger);
+ fillAction = SetInt32Tag;
+ break;
+ case DataFormatCell:
+ ASSERT(registerFormat == DataFormatJSCell);
+ fillAction = SetCellTag;
+ break;
+ case DataFormatBoolean:
+ ASSERT(registerFormat == DataFormatJSBoolean);
+ fillAction = SetBooleanTag;
+ break;
+ default:
+ fillAction = Load32Tag;
+ break;
+ }
}
- }
#endif
+ }
+
+ return SilentRegisterSavePlan(spillAction, fillAction, nodeIndex, source);
}
-
- void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg target)
+
+ SilentRegisterSavePlan silentSavePlanForFPR(VirtualRegister spillMe, FPRReg source)
{
GenerationInfo& info = m_generationInfo[spillMe];
- ASSERT(info.fpr() == target);
-
NodeIndex nodeIndex = info.nodeIndex();
Node& node = at(nodeIndex);
-#if USE(JSVALUE64)
ASSERT(info.registerFormat() == DataFormatDouble);
- if (node.hasConstant()) {
- ASSERT(isNumberConstant(nodeIndex));
- m_jit.move(ImmPtr(bitwise_cast<void*>(valueOfNumberConstant(nodeIndex))), canTrample);
- m_jit.movePtrToDouble(canTrample, target);
- return;
+ SilentSpillAction spillAction;
+ SilentFillAction fillAction;
+
+ if (!info.needsSpill())
+ spillAction = DoNothingForSpill;
+ else {
+ ASSERT(!at(info.nodeIndex()).hasConstant());
+ ASSERT(info.spillFormat() == DataFormatNone);
+ ASSERT(info.fpr() == source);
+ spillAction = StoreDouble;
}
- if (info.spillFormat() != DataFormatNone && info.spillFormat() != DataFormatDouble) {
+#if USE(JSVALUE64)
+ if (node.hasConstant()) {
+ ASSERT(isNumberConstant(nodeIndex));
+ fillAction = SetDoubleConstant;
+ } else if (info.spillFormat() != DataFormatNone && info.spillFormat() != DataFormatDouble) {
// it was already spilled previously and not as a double, which means we need unboxing.
ASSERT(info.spillFormat() & DataFormatJS);
- m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
- unboxDouble(canTrample, target);
- return;
- }
-
- m_jit.loadDouble(JITCompiler::addressFor(spillMe), target);
+ fillAction = LoadJSUnboxDouble;
+ } else
+ fillAction = LoadDouble;
#elif USE(JSVALUE32_64)
- UNUSED_PARAM(canTrample);
ASSERT(info.registerFormat() == DataFormatDouble || info.registerFormat() == DataFormatJSDouble);
if (node.hasConstant()) {
ASSERT(isNumberConstant(nodeIndex));
- m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), target);
+ fillAction = SetDoubleConstant;
} else
- m_jit.loadDouble(JITCompiler::addressFor(spillMe), target);
+ fillAction = LoadDouble;
#endif
- }
- void silentSpillAllRegisters(GPRReg exclude, GPRReg exclude2 = InvalidGPRReg)
+ return SilentRegisterSavePlan(spillAction, fillAction, nodeIndex, source);
+ }
+
+ void silentSpill(const SilentRegisterSavePlan& plan)
{
- for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- GPRReg gpr = iter.regID();
- if (iter.name() != InvalidVirtualRegister && gpr != exclude && gpr != exclude2)
- silentSpillGPR(iter.name(), gpr);
+ switch (plan.spillAction()) {
+ case DoNothingForSpill:
+ break;
+ case Store32Tag:
+ m_jit.store32(plan.gpr(), JITCompiler::tagFor(at(plan.nodeIndex()).virtualRegister()));
+ break;
+ case Store32Payload:
+ m_jit.store32(plan.gpr(), JITCompiler::payloadFor(at(plan.nodeIndex()).virtualRegister()));
+ break;
+ case StorePtr:
+ m_jit.storePtr(plan.gpr(), JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()));
+ break;
+ case StoreDouble:
+ m_jit.storeDouble(plan.fpr(), JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
}
- for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- if (iter.name() != InvalidVirtualRegister)
- silentSpillFPR(iter.name(), iter.regID());
+ }
+
+ void silentFill(const SilentRegisterSavePlan& plan, GPRReg canTrample)
+ {
+#if USE(JSVALUE32_64)
+ UNUSED_PARAM(canTrample);
+#endif
+ switch (plan.fillAction()) {
+ case DoNothingForFill:
+ break;
+ case SetInt32Constant:
+ m_jit.move(Imm32(valueOfInt32Constant(plan.nodeIndex())), plan.gpr());
+ break;
+ case SetBooleanConstant:
+ m_jit.move(TrustedImm32(valueOfBooleanConstant(plan.nodeIndex())), plan.gpr());
+ break;
+ case SetCellConstant:
+ m_jit.move(TrustedImmPtr(valueOfJSConstant(plan.nodeIndex()).asCell()), plan.gpr());
+ break;
+#if USE(JSVALUE64)
+ case SetTrustedJSConstant:
+ m_jit.move(valueOfJSConstantAsImmPtr(plan.nodeIndex()).asTrustedImmPtr(), plan.gpr());
+ break;
+ case SetJSConstant:
+ m_jit.move(valueOfJSConstantAsImmPtr(plan.nodeIndex()), plan.gpr());
+ break;
+ case SetDoubleConstant:
+ m_jit.move(ImmPtr(bitwise_cast<void*>(valueOfNumberConstant(plan.nodeIndex()))), canTrample);
+ m_jit.movePtrToDouble(canTrample, plan.fpr());
+ break;
+ case Load32PayloadBoxInt:
+ m_jit.load32(JITCompiler::payloadFor(at(plan.nodeIndex()).virtualRegister()), plan.gpr());
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, plan.gpr());
+ break;
+ case LoadDoubleBoxDouble:
+ m_jit.loadPtr(JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()), plan.gpr());
+ m_jit.subPtr(GPRInfo::tagTypeNumberRegister, plan.gpr());
+ break;
+ case LoadJSUnboxDouble:
+ m_jit.loadPtr(JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()), canTrample);
+ unboxDouble(canTrample, plan.fpr());
+ break;
+#else
+ case SetJSConstantTag:
+ m_jit.move(Imm32(valueOfJSConstant(plan.nodeIndex()).tag()), plan.gpr());
+ break;
+ case SetJSConstantPayload:
+ m_jit.move(Imm32(valueOfJSConstant(plan.nodeIndex()).payload()), plan.gpr());
+ break;
+ case SetInt32Tag:
+ m_jit.move(TrustedImm32(JSValue::Int32Tag), plan.gpr());
+ break;
+ case SetCellTag:
+ m_jit.move(TrustedImm32(JSValue::CellTag), plan.gpr());
+ break;
+ case SetBooleanTag:
+ m_jit.move(TrustedImm32(JSValue::BooleanTag), plan.gpr());
+ break;
+ case SetDoubleConstant:
+ m_jit.loadDouble(addressOfDoubleConstant(plan.nodeIndex()), plan.fpr());
+ break;
+#endif
+ case Load32Tag:
+ m_jit.load32(JITCompiler::tagFor(at(plan.nodeIndex()).virtualRegister()), plan.gpr());
+ break;
+ case Load32Payload:
+ m_jit.load32(JITCompiler::payloadFor(at(plan.nodeIndex()).virtualRegister()), plan.gpr());
+ break;
+ case LoadPtr:
+ m_jit.loadPtr(JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()), plan.gpr());
+ break;
+ case LoadDouble:
+ m_jit.loadDouble(JITCompiler::addressFor(at(plan.nodeIndex()).virtualRegister()), plan.fpr());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
}
}
- void silentSpillAllRegisters(FPRReg exclude)
+
+ template<typename CollectionType>
+ void silentSpillAllRegistersImpl(bool doSpill, CollectionType& plans, GPRReg exclude, GPRReg exclude2 = InvalidGPRReg, FPRReg fprExclude = InvalidFPRReg)
{
+ ASSERT(plans.isEmpty());
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- if (iter.name() != InvalidVirtualRegister)
- silentSpillGPR(iter.name(), iter.regID());
+ GPRReg gpr = iter.regID();
+ if (iter.name() != InvalidVirtualRegister && gpr != exclude && gpr != exclude2) {
+ SilentRegisterSavePlan plan = silentSavePlanForGPR(iter.name(), gpr);
+ if (doSpill)
+ silentSpill(plan);
+ plans.append(plan);
+ }
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- FPRReg fpr = iter.regID();
- if (iter.name() != InvalidVirtualRegister && fpr != exclude)
- silentSpillFPR(iter.name(), fpr);
+ if (iter.name() != InvalidVirtualRegister && iter.regID() != fprExclude) {
+ SilentRegisterSavePlan plan = silentSavePlanForFPR(iter.name(), iter.regID());
+ if (doSpill)
+ silentSpill(plan);
+ plans.append(plan);
+ }
}
}
-
- void silentFillAllRegisters(GPRReg exclude, GPRReg exclude2 = InvalidGPRReg)
+ template<typename CollectionType>
+ void silentSpillAllRegistersImpl(bool doSpill, CollectionType& plans, NoResultTag)
{
- GPRReg canTrample = GPRInfo::regT0;
- if (exclude == GPRInfo::regT0)
- canTrample = GPRInfo::regT1;
-
- for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- if (iter.name() != InvalidVirtualRegister)
- silentFillFPR(iter.name(), canTrample, iter.regID());
- }
- for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- GPRReg gpr = iter.regID();
- if (iter.name() != InvalidVirtualRegister && gpr != exclude && gpr != exclude2)
- silentFillGPR(iter.name(), gpr);
+ silentSpillAllRegistersImpl(doSpill, plans, InvalidGPRReg, InvalidGPRReg, InvalidFPRReg);
+ }
+ template<typename CollectionType>
+ void silentSpillAllRegistersImpl(bool doSpill, CollectionType& plans, FPRReg exclude)
+ {
+ silentSpillAllRegistersImpl(doSpill, plans, InvalidGPRReg, InvalidGPRReg, exclude);
+ }
+#if USE(JSVALUE32_64)
+ template<typename CollectionType>
+ void silentSpillAllRegistersImpl(bool doSpill, CollectionType& plans, JSValueRegs exclude)
+ {
+ silentSpillAllRegistersImpl(doSpill, plans, exclude.tagGPR(), exclude.payloadGPR());
+ }
+#endif
+
+ void silentSpillAllRegisters(GPRReg exclude, GPRReg exclude2 = InvalidGPRReg, FPRReg fprExclude = InvalidFPRReg)
+ {
+ silentSpillAllRegistersImpl(true, m_plans, exclude, exclude2, fprExclude);
+ }
+ void silentSpillAllRegisters(FPRReg exclude)
+ {
+ silentSpillAllRegisters(InvalidGPRReg, InvalidGPRReg, exclude);
+ }
+
+ static GPRReg pickCanTrample(GPRReg exclude)
+ {
+ GPRReg result = GPRInfo::regT0;
+ if (result == exclude)
+ result = GPRInfo::regT1;
+ return result;
+ }
+ static GPRReg pickCanTrample(FPRReg)
+ {
+ return GPRInfo::regT0;
+ }
+ static GPRReg pickCanTrample(NoResultTag)
+ {
+ return GPRInfo::regT0;
+ }
+
+#if USE(JSVALUE32_64)
+ static GPRReg pickCanTrample(JSValueRegs exclude)
+ {
+ GPRReg result = GPRInfo::regT0;
+ if (result == exclude.tagGPR()) {
+ result = GPRInfo::regT1;
+ if (result == exclude.payloadGPR())
+ result = GPRInfo::regT2;
+ } else if (result == exclude.payloadGPR()) {
+ result = GPRInfo::regT1;
+ if (result == exclude.tagGPR())
+ result = GPRInfo::regT2;
}
+ return result;
}
- void silentFillAllRegisters(FPRReg exclude)
+#endif
+
+ template<typename RegisterType>
+ void silentFillAllRegisters(RegisterType exclude)
{
- GPRReg canTrample = GPRInfo::regT0;
+ GPRReg canTrample = pickCanTrample(exclude);
- for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- FPRReg fpr = iter.regID();
- if (iter.name() != InvalidVirtualRegister && fpr != exclude)
- silentFillFPR(iter.name(), canTrample, fpr);
- }
- for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- if (iter.name() != InvalidVirtualRegister)
- silentFillGPR(iter.name(), iter.regID());
+ while (!m_plans.isEmpty()) {
+ SilentRegisterSavePlan& plan = m_plans.last();
+ silentFill(plan, canTrample);
+ m_plans.removeLast();
}
}
@@ -887,12 +1018,11 @@ private:
void nonSpeculativeValueToInt32(Node&);
void nonSpeculativeUInt32ToNumber(Node&);
- enum SpillRegistersMode { NeedToSpill, DontSpill };
#if USE(JSVALUE64)
- JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
+ void cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, Edge valueUse, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
#elif USE(JSVALUE32_64)
- JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
+ void cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, Edge valueUse, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
#endif
@@ -1082,6 +1212,11 @@ private:
// machine registers, and delegate the calling convention specific
// decision as to how to fill the regsiters to setupArguments* methods.
#if USE(JSVALUE64)
+ JITCompiler::Call callOperation(J_DFGOperation_E operation, GPRReg result)
+ {
+ m_jit.setupArgumentsExecState();
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg result, void* pointer)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer));
@@ -1144,6 +1279,21 @@ private:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EZ operation, GPRReg result, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EZ operation, GPRReg result, int32_t arg1)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImm32(arg1));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EZZ operation, GPRReg result, int32_t arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result)
{
m_jit.setupArgumentsExecState();
@@ -1164,6 +1314,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EIcf operation, GPRReg result, InlineCallFrame* inlineCallFrame)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(inlineCallFrame));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArguments(arg1);
@@ -1214,6 +1369,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_ECIcf operation, GPRReg arg1, InlineCallFrame* arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(arg2));
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer));
@@ -1244,6 +1404,26 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_ECZ operation, GPRReg arg1, int arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2));
+ return appendCallWithExceptionCheck(operation);
+ }
+ template<typename FunctionType, typename ArgumentType1>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
+ {
+ return callOperation(operation, arg1);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1, ArgumentType2 arg2)
+ {
+ return callOperation(operation, arg1, arg2);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1, ArgumentType2 arg2, ArgumentType3 arg3)
+ {
+ return callOperation(operation, arg1, arg2, arg3);
+ }
JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
@@ -1277,6 +1457,11 @@ private:
m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
return call;
}
+ JITCompiler::Call callOperation(J_DFGOperation_E operation, GPRReg resultTag, GPRReg resultPayload)
+ {
+ m_jit.setupArgumentsExecState();
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, void* pointer)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer));
@@ -1352,6 +1537,21 @@ private:
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImm32(arg1));
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EZZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result)
{
m_jit.setupArgumentsExecState();
@@ -1372,6 +1572,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EIcf operation, GPRReg result, InlineCallFrame* inlineCallFrame)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(inlineCallFrame));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArguments(arg1Payload, arg1Tag);
@@ -1422,6 +1627,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_ECIcf operation, GPRReg arg1, InlineCallFrame* inlineCallFrame)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(inlineCallFrame));
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer));
@@ -1437,6 +1647,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
+ JITCompiler::Call callOperation(V_DFGOperation_ECZ operation, GPRReg arg1, int arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2));
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
@@ -1447,6 +1662,26 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
+ template<typename FunctionType, typename ArgumentType1>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
+ {
+ return callOperation(operation, arg1);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1, ArgumentType2 arg2)
+ {
+ return callOperation(operation, arg1, arg2);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3, typename ArgumentType4>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1, ArgumentType2 arg2, ArgumentType3 arg3, ArgumentType4 arg4)
+ {
+ return callOperation(operation, arg1, arg2, arg3, arg4);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3, typename ArgumentType4, typename ArgumentType5>
+ JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1, ArgumentType2 arg2, ArgumentType3 arg3, ArgumentType4 arg4, ArgumentType5 arg5)
+ {
+ return callOperation(operation, arg1, arg2, arg3, arg4, arg5);
+ }
JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
@@ -1466,10 +1701,56 @@ private:
}
#undef EABI_32BIT_DUMMY_ARG
-
+
+ template<typename FunctionType>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result)
+ {
+ return callOperation(operation, result.tagGPR(), result.payloadGPR());
+ }
+ template<typename FunctionType, typename ArgumentType1>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result, ArgumentType1 arg1)
+ {
+ return callOperation(operation, result.tagGPR(), result.payloadGPR(), arg1);
+ }
+ template<typename FunctionType, typename ArgumentType1, typename ArgumentType2>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result, ArgumentType1 arg1, ArgumentType2 arg2)
+ {
+ return callOperation(operation, result.tagGPR(), result.payloadGPR(), arg1, arg2);
+ }
+ template<
+ typename FunctionType, typename ArgumentType1, typename ArgumentType2,
+ typename ArgumentType3>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result, ArgumentType1 arg1, ArgumentType2 arg2,
+ ArgumentType3 arg3)
+ {
+ return callOperation(operation, result.tagGPR(), result.payloadGPR(), arg1, arg2, arg3);
+ }
+ template<
+ typename FunctionType, typename ArgumentType1, typename ArgumentType2,
+ typename ArgumentType3, typename ArgumentType4>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result, ArgumentType1 arg1, ArgumentType2 arg2,
+ ArgumentType3 arg3, ArgumentType4 arg4)
+ {
+ return callOperation(operation, result.tagGPR(), result.payloadGPR(), arg1, arg2, arg3, arg4);
+ }
+ template<
+ typename FunctionType, typename ArgumentType1, typename ArgumentType2,
+ typename ArgumentType3, typename ArgumentType4, typename ArgumentType5>
+ JITCompiler::Call callOperation(
+ FunctionType operation, JSValueRegs result, ArgumentType1 arg1, ArgumentType2 arg2,
+ ArgumentType3 arg3, ArgumentType4 arg4, ArgumentType5 arg5)
+ {
+ return callOperation(
+ operation, result.tagGPR(), result.payloadGPR(), arg1, arg2, arg3, arg4, arg5);
+ }
#endif
-#ifndef NDEBUG
+#if !defined(NDEBUG) && !CPU(ARM_THUMB2)
void prepareForExternalCall()
{
for (unsigned i = 0; i < sizeof(void*) / 4; i++)
@@ -1689,7 +1970,7 @@ private:
{
if (haveEdgeCodeToEmit(destination))
emitEdgeCode(destination);
- if (destination == m_block + 1
+ if (destination == nextBlock()
&& fallThroughMode == AtFallThroughPoint)
return;
addBranch(m_jit.jump(), destination);
@@ -1774,6 +2055,10 @@ private:
void compileGetCharCodeAt(Node&);
void compileGetByValOnString(Node&);
+
+ void compileGetByValOnArguments(Node&);
+ void compileGetArgumentsLength(Node&);
+
void compileValueToInt32(Node&);
void compileUInt32ToNumber(Node&);
void compileDoubleAsInt32(Node&);
@@ -1863,21 +2148,25 @@ private:
{
if (!m_compileOkay)
return;
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this));
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail);
}
// Add a set of speculation checks without additional recovery.
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
for (unsigned i = 0; i < jumpVector.size(); ++i)
speculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i]);
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::JumpList& jumpsToFail)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
speculationCheck(kind, jsValueSource, nodeUse.index(), jumpsToFail);
}
// Add a speculation check with additional recovery.
@@ -1885,15 +2174,18 @@ private:
{
if (!m_compileOkay)
return;
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
m_jit.codeBlock()->appendSpeculationRecovery(recovery);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_jit.codeBlock()->numberOfSpeculationRecoveries()));
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail, recovery);
}
void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail);
unsigned setLocalIndexInBlock = m_indexInBlock + 1;
@@ -1925,6 +2217,7 @@ private:
}
void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
for (unsigned i = 0; i < jumpVector.size(); ++i)
forwardSpeculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i], valueRecovery);
@@ -1933,6 +2226,7 @@ private:
// Called when we statically determine that a speculation will fail.
void terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, NodeIndex nodeIndex)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("SpeculativeJIT was terminated.\n");
#endif
@@ -1943,6 +2237,7 @@ private:
}
void terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse)
{
+ ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.index());
}
@@ -1985,8 +2280,8 @@ private:
return m_variables[operand];
}
- // The JIT, while also provides MacroAssembler functionality.
JITCompiler& m_jit;
+
// The current node being generated.
BlockIndex m_block;
NodeIndex m_compileIndex;
@@ -2018,6 +2313,11 @@ private:
AbstractState m_state;
+ bool m_isCheckingArgumentTypes;
+
+ Vector<SlowPathGenerator*, 8> m_slowPathGenerators; // doesn't use OwnPtr<> because I don't want to include DFGSlowPathGenerator.h
+ Vector<SilentRegisterSavePlan> m_plans;
+
ValueRecovery computeValueRecoveryFor(const ValueSource&);
ValueRecovery computeValueRecoveryFor(int operand)
@@ -2637,20 +2937,6 @@ private:
GPRReg m_gprOrInvalid;
};
-inline SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
- : m_compileOkay(true)
- , m_jit(jit)
- , m_compileIndex(0)
- , m_indexInBlock(0)
- , m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
- , m_blockHeads(jit.graph().m_blocks.size())
- , m_arguments(jit.codeBlock()->numParameters())
- , m_variables(jit.graph().m_localVars)
- , m_lastSetOperand(std::numeric_limits<int>::max())
- , m_state(m_jit.graph())
-{
-}
-
} } // namespace JSC::DFG
#endif