| 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: |
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.