Paste number 64031: patch for cpst, othermaciej or ggaren

Paste number 64031: patch for cpst, othermaciej or ggaren
Pasted by: olliej
When:11 months, 1 week ago
Share:Tweet this! | http://paste.lisp.org/+1DEN
Channel:#webkit
Paste contents:
Raw Source | XML | Display As
diff --git a/JavaScriptCore/VM/CodeBlock.cpp b/JavaScriptCore/VM/CodeBlock.cpp
index 0b54b73..bb78276 100644
--- a/JavaScriptCore/VM/CodeBlock.cpp
+++ b/JavaScriptCore/VM/CodeBlock.cpp
@@ -197,7 +197,22 @@ void CodeBlock::dump(ExecState* exec) const
             ++i;
         } while (i < exceptionHandlers.size());
     }
+
+    if (stringSwitchJumpTables.size()) {
+        printf("\nString-switch jump tables:\n");
+        unsigned i = 0;
+        do {
+            printf("\t{\n");
+            HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash>::const_iterator end = stringSwitchJumpTables[i].end();
+            for (HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash>::const_iterator iter = stringSwitchJumpTables[i].begin(); iter != end; ++iter) {
+                printf("\t\t%s => %04d\n", UString(iter->first).ascii(), iter->second);
+            }
+            printf("\t}\n");
+            ++i;
+        } while (i < stringSwitchJumpTables.size());
         
+    }
+
     printf("\n");
 }
 
@@ -502,6 +517,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] loop_if_less %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
             break;
         }
+        case op_switch_string: {
+            int tableIndex = (++it)->u.operand;
+            int defaultTarget = (++it)->u.operand;
+            int scrutineeRegister = (++it)->u.operand;
+            printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
+            break;
+        }
         case op_new_func: {
             int r0 = (++it)->u.operand;
             int f0 = (++it)->u.operand;
diff --git a/JavaScriptCore/VM/CodeBlock.h b/JavaScriptCore/VM/CodeBlock.h
index 6bdbe73..3c9c07d 100644
--- a/JavaScriptCore/VM/CodeBlock.h
+++ b/JavaScriptCore/VM/CodeBlock.h
@@ -111,6 +111,7 @@ namespace KJS {
         Vector<HandlerInfo> exceptionHandlers;
         Vector<ExpressionRangeInfo> expressionInfo;
         Vector<LineInfo> lineInfo;
+        Vector<HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash> > stringSwitchJumpTables;
 
     private:
         void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
diff --git a/JavaScriptCore/VM/CodeGenerator.cpp b/JavaScriptCore/VM/CodeGenerator.cpp
index 07cb873..ac4afa6 100644
--- a/JavaScriptCore/VM/CodeGenerator.cpp
+++ b/JavaScriptCore/VM/CodeGenerator.cpp
@@ -32,6 +32,7 @@
 
 #include "JSFunction.h"
 #include "Machine.h"
+#include "ustring.h"
 
 using namespace std;
 
@@ -1144,4 +1145,32 @@ void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
     instructions().append(retAddrSrc->index());
 }
 
+void CodeGenerator::startSwitch(RegisterID* scrutinee) {
+    SwitchInfo info = { instructions().size() };
+    emitOpcode(op_switch_string);
+    instructions().append(0); // place holder for table index
+    instructions().append(0); // place holder for default target    
+    instructions().append(scrutinee->index());
+    m_switchContextStack.append(info);
+}
+
+void CodeGenerator::finaliseSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel)
+{
+    HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash> jumpTable;
+    SwitchInfo switchInfo = m_switchContextStack.last();
+    for (uint32_t i = 0; i < clauseCount; i++) {
+        ASSERT(nodes[i]->isString());
+        // We're emitting this after the clause labels should have been fixed, so 
+        // the labels should not be "forward" references
+        ASSERT(!labels[i]->isForwardLabel());
+        UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
+        clause->hash();
+        jumpTable.add(clause, labels[i]->offsetFrom(switchInfo.opcodeOffset + 3)); 
+    }
+    instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->stringSwitchJumpTables.size();
+    m_codeBlock->stringSwitchJumpTables.append(jumpTable);
+    instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
+    m_switchContextStack.removeLast();
+}
+
 } // namespace KJS
