fourthTier: DFG should have switch_char
https://bugs.webkit.org/show_bug.cgi?id=117710

Source/JavaScriptCore:

Reviewed by Michael Saboff.

Add op_switch_char. Most of this is fairly simple, except for the whole
LazyJSValue thing.

It's long been the case that anytime you wanted the DFG to speak of a string
that didn't appear in the constant pool, you would have a hard time since
the DFG isn't allowed to allocate in the GC heap. For example, if you know
that you want to speak of a single character string, you might find that
the one you wanted to speak of had been GC'd. Another example is if you
wanted to add constant folding for string concatenation - something we don't
have yet but will want eventually.

I solve this by finally adding the notion of LazyJSValue. In the future I
anticipate using this for a variety of string-related things. The idea here
is that the DFG can either say that it already knows what the value is, or
it can describe the value. For example, in this patch I needed to be able to
describe single-character strings.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/JumpTable.h:
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(InlineStackEntry):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGPRInfo.h:
(JSC::DFG::JSValueRegs::payloadGPR):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::jumpTable):
(DFG):
(JSC::DFG::JITCompiler::numberOfJumpTables):
(JSC::DFG::JITCompiler::linkSwitches):
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JITCompiler):
* dfg/DFGLazyJSValue.cpp: Added.
(DFG):
(JSC::DFG::LazyJSValue::getValue):
(JSC::DFG::equalToSingleCharacter):
(JSC::DFG::LazyJSValue::strictEqual):
(JSC::DFG::LazyJSValue::dump):
* dfg/DFGLazyJSValue.h: Added.
(DFG):
(LazyJSValue):
(JSC::DFG::LazyJSValue::LazyJSValue):
(JSC::DFG::LazyJSValue::singleCharacterString):
(JSC::DFG::LazyJSValue::tryGetValue):
(JSC::DFG::LazyJSValue::value):
(JSC::DFG::LazyJSValue::character):
(JSC::DFG::LazyJSValue::switchLookupValue):
* dfg/DFGNode.h:
(JSC::DFG::SwitchCase::SwitchCase):
(SwitchCase):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitSwitchIntJump):
(JSC::DFG::SpeculativeJIT::emitSwitchImmIntJump):
(DFG):
(JSC::DFG::SpeculativeJIT::emitSwitchImm):
(JSC::DFG::SpeculativeJIT::emitSwitchCharStringJump):
(JSC::DFG::SpeculativeJIT::emitSwitchChar):
(JSC::DFG::SpeculativeJIT::emitSwitch):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):

Source/WTF:

Reviewed by Michael Saboff.

I wanted to be able to say stringImpl->at(index), and now I can!

Also made it possible to convert a UChar to a utf8 CString without
allocating a StringImpl.

* wtf/text/StringImpl.cpp:
(WTF::StringImpl::utf8Impl):
(WTF):
(WTF::StringImpl::utf8ForCharacters):
(WTF::StringImpl::utf8ForRange):
* wtf/text/StringImpl.h:
(StringImpl):
(WTF::StringImpl::at):
(WTF::StringImpl::operator[]):

LayoutTests:

Rubber stamped by Mark Hahnenberg.

