| Paste number 64031: | patch for cpst, othermaciej or ggaren |
| Pasted by: | olliej |
| 4 months, 1 week ago | |
| #webkit | Context in IRC logs | |
| Paste contents: |
| 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.