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;