* fast/js/regress/script-tests/switch-char-constant.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/switch-char.js: Added.
(foo):
(bar):
* fast/js/regress/switch-char-constant-expected.txt: Added.
* fast/js/regress/switch-char-constant.html: Added.
* fast/js/regress/switch-char-expected.txt: Added.
* fast/js/regress/switch-char.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153234 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2638ac9..1ed6536 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,85 @@
+2013-06-18  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: DFG should have switch_char
+        https://bugs.webkit.org/show_bug.cgi?id=117710
+
+        Reviewed by Michael Saboff.
+        
+        Add op_switch_char. Most of this is fairly simple, except for the whole
+        LazyJSValue thing.
+        
+        It's long been the case that anytime you wanted the DFG to speak of a string
+        that didn't appear in the constant pool, you would have a hard time since
+        the DFG isn't allowed to allocate in the GC heap. For example, if you know
+        that you want to speak of a single character string, you might find that
+        the one you wanted to speak of had been GC'd. Another example is if you
+        wanted to add constant folding for string concatenation - something we don't
+        have yet but will want eventually.
+        
+        I solve this by finally adding the notion of LazyJSValue. In the future I
+        anticipate using this for a variety of string-related things. The idea here
+        is that the DFG can either say that it already knows what the value is, or
+        it can describe the value. For example, in this patch I needed to be able to
+        describe single-character strings.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::CodeBlock):
+        * bytecode/JumpTable.h:
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (InlineStackEntry):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::run):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compile):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGPRInfo.h:
+        (JSC::DFG::JSValueRegs::payloadGPR):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::jumpTable):
+        (DFG):
+        (JSC::DFG::JITCompiler::numberOfJumpTables):
+        (JSC::DFG::JITCompiler::linkSwitches):
+        (JSC::DFG::JITCompiler::link):
+        * dfg/DFGJITCompiler.h:
+        (JITCompiler):
+        * dfg/DFGLazyJSValue.cpp: Added.
+        (DFG):
+        (JSC::DFG::LazyJSValue::getValue):
+        (JSC::DFG::equalToSingleCharacter):
+        (JSC::DFG::LazyJSValue::strictEqual):
+        (JSC::DFG::LazyJSValue::dump):
+        * dfg/DFGLazyJSValue.h: Added.
+        (DFG):
+        (LazyJSValue):
+        (JSC::DFG::LazyJSValue::LazyJSValue):
+        (JSC::DFG::LazyJSValue::singleCharacterString):
+        (JSC::DFG::LazyJSValue::tryGetValue):
+        (JSC::DFG::LazyJSValue::value):
+        (JSC::DFG::LazyJSValue::character):
+        (JSC::DFG::LazyJSValue::switchLookupValue):
+        * dfg/DFGNode.h:
+        (JSC::DFG::SwitchCase::SwitchCase):
+        (SwitchCase):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitSwitchIntJump):
+        (JSC::DFG::SpeculativeJIT::emitSwitchImmIntJump):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::emitSwitchImm):
+        (JSC::DFG::SpeculativeJIT::emitSwitchCharStringJump):
+        (JSC::DFG::SpeculativeJIT::emitSwitchChar):
+        (JSC::DFG::SpeculativeJIT::emitSwitch):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+
 2013-06-19  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Refactor ObjCCallbackFunction to inherit directly from InternalFunction
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 7a633d6..58aa2f6 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -756,6 +756,8 @@
 		A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386551118697B400540279 /* SpecializedThunkJIT.h */; };
 		A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7386552118697B400540279 /* ThunkGenerators.cpp */; };
 		A7386556118697B400540279 /* ThunkGenerators.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386553118697B400540279 /* ThunkGenerators.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		A73A535A1799CD5D00170C19 /* DFGLazyJSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */; };
