fourthTier: DFG should support op_switch_imm
https://bugs.webkit.org/show_bug.cgi?id=117559
Reviewed by Oliver Hunt.
Implement integer (i.e. immediate) switches in the DFG. Reduce the minimum
threshold for using op_switch.
Also get rid of edge code support, since we haven't used it in the year since
I introduced it. It was supposed to allow us to break critical edges late in
the backend, thus enabling global register allocation from an SSA-form graph.
But we aren't doing that so I figure we should just kill the code for now. It
would have made implementing switch harder.
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::timesPtr):
* assembler/MacroAssemblerCodeRef.h:
(JSC::MacroAssemblerCodePtr::dumpWithName):
(MacroAssemblerCodePtr):
(JSC::MacroAssemblerCodePtr::dump):
(MacroAssemblerCodeRef):
(JSC::MacroAssemblerCodeRef::dump):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::shrinkToFit):
* bytecode/JumpTable.h:
(SimpleJumpTable):
(JSC::SimpleJumpTable::clear):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
(JSC::DFG::AbstractState::mergeToSuccessors):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(InlineStackEntry):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::linkBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGCommon.h:
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::determineReachability):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::JITCompiler):
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JITCompiler):
(JSC::DFG::JITCompiler::blockHeads):
* dfg/DFGNode.h:
(DFG):
(JSC::DFG::SwitchCase::SwitchCase):
(SwitchCase):
(SwitchData):
(JSC::DFG::SwitchData::SwitchData):
(Node):
(JSC::DFG::Node::isSwitch):
(JSC::DFG::Node::isTerminal):
(JSC::DFG::Node::switchData):
(JSC::DFG::Node::numSuccessors):
(JSC::DFG::Node::successor):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::createOSREntries):
(JSC::DFG::SpeculativeJIT::emitSwitchImmIntJump):
(DFG):
(JSC::DFG::SpeculativeJIT::emitSwitchImm):
(JSC::DFG::SpeculativeJIT::emitSwitch):
(JSC::DFG::SpeculativeJIT::linkBranches):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::branchDouble):
(JSC::DFG::SpeculativeJIT::branchDoubleNonZero):
(JSC::DFG::SpeculativeJIT::branch32):
(JSC::DFG::SpeculativeJIT::branchTest32):
(JSC::DFG::SpeculativeJIT::branch64):
(JSC::DFG::SpeculativeJIT::branchPtr):
(JSC::DFG::SpeculativeJIT::branchTestPtr):
(JSC::DFG::SpeculativeJIT::branchTest8):
(JSC::DFG::SpeculativeJIT::jump):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* parser/Nodes.h:
(CaseBlockNode):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153228 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 587389f..1b67873 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,106 @@
+2013-06-13 Filip Pizlo <fpizlo@apple.com>
+
+ fourthTier: DFG should support op_switch_imm
+ https://bugs.webkit.org/show_bug.cgi?id=117559
+
+ Reviewed by Oliver Hunt.
+
+ Implement integer (i.e. immediate) switches in the DFG. Reduce the minimum
+ threshold for using op_switch.
+
+ Also get rid of edge code support, since we haven't used it in the year since
+ I introduced it. It was supposed to allow us to break critical edges late in
+ the backend, thus enabling global register allocation from an SSA-form graph.
+ But we aren't doing that so I figure we should just kill the code for now. It
+ would have made implementing switch harder.
+
+ * assembler/AbstractMacroAssembler.h:
+ (JSC::AbstractMacroAssembler::timesPtr):
+ * assembler/MacroAssemblerCodeRef.h:
+ (JSC::MacroAssemblerCodePtr::dumpWithName):
+ (MacroAssemblerCodePtr):
+ (JSC::MacroAssemblerCodePtr::dump):
+ (MacroAssemblerCodeRef):
+ (JSC::MacroAssemblerCodeRef::dump):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::shrinkToFit):
+ * bytecode/JumpTable.h:
+ (SimpleJumpTable):
+ (JSC::SimpleJumpTable::clear):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::executeEffects):
+ (JSC::DFG::AbstractState::mergeToSuccessors):
+ * dfg/DFGBackwardsPropagationPhase.cpp:
+ (JSC::DFG::BackwardsPropagationPhase::propagate):
+ * dfg/DFGByteCodeParser.cpp:
+ (InlineStackEntry):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (JSC::DFG::ByteCodeParser::linkBlock):
+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGCommon.h:
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ (JSC::DFG::Graph::determineReachability):
+ * dfg/DFGGraph.h:
+ (Graph):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::JITCompiler):
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGJITCompiler.h:
+ (JITCompiler):
+ (JSC::DFG::JITCompiler::blockHeads):
+ * dfg/DFGNode.h:
+ (DFG):
+ (JSC::DFG::SwitchCase::SwitchCase):
+ (SwitchCase):
+ (SwitchData):
+ (JSC::DFG::SwitchData::SwitchData):
+ (Node):
+ (JSC::DFG::Node::isSwitch):
+ (JSC::DFG::Node::isTerminal):
+ (JSC::DFG::Node::switchData):
+ (JSC::DFG::Node::numSuccessors):
+ (JSC::DFG::Node::successor):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::SpeculativeJIT):
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::SpeculativeJIT::createOSREntries):
+ (JSC::DFG::SpeculativeJIT::emitSwitchImmIntJump):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::emitSwitchImm):
+ (JSC::DFG::SpeculativeJIT::emitSwitch):
+ (JSC::DFG::SpeculativeJIT::linkBranches):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ (SpeculativeJIT):
+ (JSC::DFG::SpeculativeJIT::branchDouble):
+ (JSC::DFG::SpeculativeJIT::branchDoubleNonZero):
+ (JSC::DFG::SpeculativeJIT::branch32):
+ (JSC::DFG::SpeculativeJIT::branchTest32):
+ (JSC::DFG::SpeculativeJIT::branch64):
+ (JSC::DFG::SpeculativeJIT::branchPtr):
+ (JSC::DFG::SpeculativeJIT::branchTestPtr):
+ (JSC::DFG::SpeculativeJIT::branchTest8):
+ (JSC::DFG::SpeculativeJIT::jump):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ * parser/Nodes.h:
+ (CaseBlockNode):
+
2013-06-15 Filip Pizlo <fpizlo@apple.com>
Concurrent JIT shouldn't try to recompute the CodeBlockHash as part of debug dumps, since doing so may fail if dealing with a CachedScript that doesn't have its script string handy
diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
index 092bcc1..630a9b0 100644
--- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
@@ -95,6 +95,13 @@
TimesFour,
TimesEight,
};
+
+ static Scale timesPtr()
+ {
+ if (sizeof(void*) == 4)
+ return TimesFour;
+ return TimesEight;
+ }
// Address:
//
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h
index ba5af35..87d7cb0 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h
@@ -31,6 +31,7 @@
#include "LLIntData.h"
#include <wtf/DataLog.h>
#include <wtf/PassRefPtr.h>
+#include <wtf/PrintStream.h>
#include <wtf/RefPtr.h>
// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid
@@ -320,6 +321,20 @@
return m_value == other.m_value;
}
+ void dumpWithName(const char* name, PrintStream& out) const
+ {
+ if (executableAddress() == dataLocation()) {
+ out.print(name, "(", RawPointer(executableAddress()), ")");
+ return;
+ }
+ out.print(name, "(executable = ", RawPointer(executableAddress()), ", dataLocation = ", RawPointer(dataLocation()), ")");
+ }
+
+ void dump(PrintStream& out) const
+ {
+ dumpWithName("CodePtr", out);
+ }
+
private:
void* m_value;
};
@@ -392,6 +407,11 @@
}
bool operator!() const { return !m_codePtr; }
+
+ void dump(PrintStream& out) const
+ {
+ m_codePtr.dumpWithName("CodeRef", out);
+ }
private:
MacroAssemblerCodePtr m_codePtr;
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index c811bc8..aff2766 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -2458,13 +2458,16 @@
m_functionDecls.shrinkToFit();
m_functionExprs.shrinkToFit();
m_constantRegisters.shrinkToFit();
+
+ if (m_rareData) {
+ m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
+ m_rareData->m_characterSwitchJumpTables.shrinkToFit();
+ m_rareData->m_stringSwitchJumpTables.shrinkToFit();
+ }
} // else don't shrink these, because we would have already pointed pointers into these tables.
if (m_rareData) {
m_rareData->m_exceptionHandlers.shrinkToFit();
- m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
- m_rareData->m_characterSwitchJumpTables.shrinkToFit();
- m_rareData->m_stringSwitchJumpTables.shrinkToFit();
#if ENABLE(JIT)
m_rareData->m_callReturnIndexVector.shrinkToFit();
#endif
diff --git a/Source/JavaScriptCore/bytecode/JumpTable.h b/Source/JavaScriptCore/bytecode/JumpTable.h
index f54a371..6b3a713 100644
--- a/Source/JavaScriptCore/bytecode/JumpTable.h
+++ b/Source/JavaScriptCore/bytecode/JumpTable.h
@@ -96,6 +96,12 @@
return ctiDefault;
}
#endif
+
+ void clear()
+ {
+ branchOffsets.clear();
+ ctiOffsets.clear();
+ }
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 2674c6b..637ac81 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1038,6 +1038,12 @@
m_branchDirection = TakeBoth;
break;
}
+
+ case Switch: {
+ // Nothing to do for now.
+ // FIXME: Do sparse conditional things.
+ break;
+ }
case Return:
m_isValid = false;
@@ -1809,6 +1815,17 @@
return changed;
}
+ case Switch: {
+ // FIXME: It would be cool to be sparse conditional for Switch's. Currently
+ // we're not. However I somehow doubt that this will ever be a big deal.
+ ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
+ SwitchData* data = terminal->switchData();
+ bool changed = merge(basicBlock, graph.m_blocks[data->fallThrough].get());
+ for (unsigned i = data->cases.size(); i--;)
+ changed |= merge(basicBlock, graph.m_blocks[data->cases[i].target].get());
+ return changed;
+ }
+
case Return:
case Throw:
case ThrowReferenceError:
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
index 2f06646..7b5c475 100644
--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
@@ -347,6 +347,20 @@
break;
}
+ case Switch: {
+ SwitchData* data = node->switchData();
+ switch (data->kind) {
+ case SwitchImm: {
+ // We don't need NodeNeedsNegZero because if the cases are all integers
+ // then -0 and 0 are treated the same. We don't need NodeUsedAsOther
+ // because if all of the cases are integers then NaN and undefined are
+ // treated the same.
+ node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ break;
+ } }
+ break;
+ }
+
default:
mergeDefaultFlags(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 8315573..fae82f4 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1009,6 +1009,7 @@
Vector<unsigned> m_identifierRemap;
Vector<unsigned> m_constantRemap;
Vector<unsigned> m_constantBufferRemap;
+ Vector<unsigned> m_switchImmRemap;
// Blocks introduced by this code block, which need successor linking.
// May include up to one basic block that includes the continuation after
@@ -2756,6 +2757,25 @@
addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jngreatereq)), OpInfo(m_currentIndex + relativeOffset), condition);
LAST_OPCODE(op_jngreatereq);
}
+
+ case op_switch_imm: {
+ SwitchData data;
+ data.kind = SwitchImm;
+ data.switchTableIndex = m_inlineStackTop->m_switchImmRemap[currentInstruction[1].u.operand];
+ data.fallThrough = m_currentIndex + currentInstruction[2].u.operand;
+ SimpleJumpTable& table = m_codeBlock->immediateSwitchJumpTable(data.switchTableIndex);
+ for (unsigned i = 0; i < table.branchOffsets.size(); ++i) {
+ if (!table.branchOffsets[i])
+ continue;
+ unsigned target = m_currentIndex + table.branchOffsets[i];
+ if (target == data.fallThrough)
+ continue;
+ data.cases.append(SwitchCase(jsNumber(table.min + i), target));
+ }
+ m_graph.m_switchData.append(data);
+ addToGraph(Switch, OpInfo(&m_graph.m_switchData.last()), get(currentInstruction[3].u.operand));
+ LAST_OPCODE(op_switch_imm);
+ }
case op_ret:
flushArgumentsAndCapturedVariables();
@@ -3122,6 +3142,12 @@
#endif
break;
+ case Switch:
+ for (unsigned i = node->switchData()->cases.size(); i--;)
+ node->switchData()->cases[i].target = m_graph.blockIndexForBytecodeOffset(possibleTargets, node->switchData()->cases[i].target);
+ node->switchData()->fallThrough = m_graph.blockIndexForBytecodeOffset(possibleTargets, node->switchData()->fallThrough);
+ break;
+
default:
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("Marking basic block %p as linked.\n", block);
@@ -3247,6 +3273,7 @@
m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+ m_switchImmRemap.resize(codeBlock->numberOfImmediateSwitchJumpTables());
for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) {
StringImpl* rep = codeBlock->identifier(i).impl();
@@ -3287,6 +3314,10 @@
m_constantBufferRemap[i] = newIndex;
byteCodeParser->m_constantBufferCache.add(ConstantBufferKey(codeBlock, i), newIndex);
}
+ for (unsigned i = 0; i < codeBlock->numberOfImmediateSwitchJumpTables(); ++i) {
+ m_switchImmRemap[i] = byteCodeParser->m_codeBlock->numberOfImmediateSwitchJumpTables();
+ byteCodeParser->m_codeBlock->addImmediateSwitchJumpTable() = codeBlock->immediateSwitchJumpTable(i);
+ }
m_callsiteBlockHeadNeedsLinking = true;
} else {
// Machine code block case.
@@ -3301,12 +3332,15 @@
m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+ m_switchImmRemap.resize(codeBlock->numberOfImmediateSwitchJumpTables());
for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i)
m_identifierRemap[i] = i;
for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i)
m_constantRemap[i] = i + FirstConstantRegisterIndex;
for (size_t i = 0; i < codeBlock->numberOfConstantBuffers(); ++i)
m_constantBufferRemap[i] = i;
+ for (size_t i = 0; i < codeBlock->numberOfImmediateSwitchJumpTables(); ++i)
+ m_switchImmRemap[i] = i;
m_callsiteBlockHeadNeedsLinking = false;
}
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index a86b560..7deec2f 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -166,6 +166,7 @@
case op_jneq_ptr:
case op_typeof:
case op_to_number:
+ case op_switch_imm:
case op_in:
case op_get_from_scope:
case op_put_to_scope:
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 18e1d41..cf2c907 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -68,8 +68,6 @@
#define DFG_ENABLE_OSR_ENTRY ENABLE(DFG_JIT)
// Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path.
#define DFG_ENABLE_SUCCESS_STATS 0
-// Enable verification that the DFG is able to insert code for control flow edges.
-#define DFG_ENABLE_EDGE_CODE_VERIFICATION 0
namespace JSC { namespace DFG {
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 3bc7941..6af634f 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -578,6 +578,17 @@
break;
}
+ case Switch: {
+ SwitchData* data = node->switchData();
+ switch (data->kind) {
+ case SwitchImm:
+ if (node->child1()->shouldSpeculateInteger())
+ setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+ break;
+ }
+ break;
+ }
+
case ToPrimitive: {
fixupToPrimitive(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 826defb..b23d8d8 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -258,6 +258,12 @@
out.print(comma, "T:#", node->takenBlockIndex());
if (node->isBranch())
out.print(comma, "F:#", node->notTakenBlockIndex());
+ if (node->isSwitch()) {
+ SwitchData* data = node->switchData();
+ for (unsigned i = 0; i < data->cases.size(); ++i)
+ out.print(comma, data->cases[i].value, ":#", data->cases[i].target);
+ out.print(comma, "default:#", data->fallThrough);
+ }
out.print(comma, "bc#", node->codeOrigin.bytecodeIndex);
out.print(")");
@@ -404,17 +410,8 @@
worklist.removeLast();
BasicBlock* block = m_blocks[index].get();
- ASSERT(block->isLinked);
-
- Node* node = block->last();
- ASSERT(node->isTerminal());
-
- if (node->isJump())
- handleSuccessor(worklist, index, node->takenBlockIndex());
- else if (node->isBranch()) {
- handleSuccessor(worklist, index, node->takenBlockIndex());
- handleSuccessor(worklist, index, node->notTakenBlockIndex());
- }
+ for (unsigned i = numSuccessors(block); i--;)
+ handleSuccessor(worklist, index, successor(block, i));
}
}
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index af3487c..3f1fc1f 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -65,7 +65,6 @@
SpeculateInteger
};
-
//
// === Graph ===
//
@@ -704,6 +703,7 @@
SegmentedVector<StructureSet, 16> m_structureSet;
SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData;
+ SegmentedVector<SwitchData, 4> m_switchData;
bool m_hasArguments;
HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped;
BitVector m_preservedVars;
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 1d70f15..1e4a7e7 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -48,6 +48,7 @@
: CCallHelpers(&dfg.m_vm, dfg.m_codeBlock)
, m_graph(dfg)
, m_jitCode(adoptRef(new JITCode()))
+ , m_blockHeads(dfg.m_blocks.size())
, m_currentCodeOriginIndex(0)
{
if (shouldShowDisassembly() || m_graph.m_vm.m_perBytecodeProfiler)
@@ -155,6 +156,34 @@
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("JIT code for %p start at [%p, %p). Size = %zu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize());
#endif
+
+ BitVector usedJumpTables;
+ for (unsigned i = m_graph.m_switchData.size(); i--;) {
+ SwitchData& data = m_graph.m_switchData[i];
+ if (!data.didUseJumpTable)
+ continue;
+
+ // Cast to int to avoid tautological comparison warnings.
+ RELEASE_ASSERT(static_cast<int>(data.kind) == static_cast<int>(SwitchImm));
+
+ usedJumpTables.set(data.switchTableIndex);
+ SimpleJumpTable& table =
+ m_codeBlock->immediateSwitchJumpTable(data.switchTableIndex);
+ table.ctiDefault = linkBuffer.locationOf(m_blockHeads[data.fallThrough]);
+ for (unsigned j = table.ctiOffsets.size(); j--;)
+ table.ctiOffsets[j] = table.ctiDefault;
+ for (unsigned j = data.cases.size(); j--;) {
+ SwitchCase& myCase = data.cases[j];
+ table.ctiOffsets[myCase.value.asInt32() - table.min] =
+ linkBuffer.locationOf(m_blockHeads[myCase.target]);
+ }
+ }
+ for (unsigned i = m_codeBlock->numberOfImmediateSwitchJumpTables(); i--;) {
+ if (usedJumpTables.get(i))
+ continue;
+
+ m_codeBlock->immediateSwitchJumpTable(i).clear();
+ }
// Link all calls out from the JIT code to their respective functions.
for (unsigned i = 0; i < m_calls.size(); ++i)
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index 585ca97..a468fdf 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -462,6 +462,8 @@
}
PassRefPtr<JITCode> jitCode() { return m_jitCode; }
+
+ Vector<Label>& blockHeads() { return m_blockHeads; }
private:
friend class OSRExitJumpPlaceholder;
@@ -488,6 +490,8 @@
Vector<CallLinkRecord> m_calls;
Vector<CallExceptionRecord> m_exceptionChecks;
+ Vector<Label> m_blockHeads;
+
struct JSCallRecord {
JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
: m_fastCall(fastCall)
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 60845df..c0cdf2f 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -66,6 +66,50 @@
IndexingType indexingType;
};
+// The SwitchData and associated data structures duplicate the information in
+// JumpTable. The DFG may ultimately end up using the JumpTable, though it may
+// instead decide to do something different - this is entirely up to the DFG.
+// These data structures give the DFG a higher-level semantic description of
+// what is going on, which will allow it to make the right decision.
+struct SwitchCase {
+ SwitchCase()
+ : target(NoBlock)
+ {
+ }
+
+ SwitchCase(JSValue value, BlockIndex target)
+ : value(value)
+ , target(target)
+ {
+ }
+
+ JSValue value;
+ BlockIndex target;
+};
+
+enum SwitchKind {
+ SwitchImm
+};
+
+struct SwitchData {
+ // Initializes most fields to obviously invalid values. Anyone
+ // constructing this should make sure to initialize everything they
+ // care about manually.
+ SwitchData()
+ : fallThrough(NoBlock)
+ , kind(static_cast<SwitchKind>(-1))
+ , switchTableIndex(UINT_MAX)
+ , didUseJumpTable(false)
+ {
+ }
+
+ Vector<SwitchCase> cases;
+ BlockIndex fallThrough;
+ SwitchKind kind;
+ unsigned switchTableIndex;
+ bool didUseJumpTable;
+};
+
// This type used in passing an immediate argument to Node constructor;
// distinguishes an immediate value (typically an index into a CodeBlock data structure -
// a constant index, argument, or identifier) from a Node*.
@@ -659,12 +703,18 @@
{
return op() == Branch;
}
+
+ bool isSwitch()
+ {
+ return op() == Switch;
+ }
bool isTerminal()
{
switch (op()) {
case Jump:
case Branch:
+ case Switch:
case Return:
case Throw:
case ThrowReferenceError:
@@ -710,6 +760,12 @@
return m_opInfo2;
}
+ SwitchData* switchData()
+ {
+ ASSERT(isSwitch());
+ return bitwise_cast<SwitchData*>(m_opInfo);
+ }
+
unsigned numSuccessors()
{
switch (op()) {
@@ -717,6 +773,8 @@
return 1;
case Branch:
return 2;
+ case Switch:
+ return switchData()->cases.size() + 1;
default:
return 0;
}
@@ -724,6 +782,12 @@
BlockIndex successor(unsigned index)
{
+ if (isSwitch()) {
+ if (index < switchData()->cases.size())
+ return switchData()->cases[index].target;
+ RELEASE_ASSERT(index == switchData()->cases.size());
+ return switchData()->fallThrough;
+ }
switch (index) {
case 0:
return takenBlockIndex();
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index efca840..aa318e0 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -249,6 +249,7 @@
/* Block terminals. */\
macro(Jump, NodeMustGenerate) \
macro(Branch, NodeMustGenerate) \
+ macro(Switch, NodeMustGenerate) \
macro(Return, NodeMustGenerate) \
macro(Throw, NodeMustGenerate) \
macro(ThrowReferenceError, NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 9144927..b6f973b 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1612,6 +1612,20 @@
return JSRopeString::create(vm, a, b, c);
}
+char* DFG_OPERATION operationFindSwitchImmTargetForDouble(
+ ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
+{
+ CodeBlock* codeBlock = exec->codeBlock();
+ SimpleJumpTable& table = codeBlock->immediateSwitchJumpTable(tableIndex);
+ JSValue value = JSValue::decode(encodedValue);
+ ASSERT(value.isDouble());
+ double asDouble = value.asDouble();
+ int32_t asInt32 = static_cast<int32_t>(asDouble);
+ if (asDouble == asInt32)
+ return static_cast<char*>(table.ctiForValue(asInt32).executableAddress());
+ return static_cast<char*>(table.ctiDefault.executableAddress());
+}
+
double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
{
return fmod(a, b);
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 17e86d1..3c14052 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -113,6 +113,7 @@
typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*);
typedef char* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
typedef char* DFG_OPERATION (*P_DFGOperation_EC)(ExecState*, JSCell*);
+typedef char* DFG_OPERATION (*P_DFGOperation_EJS)(ExecState*, EncodedJSValue, size_t);
typedef char* DFG_OPERATION (*P_DFGOperation_EO)(ExecState*, JSObject*);
typedef char* DFG_OPERATION (*P_DFGOperation_EOS)(ExecState*, JSObject*, size_t);
typedef char* DFG_OPERATION (*P_DFGOperation_EOZ)(ExecState*, JSObject*, int32_t);
@@ -223,6 +224,7 @@
JSCell* DFG_OPERATION operationToString(ExecState*, EncodedJSValue);
JSCell* DFG_OPERATION operationMakeRope2(ExecState*, JSString*, JSString*);
JSCell* DFG_OPERATION operationMakeRope3(ExecState*, JSString*, JSString*, JSString*);
+char* DFG_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index f230066..dda403b 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -518,6 +518,7 @@
case SetMyScope:
case DFG::Jump:
case Branch:
+ case Switch:
case Breakpoint:
case CheckHasInstance:
case ThrowReferenceError:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6834589..ad89913 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -43,7 +43,6 @@
, m_currentNode(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())
@@ -1672,7 +1671,7 @@
return;
}
- m_blockHeads[m_block] = m_jit.label();
+ m_jit.blockHeads()[m_block] = m_jit.label();
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
m_jit.breakpoint();
#endif
@@ -1719,13 +1718,6 @@
m_lastSetOperand = std::numeric_limits<int>::max();
m_codeOriginForOSR = CodeOrigin();
- if (DFG_ENABLE_EDGE_CODE_VERIFICATION) {
- JITCompiler::Jump verificationSucceeded =
- m_jit.branch32(JITCompiler::Equal, GPRInfo::regT0, TrustedImm32(m_block));
- m_jit.breakpoint();
- verificationSucceeded.link(&m_jit);
- }
-
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("\n");
#endif
@@ -1910,9 +1902,6 @@
{
checkArgumentTypes();
- if (DFG_ENABLE_EDGE_CODE_VERIFICATION)
- m_jit.move(TrustedImm32(0), GPRInfo::regT0);
-
ASSERT(!m_currentNode);
for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block) {
m_jit.setForBlock(m_block);
@@ -1933,18 +1922,9 @@
if (!block->isOSRTarget)
continue;
- // Currently we only need to create OSR entry trampolines when using edge code
- // verification. But in the future, we'll need this for other things as well (like
- // when we have global reg alloc).
- // If we don't need OSR entry trampolin
- if (!DFG_ENABLE_EDGE_CODE_VERIFICATION) {
- m_osrEntryHeads.append(m_blockHeads[blockIndex]);
- continue;
- }
-
- m_osrEntryHeads.append(m_jit.label());
- m_jit.move(TrustedImm32(blockIndex), GPRInfo::regT0);
- m_jit.jump().linkTo(m_blockHeads[blockIndex], &m_jit);
+ // Currently we don't have OSR entry trampolines. We could add them
+ // here if need be.
+ m_osrEntryHeads.append(m_jit.blockHeads()[blockIndex]);
}
}
@@ -4654,6 +4634,95 @@
}
}
+void SpeculativeJIT::emitSwitchImmIntJump(Node*, SwitchData* data, GPRReg value, GPRReg scratch)
+{
+ SimpleJumpTable& table = m_jit.codeBlock()->immediateSwitchJumpTable(data->switchTableIndex);
+ m_jit.sub32(Imm32(table.min), value);
+ addBranch(
+ m_jit.branch32(JITCompiler::AboveOrEqual, value, Imm32(table.ctiOffsets.size())),
+ data->fallThrough);
+ m_jit.move(TrustedImmPtr(table.ctiOffsets.begin()), scratch);
+ m_jit.loadPtr(JITCompiler::BaseIndex(scratch, value, JITCompiler::timesPtr()), scratch);
+ m_jit.jump(scratch);
+ data->didUseJumpTable = true;
+}
+
+void SpeculativeJIT::emitSwitchImm(Node* node, SwitchData* data)
+{
+ switch (node->child1().useKind()) {
+ case Int32Use: {
+ SpeculateIntegerOperand value(this, node->child1());
+ GPRTemporary temp(this);
+ emitSwitchImmIntJump(node, data, value.gpr(), temp.gpr());
+ noResult(node);
+ break;
+ }
+
+ case UntypedUse: {
+ JSValueOperand value(this, node->child1());
+ GPRTemporary temp(this);
+ JSValueRegs valueRegs = value.jsValueRegs();
+ GPRReg scratch = temp.gpr();
+
+ value.use();
+
+#if USE(JSVALUE64)
+ JITCompiler::Jump notInt = m_jit.branch64(
+ JITCompiler::Below, valueRegs.gpr(), GPRInfo::tagTypeNumberRegister);
+ emitSwitchImmIntJump(node, data, valueRegs.gpr(), scratch);
+ notInt.link(&m_jit);
+ addBranch(
+ m_jit.branchTest64(
+ JITCompiler::Zero, valueRegs.gpr(), GPRInfo::tagTypeNumberRegister),
+ data->fallThrough);
+ silentSpillAllRegisters(scratch);
+ callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs.gpr(), data->switchTableIndex);
+ silentFillAllRegisters(scratch);
+ m_jit.jump(scratch);
+#else
+ JITCompiler::Jump notInt = m_jit.branch32(
+ JITCompiler::NotEqual, valueRegs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
+ emitSwitchImmIntJump(node, data, valueRegs.payloadGPR(), scratch);
+ notInt.link(&m_jit);
+ addBranch(
+ m_jit.branch32(
+ JITCompiler::AboveOrEqual, valueRegs.tagGPR(),
+ TrustedImm32(JSValue::LowestTag)),
+ data->fallThrough);
+ silentSpillAllRegisters(scratch);
+ callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs, data->switchTableIndex);
+ silentFillAllRegisters(scratch);
+ m_jit.jump(scratch);
+#endif
+ noResult(node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void SpeculativeJIT::emitSwitch(Node* node)
+{
+ SwitchData* data = node->switchData();
+ switch (data->kind) {
+ case SwitchImm: {
+ emitSwitchImm(node, data);
+ return;
+ } }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void SpeculativeJIT::linkBranches()
+{
+ for (size_t i = 0; i < m_branches.size(); ++i) {
+ BranchRecord& branch = m_branches[i];
+ branch.jump.linkTo(m_jit.blockHeads()[branch.destination], &m_jit);
+ }
+}
+
} } // namespace JSC::DFG
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 18a99e0..cb6fc9e 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1220,6 +1220,11 @@
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(P_DFGOperation_EJS operation, GPRReg result, GPRReg value, size_t index)
+ {
+ m_jit.setupArgumentsWithExecState(value, TrustedImmPtr(index));
+ return appendCallSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
{
@@ -1456,6 +1461,11 @@
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(P_DFGOperation_EJS operation, GPRReg result, JSValueRegs value, size_t index)
+ {
+ m_jit.setupArgumentsWithExecState(value.payloadGPR(), value.tagGPR(), TrustedImmPtr(index));
+ return appendCallSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
@@ -1725,146 +1735,68 @@
void branchDouble(JITCompiler::DoubleCondition cond, FPRReg left, FPRReg right, BlockIndex destination)
{
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchDouble(cond, left, right), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchDouble(JITCompiler::invert(cond), left, right);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchDouble(cond, left, right), destination);
}
void branchDoubleNonZero(FPRReg value, FPRReg scratch, BlockIndex destination)
{
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchDoubleNonZero(value, scratch), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchDoubleZeroOrNaN(value, scratch);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchDoubleNonZero(value, scratch), destination);
}
template<typename T, typename U>
void branch32(JITCompiler::RelationalCondition cond, T left, U right, BlockIndex destination)
{
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branch32(cond, left, right), destination);
-
- JITCompiler::Jump notTaken = m_jit.branch32(JITCompiler::invert(cond), left, right);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branch32(cond, left, right), destination);
}
template<typename T, typename U>
void branchTest32(JITCompiler::ResultCondition cond, T value, U mask, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTest32(cond, value, mask), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTest32(JITCompiler::invert(cond), value, mask);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTest32(cond, value, mask), destination);
}
template<typename T>
void branchTest32(JITCompiler::ResultCondition cond, T value, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTest32(cond, value), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTest32(JITCompiler::invert(cond), value);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTest32(cond, value), destination);
}
#if USE(JSVALUE64)
template<typename T, typename U>
void branch64(JITCompiler::RelationalCondition cond, T left, U right, BlockIndex destination)
{
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branch64(cond, left, right), destination);
-
- JITCompiler::Jump notTaken = m_jit.branch64(JITCompiler::invert(cond), left, right);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branch64(cond, left, right), destination);
}
#endif
template<typename T, typename U>
void branchPtr(JITCompiler::RelationalCondition cond, T left, U right, BlockIndex destination)
{
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchPtr(cond, left, right), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchPtr(JITCompiler::invert(cond), left, right);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchPtr(cond, left, right), destination);
}
template<typename T, typename U>
void branchTestPtr(JITCompiler::ResultCondition cond, T value, U mask, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTestPtr(cond, value, mask), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTestPtr(JITCompiler::invert(cond), value, mask);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTestPtr(cond, value, mask), destination);
}
template<typename T>
void branchTestPtr(JITCompiler::ResultCondition cond, T value, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTestPtr(cond, value), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTestPtr(JITCompiler::invert(cond), value);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTestPtr(cond, value), destination);
}
template<typename T, typename U>
void branchTest8(JITCompiler::ResultCondition cond, T value, U mask, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTest8(cond, value, mask), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTest8(JITCompiler::invert(cond), value, mask);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTest8(cond, value, mask), destination);
}
template<typename T>
void branchTest8(JITCompiler::ResultCondition cond, T value, BlockIndex destination)
{
- ASSERT(JITCompiler::isInvertible(cond));
-
- if (!haveEdgeCodeToEmit(destination))
- return addBranch(m_jit.branchTest8(cond, value), destination);
-
- JITCompiler::Jump notTaken = m_jit.branchTest8(JITCompiler::invert(cond), value);
- emitEdgeCode(destination);
- addBranch(m_jit.jump(), destination);
- notTaken.link(&m_jit);
+ return addBranch(m_jit.branchTest8(cond, value), destination);
}
enum FallThroughMode {
@@ -1873,37 +1805,18 @@
};
void jump(BlockIndex destination, FallThroughMode fallThroughMode = AtFallThroughPoint)
{
- if (haveEdgeCodeToEmit(destination))
- emitEdgeCode(destination);
if (destination == nextBlock()
&& fallThroughMode == AtFallThroughPoint)
return;
addBranch(m_jit.jump(), destination);
}
- inline bool haveEdgeCodeToEmit(BlockIndex)
- {
- return DFG_ENABLE_EDGE_CODE_VERIFICATION;
- }
- void emitEdgeCode(BlockIndex destination)
- {
- if (!DFG_ENABLE_EDGE_CODE_VERIFICATION)
- return;
- m_jit.move(TrustedImm32(destination), GPRInfo::regT0);
- }
-
void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
{
m_branches.append(BranchRecord(jump, destination));
}
- void linkBranches()
- {
- for (size_t i = 0; i < m_branches.size(); ++i) {
- BranchRecord& branch = m_branches[i];
- branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
- }
- }
+ void linkBranches();
BasicBlock* block()
{
@@ -1949,6 +1862,9 @@
void compileStringEquality(Node*);
void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
void emitBranch(Node*);
+ void emitSwitchImmIntJump(Node*, SwitchData*, GPRReg value, GPRReg scratch);
+ void emitSwitchImm(Node*, SwitchData*);
+ void emitSwitch(Node*);
void compileToStringOnCell(Node*);
void compileNewStringObject(Node*);
@@ -2209,7 +2125,6 @@
RegisterBank<GPRInfo> m_gprs;
RegisterBank<FPRInfo> m_fprs;
- Vector<MacroAssembler::Label> m_blockHeads;
Vector<MacroAssembler::Label> m_osrEntryHeads;
struct BranchRecord {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 4b909a2..aa778bc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3234,6 +3234,10 @@
case Branch:
emitBranch(node);
break;
+
+ case Switch:
+ emitSwitch(node);
+ break;
case Return: {
ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index abd2845..7c9d4dc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3179,6 +3179,10 @@
emitBranch(node);
break;
+ case Switch:
+ emitSwitch(node);
+ break;
+
case Return: {
ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT1);
ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index cb003ba..df12802 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -2057,7 +2057,7 @@
if (scrutinee.isInt32())
return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress();
if (scrutinee.isDouble() && scrutinee.asDouble() == static_cast<int32_t>(scrutinee.asDouble()))
- return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(static_cast<int32_t>(scrutinee.asDouble())).executableAddress();
+ return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(static_cast<int32_t>(scrutinee.asDouble())).executableAddress();
return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
}
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 2eeaae9..73df04b 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1575,7 +1575,7 @@
private:
SwitchInfo::SwitchType tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num);
- static const size_t s_tableSwitchMinimum = 10;
+ static const size_t s_tableSwitchMinimum = 3;
ClauseListNode* m_list1;
CaseClauseNode* m_defaultClause;
ClauseListNode* m_list2;