diff --git a/JavaScriptCore/VM/CodeGenerator.h b/JavaScriptCore/VM/CodeGenerator.h
index ee1b239..068d259 100644
--- a/JavaScriptCore/VM/CodeGenerator.h
+++ b/JavaScriptCore/VM/CodeGenerator.h
@@ -69,6 +69,10 @@ namespace KJS {
         FinallyContext finallyContext;
     };
 
+    struct SwitchInfo {
+        uint32_t opcodeOffset;
+    };
+    
     class CodeGenerator {
     public:
         typedef DeclarationStacks::VarStack VarStack;
@@ -313,6 +317,9 @@ namespace KJS {
         JumpContext* jumpContextForContinue(const Identifier&);
         JumpContext* jumpContextForBreak(const Identifier&);
 
+        void startSwitch(RegisterID*);
+        void finaliseSwitch(uint32_t clauseCount, RefPtr<LabelID>*, ExpressionNode**, LabelID* defaultLabel);
+
         CodeType codeType() const { return m_codeType; }
 
         ExecState* globalExec() { return m_scopeChain->globalObject()->globalExec(); }
@@ -401,6 +408,7 @@ namespace KJS {
         Vector<JumpContext> m_jumpContextStack;
         int m_continueDepth;
         Vector<ControlFlowContext> m_scopeContextStack;
+        Vector<SwitchInfo> m_switchContextStack;
 
         int m_nextVar;
         int m_nextParameter;
diff --git a/JavaScriptCore/VM/Machine.cpp b/JavaScriptCore/VM/Machine.cpp
index b4fefa4..e5809c2 100644
--- a/JavaScriptCore/VM/Machine.cpp
+++ b/JavaScriptCore/VM/Machine.cpp
@@ -2127,6 +2127,24 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         ++vPC;
         NEXT_OPCODE;
     }
+    BEGIN_OPCODE(op_switch_string) {
+        int tableIndex = (++vPC)->u.operand;
+        int defaultTargetOffset = (++vPC)->u.operand;
+        JSValue* scrutinee = r[(++vPC)->u.operand].jsValue();
+        if (scrutinee->type() != StringType)
+            vPC += defaultTargetOffset;
+        else {
+            HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash>::const_iterator end = codeBlock->stringSwitchJumpTables[tableIndex].end();
+            UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
+            value->hash(); // Force computation of hash.
+            HashMap<RefPtr<UString::Rep>, int32_t, IdentifierRepHash>::const_iterator iter = codeBlock->stringSwitchJumpTables[tableIndex].find(value);
+            if (end == iter)
+                vPC += defaultTargetOffset;
+            else
+                vPC += iter->second;
+        }
+        NEXT_OPCODE;
+    }
     BEGIN_OPCODE(op_new_func) {
         /* new_func dst(r) func(f)
 
diff --git a/JavaScriptCore/VM/Opcode.cpp b/JavaScriptCore/VM/Opcode.cpp
index 3d7b252..eb9fe7c 100644
--- a/JavaScriptCore/VM/Opcode.cpp
+++ b/JavaScriptCore/VM/Opcode.cpp
@@ -109,6 +109,7 @@ static const char* opcodeNames[] = {
     "loop        ",
     "loop_if_true",
     "loop_if_less",
+    "switch_string",
 
     "new_func    ",
     "new_func_exp",
diff --git a/JavaScriptCore/VM/Opcode.h b/JavaScriptCore/VM/Opcode.h
index d7850e5..b5895c0 100644
--- a/JavaScriptCore/VM/Opcode.h
+++ b/JavaScriptCore/VM/Opcode.h
@@ -101,6 +101,7 @@ namespace KJS {
         macro(op_loop) \
         macro(op_loop_if_true) \
         macro(op_loop_if_less) \
+        macro(op_switch_string) \
         \
         macro(op_new_func) \
         macro(op_new_func_exp) \
diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp
index e325b07..b9952f7 100644
--- a/JavaScriptCore/kjs/nodes.cpp
+++ b/JavaScriptCore/kjs/nodes.cpp
@@ -1396,28 +1396,83 @@ RegisterID* WithNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst)
 {
+    RefPtr<LabelID> defaultLabel;
     Vector<RefPtr<LabelID>, 8> labelVector;
-
-    // Setup jumps
+    Vector<ExpressionNode*, 8> literalVector;
+    enum { SwitchUnset = 0, SwitchNumber = 1, SwitchString = 2, SwitchNeither = 3 } typeForTable = SwitchUnset;
     for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
-        RefPtr<RegisterID> clauseVal = generator.newTemporary();
-        generator.emitNode(clauseVal.get(), list->getClause()->expr());
-        generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
-        labelVector.append(generator.newLabel());
-        generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
+        ExpressionNode* clauseExpression = list->getClause()->expr();
+        literalVector.append(clauseExpression);
+        if (clauseExpression->isNumber()) {
+            if (typeForTable & ~SwitchNumber) {
+                typeForTable = SwitchNeither;
+                break;
+            }
+            typeForTable = SwitchNumber;
+            continue;
+        }
+        if (clauseExpression->isString()) {
+            if (typeForTable & ~SwitchString) {
+                typeForTable = SwitchNeither;
+                break;
+            }
+            typeForTable = SwitchString;
+            continue;
+        }
+        typeForTable = SwitchNeither;
+        break;        
     }
-
+    
     for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
-        RefPtr<RegisterID> clauseVal = generator.newTemporary();
-        generator.emitNode(clauseVal.get(), list->getClause()->expr());
-        generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
-        labelVector.append(generator.newLabel());
-        generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
+        ExpressionNode* clauseExpression = list->getClause()->expr();
+        literalVector.append(clauseExpression);
+        if (clauseExpression->isNumber()) {
+            if (typeForTable & ~SwitchNumber) {
+                typeForTable = SwitchNeither;
+                break;
+            }
+            typeForTable = SwitchNumber;
+            continue;
+        }
+        if (clauseExpression->isString()) {
+            if (typeForTable & ~SwitchString) {
+                typeForTable = SwitchNeither;
+                break;
+            }
+            typeForTable = SwitchString;
+            continue;
+        }
+        typeForTable = SwitchNeither;
+        break; 
+    }
+    
+    
+    if (typeForTable == SwitchString) {
+        // Prepare the various labels
+        for (uint32_t i = 0; i < literalVector.size(); i++)
+            labelVector.append(generator.newLabel());
+        defaultLabel = generator.newLabel();
+        generator.startSwitch(switchExpression);
+    } else {
+        // Setup jumps
+        for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
+            RefPtr<RegisterID> clauseVal = generator.newTemporary();
+            generator.emitNode(clauseVal.get(), list->getClause()->expr());
+            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
+            labelVector.append(generator.newLabel());
+            generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
+        }
+        
+        for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
+            RefPtr<RegisterID> clauseVal = generator.newTemporary();
+            generator.emitNode(clauseVal.get(), list->getClause()->expr());
+            generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression);
+            labelVector.append(generator.newLabel());
+            generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
+        }
+        defaultLabel = generator.newLabel();
+        generator.emitJump(defaultLabel.get());
     }
-
-    RefPtr<LabelID> defaultLabel;
-    defaultLabel = generator.newLabel();
-    generator.emitJump(defaultLabel.get());
 
     RegisterID* result = 0;
 
@@ -1440,7 +1495,10 @@ RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID
         generator.emitLabel(defaultLabel.get());
 
     ASSERT(i == labelVector.size());
-
+    if (typeForTable == SwitchString) {
+        ASSERT(labelVector.size() == literalVector.size());
+        generator.finaliseSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get());
+    }
     return result;
 }
 
diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h
index c959bb1..3843d7d 100644
--- a/JavaScriptCore/kjs/nodes.h
+++ b/JavaScriptCore/kjs/nodes.h
@@ -198,8 +198,9 @@ namespace KJS {
             : Node(globalData, expectedReturn)
         {
         }
-
+        
         virtual bool isNumber() const KJS_FAST_CALL { return false; }
+        virtual bool isString() const KJS_FAST_CALL { return false; }
         virtual bool isPure(CodeGenerator&) const KJS_FAST_CALL { return false; }        
         virtual bool isLocation() const KJS_FAST_CALL { return false; }
         virtual bool isResolveNode() const KJS_FAST_CALL { return false; }
@@ -307,7 +308,9 @@ namespace KJS {
         }
 
         virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) KJS_FAST_CALL;
-
+        
+        virtual bool isString() const KJS_FAST_CALL { return true; }
+        UString& value() { return m_value; }
         virtual bool isPure(CodeGenerator&) const KJS_FAST_CALL { return true; }
         virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
         virtual Precedence precedence() const { return PrecPrimary; }

This paste has no annotations.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.