+		A73A535B1799CD5D00170C19 /* DFGLazyJSValue.h in Headers */ = {isa = PBXBuildFile; fileRef = A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A73E1330179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A73E132C179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp */; };
 		A73E1331179624CD00E4DEA8 /* DFGDesiredStructureChains.h in Headers */ = {isa = PBXBuildFile; fileRef = A73E132D179624CD00E4DEA8 /* DFGDesiredStructureChains.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A7482B9311671147003B0712 /* JSWeakObjectMapRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1789,6 +1791,8 @@
 		A7386551118697B400540279 /* SpecializedThunkJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecializedThunkJIT.h; sourceTree = "<group>"; };
 		A7386552118697B400540279 /* ThunkGenerators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThunkGenerators.cpp; sourceTree = "<group>"; };
 		A7386553118697B400540279 /* ThunkGenerators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerators.h; sourceTree = "<group>"; };
+		A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyJSValue.cpp; path = dfg/DFGLazyJSValue.cpp; sourceTree = "<group>"; };
+		A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyJSValue.h; path = dfg/DFGLazyJSValue.h; sourceTree = "<group>"; };
 		A73E132C179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredStructureChains.cpp; path = dfg/DFGDesiredStructureChains.cpp; sourceTree = "<group>"; };
 		A73E132D179624CD00E4DEA8 /* DFGDesiredStructureChains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredStructureChains.h; path = dfg/DFGDesiredStructureChains.h; sourceTree = "<group>"; };
 		A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefPrivate.h; sourceTree = "<group>"; };
@@ -2972,6 +2976,8 @@
 		86EC9DB31328DF44002B2AD7 /* dfg */ = {
 			isa = PBXGroup;
 			children = (
+				A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */,
+				A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */,
 				0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */,
 				0F62016E143FCD2F0068B77C /* DFGAbstractState.h */,
 				0F55C19317276E4600CEABFD /* DFGAbstractValue.cpp */,
@@ -3714,6 +3720,7 @@
 				14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */,
 				BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */,
 				BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
+				A73A535B1799CD5D00170C19 /* DFGLazyJSValue.h in Headers */,
 				E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
 				969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */,
 				0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
@@ -4283,6 +4290,7 @@
 				0FC09776146943B000CF2442 /* DFGOSRExitCompiler32_64.cpp in Sources */,
 				0FC0977214693AF900CF2442 /* DFGOSRExitCompiler64.cpp in Sources */,
 				0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */,
+				A73A535A1799CD5D00170C19 /* DFGLazyJSValue.cpp in Sources */,
 				0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */,
 				0F235BED17178E7300690C7F /* DFGOSRExitPreparation.cpp in Sources */,
 				0FFFC95B14EF90AD00C72532 /* DFGPhase.cpp in Sources */,
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index aff2766..349a664 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -564,7 +564,7 @@
                     continue;
                 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
                 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
-                out.printf("\t\t\"%s\" => %04d\n", String(&ch, 1).utf8().data(), *iter);
+                out.printf("\t\t\"%s\" => %04d\n", StringImpl::utf8ForCharacters(&ch, 1).data(), *iter);
             }
             out.printf("      }\n");
             ++i;
@@ -1839,6 +1839,20 @@
     optimizeAfterWarmUp();
     jitAfterWarmUp();
 
+    // If the concurrent thread will want the code block's hash, then compute it here
+    // synchronously.
+    if (Options::showDisassembly()
+        || Options::showDFGDisassembly()
+        || Options::dumpBytecodeAtDFGTime()
+        || Options::verboseCompilation()
+        || Options::logCompilationChanges()
+        || Options::validateGraph()
+        || Options::validateGraphAtEachPhase()
+        || Options::verboseOSR()
+        || Options::verboseCompilationQueue()
+        || Options::reportCompileTimes())
+        hash();
+
     if (Options::dumpGeneratedBytecodes())
         dumpBytecode();
     m_vm->finishedCompiling(this);
diff --git a/Source/JavaScriptCore/bytecode/JumpTable.h b/Source/JavaScriptCore/bytecode/JumpTable.h
index 6b3a713..aa90482 100644
--- a/Source/JavaScriptCore/bytecode/JumpTable.h
+++ b/Source/JavaScriptCore/bytecode/JumpTable.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
index 7b5c475..df27a9a 100644
--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
@@ -350,14 +350,17 @@
         case Switch: {
             SwitchData* data = node->switchData();
             switch (data->kind) {
-            case SwitchImm: {
+            case SwitchImm:
+            case SwitchChar: {
                 // 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.
+                // or strings then -0 and 0 are treated the same.  We don't need
+                // NodeUsedAsOther because if all of the cases are integers or
+                // single-character strings then NaN and undefined are treated the same
+                // (i.e. they will take default).
                 node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
                 break;
-            } }
+            }
+            }
             break;
         }
             
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index fae82f4..649ef77 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1010,6 +1010,7 @@
         Vector<unsigned> m_constantRemap;
         Vector<unsigned> m_constantBufferRemap;
         Vector<unsigned> m_switchImmRemap;
+        Vector<unsigned> m_switchCharRemap;
         
         // Blocks introduced by this code block, which need successor linking.
         // May include up to one basic block that includes the continuation after
@@ -2776,6 +2777,26 @@
             addToGraph(Switch, OpInfo(&m_graph.m_switchData.last()), get(currentInstruction[3].u.operand));
             LAST_OPCODE(op_switch_imm);
         }
+            
+        case op_switch_char: {
+            SwitchData data;
+            data.kind = SwitchChar;
+            data.switchTableIndex = m_inlineStackTop->m_switchCharRemap[currentInstruction[1].u.operand];
+            data.fallThrough = m_currentIndex + currentInstruction[2].u.operand;
+            SimpleJumpTable& table = m_codeBlock->characterSwitchJumpTable(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(LazyJSValue::singleCharacterString(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_char);
+        }
 
         case op_ret:
             flushArgumentsAndCapturedVariables();
@@ -3274,6 +3295,7 @@
         m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
         m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
         m_switchImmRemap.resize(codeBlock->numberOfImmediateSwitchJumpTables());
+        m_switchCharRemap.resize(codeBlock->numberOfCharacterSwitchJumpTables());
 
         for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) {
             StringImpl* rep = codeBlock->identifier(i).impl();
@@ -3318,6 +3340,10 @@
             m_switchImmRemap[i] = byteCodeParser->m_codeBlock->numberOfImmediateSwitchJumpTables();
             byteCodeParser->m_codeBlock->addImmediateSwitchJumpTable() = codeBlock->immediateSwitchJumpTable(i);
         }
+        for (unsigned i = 0; i < codeBlock->numberOfCharacterSwitchJumpTables(); ++i) {
+            m_switchCharRemap[i] = byteCodeParser->m_codeBlock->numberOfCharacterSwitchJumpTables();
+            byteCodeParser->m_codeBlock->addCharacterSwitchJumpTable() = codeBlock->characterSwitchJumpTable(i);
+        }
         m_callsiteBlockHeadNeedsLinking = true;
     } else {
         // Machine code block case.
@@ -3333,6 +3359,7 @@
         m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
         m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
         m_switchImmRemap.resize(codeBlock->numberOfImmediateSwitchJumpTables());
+        m_switchCharRemap.resize(codeBlock->numberOfCharacterSwitchJumpTables());
         for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i)
             m_identifierRemap[i] = i;
         for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i)
@@ -3341,6 +3368,8 @@
             m_constantBufferRemap[i] = i;
         for (size_t i = 0; i < codeBlock->numberOfImmediateSwitchJumpTables(); ++i)
             m_switchImmRemap[i] = i;
+        for (size_t i = 0; i < codeBlock->numberOfCharacterSwitchJumpTables(); ++i)
+            m_switchCharRemap[i] = i;
         m_callsiteBlockHeadNeedsLinking = false;
     }
     
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index 7bacc7c..af92a1d 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -188,7 +188,7 @@
                         TriState found = FalseTriState;
                         BlockIndex targetBlockIndex = NoBlock;
                         for (unsigned i = data->cases.size(); found == FalseTriState && i--;) {
-                            found = JSValue::pureStrictEqual(value, data->cases[i].value);
+                            found = data->cases[i].value.strictEqual(value);
                             if (found == TrueTriState)
                                 targetBlockIndex = data->cases[i].target;
                         }
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 7deec2f..efeb61f 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -167,6 +167,7 @@
     case op_typeof:
     case op_to_number:
     case op_switch_imm:
+    case op_switch_char:
     case op_in:
     case op_get_from_scope:
     case op_put_to_scope:
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 9b6b580..9fefcc4 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -71,20 +71,6 @@
         return CompilationFailed;
 
     
-    // If the concurrent thread will want the code block's hash, then compute it here
-    // synchronously.
-    if (Options::showDisassembly()
-        || Options::showDFGDisassembly()
-        || Options::dumpBytecodeAtDFGTime()
-        || Options::verboseCompilation()
-        || Options::logCompilationChanges()
-        || Options::validateGraph()
-        || Options::validateGraphAtEachPhase()
-        || Options::verboseOSR()
-        || Options::verboseCompilationQueue()
-        || Options::reportCompileTimes())
-        codeBlock->hash();
-    
     if (logCompilationChanges())
         dataLog("DFG(Driver) compiling ", *codeBlock, ", number of instructions = ", codeBlock->instructionCount(), "\n");
     
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 6af634f..e8b0b5b 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -585,6 +585,10 @@
                 if (node->child1()->shouldSpeculateInteger())
                     setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
                 break;
+            case SwitchChar:
+                if (node->child1()->shouldSpeculateString())
+                    setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+                break;
             }
             break;
         }
diff --git a/Source/JavaScriptCore/dfg/DFGGPRInfo.h b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
index f9b9e75..020943c 100644
--- a/Source/JavaScriptCore/dfg/DFGGPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
@@ -59,6 +59,7 @@
     bool operator!() const { return m_gpr == InvalidGPRReg; }
     
     GPRReg gpr() const { return m_gpr; }
+    GPRReg payloadGPR() const { return m_gpr; }
     
 private:
     GPRReg m_gpr;
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 3b84e9e..a112988 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -150,40 +150,66 @@
     }
 }
 
-void JITCompiler::link(LinkBuffer& linkBuffer)
+SimpleJumpTable& JITCompiler::jumpTable(SwitchKind kind, unsigned index)
 {
-    // Link the code, populate data in CodeBlock data structures.
-#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
-    
+    switch (kind) {
+    case SwitchImm:
+        return m_codeBlock->immediateSwitchJumpTable(index);
+    case SwitchChar:
+        return m_codeBlock->characterSwitchJumpTable(index);
+    }
+}
+
+unsigned JITCompiler::numberOfJumpTables(SwitchKind kind)
+{
+    switch (kind) {
+    case SwitchImm:
+        return m_codeBlock->numberOfImmediateSwitchJumpTables();
+    case SwitchChar:
+        return m_codeBlock->numberOfCharacterSwitchJumpTables();
+    }
+}
+
+void JITCompiler::linkSwitches(LinkBuffer& linkBuffer, SwitchKind kind)
+{
     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));
+        if (data.kind != kind)
+            continue;
         
         usedJumpTables.set(data.switchTableIndex);
-        SimpleJumpTable& table =
-            m_codeBlock->immediateSwitchJumpTable(data.switchTableIndex);
+        SimpleJumpTable& table = jumpTable(kind, 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] =
+            table.ctiOffsets[myCase.value.switchLookupValue() - table.min] =
                 linkBuffer.locationOf(m_blockHeads[myCase.target]);
         }
     }
-    for (unsigned i = m_codeBlock->numberOfImmediateSwitchJumpTables(); i--;) {
+    
+    for (unsigned i = numberOfJumpTables(kind); i--;) {
         if (usedJumpTables.get(i))
             continue;
         
-        m_codeBlock->immediateSwitchJumpTable(i).clear();
+        jumpTable(kind, i).clear();
     }
+}
+
+void JITCompiler::link(LinkBuffer& linkBuffer)
+{
+    // Link the code, populate data in CodeBlock data structures.
+#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
+
+    linkSwitches(linkBuffer, SwitchImm);
+    linkSwitches(linkBuffer, SwitchChar);
 
     // 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 335b2b3..8b7878e 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -472,6 +472,10 @@
     void compileEntry();
     void compileBody();
     void link(LinkBuffer&);
+    
+    SimpleJumpTable& jumpTable(SwitchKind, unsigned);
+    unsigned numberOfJumpTables(SwitchKind);
+    void linkSwitches(LinkBuffer&, SwitchKind);
 
     void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*);
     void compileExceptionHandlers();
diff --git a/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp b/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp
new file mode 100644
index 0000000..0a6fc04
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGLazyJSValue.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+JSValue LazyJSValue::getValue(VM& vm) const
+{
+    switch (m_kind) {
+    case KnownValue:
+        return value();
+    case SingleCharacterString:
+        return jsSingleCharacterString(&vm, u.character);
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+static TriState equalToSingleCharacter(JSValue value, UChar character)
+{
+    if (!value.isString())
+        return FalseTriState;
+    
+    JSString* jsString = asString(value);
+    if (jsString->length() != 1)
+        return FalseTriState;
+    
+    const StringImpl* string = jsString->tryGetValueImpl();
+    if (!string)
+        return MixedTriState;
+    
+    return triState(string->at(0) == character);
+}
+
+TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
+{
+    switch (m_kind) {
+    case KnownValue:
+        switch (other.m_kind) {
+        case KnownValue:
+            return JSValue::pureStrictEqual(value(), other.value());
+        case SingleCharacterString:
+            return equalToSingleCharacter(value(), other.character());
+        }
+        break;
+    case SingleCharacterString:
+        switch (other.m_kind) {
+        case SingleCharacterString:
+            return triState(character() == other.character());
+        default:
+            return other.strictEqual(*this);
+        }
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+void LazyJSValue::dump(PrintStream& out) const
+{
+    switch (m_kind) {
+    case KnownValue:
+        value().dump(out);
+        return;
+    case SingleCharacterString:
+        out.print("Lazy:SingleCharacterString(");
+        out.printf("%04X", static_cast<unsigned>(character()));
+        out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
+        return;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGLazyJSValue.h b/Source/JavaScriptCore/dfg/DFGLazyJSValue.h
new file mode 100644
index 0000000..16f8a1a
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGLazyJSValue.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGLazyJSValue_h
+#define DFGLazyJSValue_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "JSCJSValue.h"
+#include <wtf/text/StringImpl.h>
+
+namespace JSC { namespace DFG {
+
+// Represents either a JSValue, or for JSValues that require allocation in the heap,
+// it tells you everything you'd need to know in order to allocate it.
+
+enum LazinessKind {
+    KnownValue,
+    SingleCharacterString
+};
+
+class LazyJSValue {
+public:
+    LazyJSValue(JSValue value = JSValue())
+        : m_kind(KnownValue)
+    {
+        u.value = JSValue::encode(value);
+    }
+    
+    static LazyJSValue singleCharacterString(UChar character)
+    {
+        LazyJSValue result;
+        result.m_kind = SingleCharacterString;
+        result.u.character = character;
+        return result;
+    }
+    
+    JSValue tryGetValue() const
+    {
+        if (m_kind == KnownValue)
+            return value();
+        return JSValue();
+    }
+    
+    JSValue getValue(VM&) const;
+    
+    JSValue value() const
+    {
+        ASSERT(m_kind == KnownValue);
+        return JSValue::decode(u.value);
+    }
+    
+    UChar character() const
+    {
+        ASSERT(m_kind == SingleCharacterString);
+        return u.character;
+    }
+    
+    TriState strictEqual(const LazyJSValue& other) const;
+    
+    unsigned switchLookupValue() const
+    {
+        // NB. Not every kind of JSValue will be able to give you a switch lookup
+        // value, and this method will assert, or do bad things, if you use it
+        // for a kind of value that can't.
+        switch (m_kind) {
+        case KnownValue:
+            return value().asInt32();
+        case SingleCharacterString:
+            return character();
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
+    void dump(PrintStream&) const;
+    
+private:
+    union {
+        EncodedJSValue value;
+        UChar character;
+    } u;
+    LazinessKind m_kind;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGLazyJSValue_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index a1fce48..e5660c7 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -36,6 +36,7 @@
 #include "DFGAdjacencyList.h"
 #include "DFGArrayMode.h"
 #include "DFGCommon.h"
+#include "DFGLazyJSValue.h"
 #include "DFGNodeFlags.h"
 #include "DFGNodeType.h"
 #include "DFGVariableAccessData.h"
@@ -83,18 +84,19 @@
     {
     }
     
-    SwitchCase(JSValue value, BlockIndex target)
+    SwitchCase(LazyJSValue value, BlockIndex target)
         : value(value)
         , target(target)
     {
     }
     
-    JSValue value;
+    LazyJSValue value;
     BlockIndex target;
 };
 
 enum SwitchKind {
-    SwitchImm
+    SwitchImm,
+    SwitchChar
 };
 
 struct SwitchData {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index ad89913..bbc4d40 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4634,9 +4634,9 @@
     }
 }
 
-void SpeculativeJIT::emitSwitchImmIntJump(Node*, SwitchData* data, GPRReg value, GPRReg scratch)
+void SpeculativeJIT::emitSwitchIntJump(
+    SwitchData* data, SimpleJumpTable& table, 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())),
@@ -4647,13 +4647,21 @@
     data->didUseJumpTable = true;
 }
 
+void SpeculativeJIT::emitSwitchImmIntJump(
+    SwitchData* data, GPRReg value, GPRReg scratch)
+{
+    emitSwitchIntJump(
+        data, m_jit.codeBlock()->immediateSwitchJumpTable(data->switchTableIndex),
+        value, scratch);
+}
+
 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());
+        emitSwitchImmIntJump(data, value.gpr(), temp.gpr());
         noResult(node);
         break;
     }
@@ -4669,7 +4677,7 @@
 #if USE(JSVALUE64)
         JITCompiler::Jump notInt = m_jit.branch64(
             JITCompiler::Below, valueRegs.gpr(), GPRInfo::tagTypeNumberRegister);
-        emitSwitchImmIntJump(node, data, valueRegs.gpr(), scratch);
+        emitSwitchImmIntJump(data, valueRegs.gpr(), scratch);
         notInt.link(&m_jit);
         addBranch(
             m_jit.branchTest64(
@@ -4682,7 +4690,7 @@
 #else
         JITCompiler::Jump notInt = m_jit.branch32(
             JITCompiler::NotEqual, valueRegs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
-        emitSwitchImmIntJump(node, data, valueRegs.payloadGPR(), scratch);
+        emitSwitchImmIntJump(data, valueRegs.payloadGPR(), scratch);
         notInt.link(&m_jit);
         addBranch(
             m_jit.branch32(
@@ -4704,6 +4712,105 @@
     }
 }
 
+void SpeculativeJIT::emitSwitchCharStringJump(
+    SwitchData* data, GPRReg value, GPRReg scratch)
+{
+    addBranch(
+        m_jit.branch32(
+            MacroAssembler::NotEqual,
+            MacroAssembler::Address(value, JSString::offsetOfLength()),
+            TrustedImm32(1)),
+        data->fallThrough);
+    
+    m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
+    
+    addSlowPathGenerator(
+        slowPathCall(
+            m_jit.branchTestPtr(MacroAssembler::Zero, scratch),
+            this, operationResolveRope, scratch, value));
+    
+    m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value);
+    
+    JITCompiler::Jump is8Bit = m_jit.branchTest32(
+        MacroAssembler::NonZero,
+        MacroAssembler::Address(scratch, StringImpl::flagsOffset()),
+        TrustedImm32(StringImpl::flagIs8Bit()));
+    
+    m_jit.load16(MacroAssembler::Address(value), scratch);
+    
+    JITCompiler::Jump ready = m_jit.jump();
+    
+    is8Bit.link(&m_jit);
+    m_jit.load8(MacroAssembler::Address(value), scratch);
+    
+    ready.link(&m_jit);
+    emitSwitchIntJump(
+        data, m_jit.codeBlock()->characterSwitchJumpTable(data->switchTableIndex),
+        scratch, value);
+}
+
+void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data)
+{
+    switch (node->child1().useKind()) {
+    case StringUse: {
+        SpeculateCellOperand op1(this, node->child1());
+        GPRTemporary temp(this);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg tempGPR = temp.gpr();
+        
+        op1.use();
+
+        DFG_TYPE_CHECK(
+            JSValueSource::unboxedCell(op1GPR), node->child1(), SpecString, m_jit.branchPtr(
+                MacroAssembler::NotEqual,
+                MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+                MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+        
+        emitSwitchCharStringJump(data, op1GPR, tempGPR);
+        noResult(node, UseChildrenCalledExplicitly);
+        break;
+    }
+        
+    case UntypedUse: {
+        JSValueOperand op1(this, node->child1());
+        GPRTemporary temp(this);
+        
+        JSValueRegs op1Regs = op1.jsValueRegs();
+        GPRReg tempGPR = temp.gpr();
+        
+        op1.use();
+        
+#if USE(JSVALUE64)
+        addBranch(
+            m_jit.branchTest64(
+                MacroAssembler::NonZero, op1Regs.gpr(), GPRInfo::tagMaskRegister),
+            data->fallThrough);
+#else
+        addBranch(
+            m_jit.branch32(
+                MacroAssembler::NotEqual, op1Regs.tagGPR(), TrustedImm32(JSValue::CellTag)),
+            data->fallThrough);
+#endif
+        
+        addBranch(
+            m_jit.branchPtr(
+                MacroAssembler::NotEqual,
+                MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureOffset()),
+                MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())),
+            data->fallThrough);
+        
+        emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR);
+        noResult(node, UseChildrenCalledExplicitly);
+        break;
+    }
+        
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
 void SpeculativeJIT::emitSwitch(Node* node)
 {
     SwitchData* data = node->switchData();
@@ -4711,6 +4818,10 @@
     case SwitchImm: {
         emitSwitchImm(node, data);
         return;
+    }
+    case SwitchChar: {
+        emitSwitchChar(node, data);
+        return;
     } }
     RELEASE_ASSERT_NOT_REACHED();
 }
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index cb6fc9e..413a34a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1862,8 +1862,11 @@
     void compileStringEquality(Node*);
     void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
     void emitBranch(Node*);
-    void emitSwitchImmIntJump(Node*, SwitchData*, GPRReg value, GPRReg scratch);
+    void emitSwitchIntJump(SwitchData*, SimpleJumpTable&, GPRReg value, GPRReg scratch);
+    void emitSwitchImmIntJump(SwitchData*, GPRReg value, GPRReg scratch);
     void emitSwitchImm(Node*, SwitchData*);
+    void emitSwitchCharStringJump(SwitchData*, GPRReg value, GPRReg scratch);
+    void emitSwitchChar(Node*, SwitchData*);
     void emitSwitch(Node*);
     
     void compileToStringOnCell(Node*);
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index ad952f6..4aaf55e 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -79,7 +79,6 @@
     case Jump:
     case ForceOSRExit:
     case ForwardForceOSRExit:
-    case Switch:
         // These are OK.
         break;
     case GetArrayLength:
@@ -141,6 +140,14 @@
             return false;
         }
         break;
+    case Switch:
+        switch (node->switchData()->kind) {
+        case SwitchImm:
+            break;
+        default:
+            return false;
+        }
+        break;
     default:
         // Don't know how to handle anything else.
         return false;
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index cd5b8c4..21f13f5 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -1489,7 +1489,7 @@
             Vector<SwitchCase> cases;
             for (unsigned i = 0; i < data->cases.size(); ++i) {
                 cases.append(SwitchCase(
-                    m_out.constInt32(data->cases[i].value.asInt32()),
+                    m_out.constInt32(data->cases[i].value.switchLookupValue()),
                     m_blocks.get(m_graph.m_blocks[data->cases[i].target].get())));
             }
             
@@ -1497,7 +1497,12 @@
                 intValue, cases,
                 m_blocks.get(m_graph.m_blocks[data->fallThrough].get()));
             return;
-        } }
+        }
+        
+        case SwitchChar:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
         RELEASE_ASSERT_NOT_REACHED();
     }