Title: [149236] trunk
Revision
149236
Author
[email protected]
Date
2013-04-26 23:43:33 -0700 (Fri, 26 Apr 2013)

Log Message

Source/_javascript_Core: Re-landing <http://trac.webkit.org/changeset/148999>

    Filled out more cases of branch folding in bytecode when emitting
    expressions into a branching context
    https://bugs.webkit.org/show_bug.cgi?id=115057

    Reviewed by Phil Pizlo.

We can't fold the number == 1 case to boolean because all non-zero numbers
down-cast to true, but only 1 is == to true.

Source/WTF: Filled out more cases of branch folding in bytecode when emitting expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057

Reviewed by Filip Pizlo.

Added a helper constructor for TriState so clients can make one without
branching or making assumptions about the integer values of TriStates.

* wtf/TriState.h:
(WTF::triState):
(WTF):

LayoutTests: Re-landing <http://trac.webkit.org/changeset/148999>

    Filled out more cases of branch folding in bytecode when emitting
    expressions into a branching context
    https://bugs.webkit.org/show_bug.cgi?id=115057

    Reviewed by Phil Pizlo.

Added a more exhaustive correctness test.

* fast/js/branch-fold-correctness-expected.txt: Added.
* fast/js/branch-fold-correctness.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (149235 => 149236)


--- trunk/LayoutTests/ChangeLog	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/LayoutTests/ChangeLog	2013-04-27 06:43:33 UTC (rev 149236)
@@ -1,3 +1,18 @@
+2013-04-26  Geoffrey Garen  <[email protected]>
+
+        Re-landing <http://trac.webkit.org/changeset/148999>
+
+            Filled out more cases of branch folding in bytecode when emitting
+            expressions into a branching context
+            https://bugs.webkit.org/show_bug.cgi?id=115057
+
+            Reviewed by Phil Pizlo.
+
+        Added a more exhaustive correctness test.
+
+        * fast/js/branch-fold-correctness-expected.txt: Added.
+        * fast/js/branch-fold-correctness.html: Added.
+
 2013-04-26  Jer Noble  <[email protected]>
 
         Video playback has corruption on the edges of the video

Added: trunk/LayoutTests/fast/js/branch-fold-correctness-expected.txt (0 => 149236)


--- trunk/LayoutTests/fast/js/branch-fold-correctness-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/js/branch-fold-correctness-expected.txt	2013-04-27 06:43:33 UTC (rev 149236)
@@ -0,0 +1,4 @@
+This page tests branches that might cause interesting forms of _expression_ folding in bytecode.
+
+tests completed: 32
+

Added: trunk/LayoutTests/fast/js/branch-fold-correctness.html (0 => 149236)


--- trunk/LayoutTests/fast/js/branch-fold-correctness.html	                        (rev 0)
+++ trunk/LayoutTests/fast/js/branch-fold-correctness.html	2013-04-27 06:43:33 UTC (rev 149236)
@@ -0,0 +1,192 @@
+<p>This page tests branches that might cause interesting forms of _expression_ folding in bytecode.</p>
+<pre id="console"></pre>
+
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function log(s)
+{
+    document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
+}
+
+(function () {
+    var count = 0;
+    function fail()
+    {
+        log("FAIL on test " + count + ".");
+    }
+
+    var zero = 0;
+    var _one_ = 1;
+    var two = 2;
+
+    // bool vs bool
+    ++count;
+    if (true == (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (false == (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (true != (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (false != (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (true === (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (false === (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (true !== (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (false !== (_one_ == one)) {
+    } else
+        fail();
+
+
+    // int vs bool
+    ++count;
+    if (1 == (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 == (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 != (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 != (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 != (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 != (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 !== (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 !== (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 !== (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 !== (one != one)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 !== (_one_ == one)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 !== (_one_ == one)) {
+    } else
+        fail();
+
+
+
+    // int vs int
+    ++count;
+    if (1 == (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 == (zero | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 != (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 != (zero | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 != (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 != (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 === (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 === (zero | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 !== (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (1 !== (two | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (0 !== (one | 0)) {
+    } else
+        fail();
+
+    ++count;
+    if (2 !== (one | 0)) {
+    } else
+        fail();
+
+    log("tests completed: " + count);
+})();
+</script>

Modified: trunk/Source/_javascript_Core/ChangeLog (149235 => 149236)


--- trunk/Source/_javascript_Core/ChangeLog	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-04-27 06:43:33 UTC (rev 149236)
@@ -1,3 +1,16 @@
+2013-04-26  Geoffrey Garen  <[email protected]>
+
+        Re-landing <http://trac.webkit.org/changeset/148999>
+
+            Filled out more cases of branch folding in bytecode when emitting
+            expressions into a branching context
+            https://bugs.webkit.org/show_bug.cgi?id=115057
+
+            Reviewed by Phil Pizlo.
+
+        We can't fold the number == 1 case to boolean because all non-zero numbers
+        down-cast to true, but only 1 is == to true.
+
 2013-04-26  Filip Pizlo  <[email protected]>
 
         Correct indentation of SymbolTable.h

Modified: trunk/Source/_javascript_Core/_javascript_Core.order (149235 => 149236)


--- trunk/Source/_javascript_Core/_javascript_Core.order	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/_javascript_Core.order	2013-04-27 06:43:33 UTC (rev 149236)
@@ -717,7 +717,6 @@
 __ZNK3JSC14ExpressionNode21isBracketAccessorNodeEv
 __ZN3JSC9CodeBlock25createRareDataIfNecessaryEv
 __ZN3WTF6VectorIN3JSC8LineInfoELm0EE14expandCapacityEm
-__ZN3JSC6IfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
 __ZN3JSC17BytecodeGenerator8newLabelEv
 __ZNK3JSC14ExpressionNode26hasConditionContextCodegenEv
 __ZN3WTF6VectorIN3JSC19ExpressionRangeInfoELm0EE14expandCapacityEm

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (149235 => 149236)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2013-04-27 06:43:33 UTC (rev 149236)
@@ -1628,7 +1628,7 @@
     bool hadVariableExpression = false;
     if (length) {
         for (ElementNode* n = elements; n; n = n->next()) {
-            if (!n->value()->isNumber() && !n->value()->isString()) {
+            if (!n->value()->isConstant()) {
                 hadVariableExpression = true;
                 break;
             }
@@ -1644,12 +1644,8 @@
             JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex).data();
             unsigned index = 0;
             for (ElementNode* n = elements; index < length; n = n->next()) {
-                if (n->value()->isNumber())
-                    constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
-                else {
-                    ASSERT(n->value()->isString());
-                    constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value());
-                }
+                ASSERT(n->value()->isConstant());
+                constantBuffer[index++] = static_cast<ConstantNode*>(n->value())->jsValue(*this);
             }
             emitOpcode(op_new_array_buffer);
             instructions().append(dst->index());
@@ -2365,7 +2361,7 @@
 void BytecodeGenerator::emitThrowReferenceError(const String& message)
 {
     emitOpcode(op_throw_static_error);
-    instructions().append(addConstantValue(jsString(vm(), message))->index());
+    instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, message)))->index());
     instructions().append(true);
 }
 
@@ -2523,7 +2519,7 @@
     if (!isStrictMode())
         return;
     emitOpcode(op_throw_static_error);
-    instructions().append(addConstantValue(jsString(vm(), StrictModeReadonlyPropertyWriteError))->index());
+    instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, StrictModeReadonlyPropertyWriteError)))->index());
     instructions().append(false);
 }
 

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (149235 => 149236)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -553,6 +553,7 @@
         CodeType codeType() const { return m_codeType; }
 
         bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
+        bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; }
         
         bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
 
@@ -646,8 +647,6 @@
             return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body);
         }
 
-        JSString* addStringConstant(const Identifier&);
-
         void addLineInfo(unsigned lineNo)
         {
             m_codeBlock->addLineInfo(instructions().size(), lineNo - m_scopeNode->firstLine());
@@ -656,6 +655,8 @@
         RegisterID* emitInitLazyRegister(RegisterID*);
 
     public:
+        JSString* addStringConstant(const Identifier&);
+
         Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; }
 
         SharedSymbolTable& symbolTable() { return *m_symbolTable; }

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (149235 => 149236)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2013-04-27 06:43:33 UTC (rev 149236)
@@ -92,40 +92,31 @@
     return generator.newTemporary();
 }
 
-// ------------------------------ NullNode -------------------------------------
+// ------------------------------ ConstantNode ----------------------------------
 
-RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
 {
-    if (dst == generator.ignoredResult())
-        return 0;
-    return generator.emitLoad(dst, jsNull());
-}
+    TriState value = jsValue(generator).pureToBoolean();
+    if (value == MixedTriState)
+        ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
+    else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse)
+        generator.emitJump(trueTarget);
+    else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue)
+        generator.emitJump(falseTarget);
 
-// ------------------------------ BooleanNode ----------------------------------
-
-RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
-{
-    if (dst == generator.ignoredResult())
-        return 0;
-    return generator.emitLoad(dst, m_value);
+    // All other cases are unconditional fall-throughs, like "if (true)".
 }
 
-// ------------------------------ NumberNode -----------------------------------
-
-RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     if (dst == generator.ignoredResult())
         return 0;
-    return generator.emitLoad(dst, m_value);
+    return generator.emitLoad(dst, jsValue(generator));
 }
 
-// ------------------------------ StringNode -----------------------------------
-
-RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+JSValue StringNode::jsValue(BytecodeGenerator& generator) const
 {
-    if (dst == generator.ignoredResult())
-        return 0;
-    return generator.emitLoad(dst, m_value);
+    return generator.addStringConstant(m_value);
 }
 
 // ------------------------------ RegExpNode -----------------------------------
@@ -1042,6 +1033,64 @@
     return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size());
 }
 
+void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
+{
+    TriState branchCondition;
+    ExpressionNode* branchExpression;
+    tryFoldToBranch(generator, branchCondition, branchExpression);
+
+    if (branchCondition == MixedTriState)
+        ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
+    else if (branchCondition == TrueTriState)
+        generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode);
+    else
+        generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode));
+}
+
+static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant)
+{
+    ResultType expressionType = branchExpression->resultDescriptor();
+
+    if (expressionType.definitelyIsBoolean() && constant.isBoolean())
+        return true;
+    else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1))
+        return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch.
+    else if (expressionType.isInt32() && constant.isInt32() && constant.asInt32() == 0)
+        return true;
+
+    return false;
+}
+
+void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression)
+{
+    branchCondition = MixedTriState;
+    branchExpression = 0;
+
+    ConstantNode* constant = 0;
+    if (m_expr1->isConstant()) {
+        constant = static_cast<ConstantNode*>(m_expr1);
+        branchExpression = m_expr2;
+    } else if (m_expr2->isConstant()) {
+        constant = static_cast<ConstantNode*>(m_expr2);
+        branchExpression = m_expr1;
+    }
+
+    if (!constant)
+        return;
+    ASSERT(branchExpression);
+
+    OpcodeID opcodeID = this->opcodeID();
+    JSValue value = constant->jsValue(generator);
+    bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value);
+    if (!canFoldToBranch)
+        return;
+
+    if (opcodeID == op_eq || opcodeID == op_stricteq)
+        branchCondition = triState(value.pureToBoolean());
+    else if (opcodeID == op_neq || opcodeID == op_nstricteq)
+        branchCondition = triState(!value.pureToBoolean());
+}
+
 RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     OpcodeID opcodeID = this->opcodeID();
@@ -1504,41 +1553,71 @@
     generator.emitNode(m_expr);
 }
 
-// ------------------------------ IfNode ---------------------------------------
+// ------------------------------ IfElseNode ---------------------------------------
 
-void IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+static inline StatementNode* singleStatement(StatementNode* statementNode)
 {
-    generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
-    
-    RefPtr<Label> afterThen = generator.newLabel();
+    if (statementNode->isBlock())
+        return static_cast<BlockNode*>(statementNode)->singleStatement();
+    return statementNode;
+}
 
-    RefPtr<Label> beforeThen = generator.newLabel();
-    generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), FallThroughMeansTrue);
-    generator.emitLabel(beforeThen.get());
+bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock,
+    Label*& trueTarget, FallThroughMode& fallThroughMode)
+{
+    StatementNode* singleStatement = JSC::singleStatement(ifBlock);
+    if (!singleStatement)
+        return false;
 
-    generator.emitNode(dst, m_ifBlock);
-    generator.emitLabel(afterThen.get());
+    if (singleStatement->isBreak()) {
+        BreakNode* breakNode = static_cast<BreakNode*>(singleStatement);
+        Label* target = breakNode->trivialTarget(generator);
+        if (!target)
+            return false;
+        trueTarget = target;
+        fallThroughMode = FallThroughMeansFalse;
+        return true;
+    }
+
+    if (singleStatement->isContinue()) {
+        ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement);
+        Label* target = continueNode->trivialTarget(generator);
+        if (!target)
+            return false;
+        trueTarget = target;
+        fallThroughMode = FallThroughMeansFalse;
+        return true;
+    }
+
+    return false;
 }
 
-// ------------------------------ IfElseNode ---------------------------------------
-
 void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
     
+    RefPtr<Label> beforeThen = generator.newLabel();
     RefPtr<Label> beforeElse = generator.newLabel();
     RefPtr<Label> afterElse = generator.newLabel();
 
-    RefPtr<Label> beforeThen = generator.newLabel();
-    generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue);
+    Label* trueTarget = beforeThen.get();
+    Label* falseTarget = beforeElse.get();
+    FallThroughMode fallThroughMode = FallThroughMeansTrue;
+    bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode);
+
+    generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode);
     generator.emitLabel(beforeThen.get());
 
-    generator.emitNode(dst, m_ifBlock);
-    generator.emitJump(afterElse.get());
+    if (!didFoldIfBlock) {
+        generator.emitNode(dst, m_ifBlock);
+        if (m_elseBlock)
+            generator.emitJump(afterElse.get());
+    }
 
     generator.emitLabel(beforeElse.get());
 
-    generator.emitNode(dst, m_elseBlock);
+    if (m_elseBlock)
+        generator.emitNode(dst, m_elseBlock);
 
     generator.emitLabel(afterElse.get());
 }
@@ -1700,6 +1779,20 @@
 
 // ------------------------------ ContinueNode ---------------------------------
 
+Label* ContinueNode::trivialTarget(BytecodeGenerator& generator)
+{
+    if (generator.shouldEmitDebugHooks())
+        return 0;
+
+    LabelScope* scope = generator.continueTarget(m_ident);
+    ASSERT(scope);
+
+    if (generator.scopeDepth() != scope->scopeDepth())
+        return 0;
+
+    return scope->continueTarget();
+}
+
 void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
@@ -1713,6 +1806,20 @@
 
 // ------------------------------ BreakNode ------------------------------------
 
+Label* BreakNode::trivialTarget(BytecodeGenerator& generator)
+{
+    if (generator.shouldEmitDebugHooks())
+        return 0;
+
+    LabelScope* scope = generator.breakTarget(m_ident);
+    ASSERT(scope);
+
+    if (generator.scopeDepth() != scope->scopeDepth())
+        return 0;
+
+    return scope->breakTarget();
+}
+
 void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (149235 => 149236)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -344,16 +344,9 @@
         return result;
     }
 
-    StatementNode* createIfStatement(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* trueBlock, int start, int end)
-    {
-        IfNode* result = new (m_vm) IfNode(location, condition, trueBlock);
-        result->setLoc(start, end, location.charPosition);
-        return result;
-    }
-
     StatementNode* createIfStatement(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
     {
-        IfNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
+        IfElseNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
         result->setLoc(start, end, location.charPosition);
         return result;
     }

Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (149235 => 149236)


--- trunk/Source/_javascript_Core/parser/NodeConstructors.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -60,25 +60,30 @@
     {
     }
 
+    inline ConstantNode::ConstantNode(const JSTokenLocation& location, ResultType resultType)
+        : ExpressionNode(location, resultType)
+    {
+    }
+
     inline NullNode::NullNode(const JSTokenLocation& location)
-        : ExpressionNode(location, ResultType::nullType())
+        : ConstantNode(location, ResultType::nullType())
     {
     }
 
     inline BooleanNode::BooleanNode(const JSTokenLocation& location, bool value)
-        : ExpressionNode(location, ResultType::booleanType())
+        : ConstantNode(location, ResultType::booleanType())
         , m_value(value)
     {
     }
 
     inline NumberNode::NumberNode(const JSTokenLocation& location, double value)
-        : ExpressionNode(location, ResultType::numberType())
+        : ConstantNode(location, JSValue(value).isInt32() ? ResultType::numberTypeIsInt32() : ResultType::numberType())
         , m_value(value)
     {
     }
 
     inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value)
-        : ExpressionNode(location, ResultType::stringType())
+        : ConstantNode(location, ResultType::stringType())
         , m_value(value)
     {
     }
@@ -631,15 +636,10 @@
     {
     }
     
-    inline IfNode::IfNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock)
+    inline IfElseNode::IfElseNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
         : StatementNode(location)
         , m_condition(condition)
         , m_ifBlock(ifBlock)
-    {
-    }
-
-    inline IfElseNode::IfElseNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
-        : IfNode(location, condition, ifBlock)
         , m_elseBlock(elseBlock)
     {
     }

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (149235 => 149236)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -149,6 +149,7 @@
         virtual bool isString() const { return false; }
         virtual bool isNull() const { return false; }
         virtual bool isPure(BytecodeGenerator&) const { return false; }        
+        virtual bool isConstant() const { return false; }
         virtual bool isLocation() const { return false; }
         virtual bool isResolveNode() const { return false; }
         virtual bool isBracketAccessorNode() const { return false; }
@@ -158,6 +159,7 @@
         virtual bool isSimpleArray() const { return false; }
         virtual bool isAdd() const { return false; }
         virtual bool isSubtract() const { return false; }
+        virtual bool isBoolean() const { return false; }
 
         virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, FallThroughMode);
 
@@ -183,63 +185,67 @@
         virtual bool isEmptyStatement() const { return false; }
         virtual bool isReturnNode() const { return false; }
         virtual bool isExprStatement() const { return false; }
-
+        virtual bool isBreak() const { return false; }
+        virtual bool isContinue() const { return false; }
         virtual bool isBlock() const { return false; }
 
     private:
         int m_lastLine;
     };
 
-    class NullNode : public ExpressionNode {
+    class ConstantNode : public ExpressionNode {
     public:
+        ConstantNode(const JSTokenLocation&, ResultType);
+        virtual bool isPure(BytecodeGenerator&) const { return true; }
+        virtual bool isConstant() const { return true; }
+        virtual JSValue jsValue(BytecodeGenerator&) const = 0;
+    private:
+        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+        void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode);
+    };
+
+    class NullNode : public ConstantNode {
+    public:
         NullNode(const JSTokenLocation&);
 
     private:
-        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
-
         virtual bool isNull() const { return true; }
+        virtual JSValue jsValue(BytecodeGenerator&) const { return jsNull(); }
     };
 
-    class BooleanNode : public ExpressionNode {
+    class BooleanNode : public ConstantNode {
     public:
         BooleanNode(const JSTokenLocation&, bool value);
+        bool value() { return m_value; }
 
     private:
-        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+        virtual bool isBoolean() const { return true; }
+        virtual JSValue jsValue(BytecodeGenerator&) const { return jsBoolean(m_value); }
 
-        virtual bool isPure(BytecodeGenerator&) const { return true; }
-
         bool m_value;
     };
 
-    class NumberNode : public ExpressionNode {
+    class NumberNode : public ConstantNode {
     public:
         NumberNode(const JSTokenLocation&, double value);
-
-        double value() const { return m_value; }
+        double value() { return m_value; }
         void setValue(double value) { m_value = value; }
 
     private:
-        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
-
         virtual bool isNumber() const { return true; }
-        virtual bool isPure(BytecodeGenerator&) const { return true; }
+        virtual JSValue jsValue(BytecodeGenerator&) const { return jsNumber(m_value); }
 
         double m_value;
     };
 
-    class StringNode : public ExpressionNode {
+    class StringNode : public ConstantNode {
     public:
         StringNode(const JSTokenLocation&, const Identifier&);
-
         const Identifier& value() { return m_value; }
 
     private:
-        virtual bool isPure(BytecodeGenerator&) const { return true; }
-
-        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
-        
         virtual bool isString() const { return true; }
+        virtual JSValue jsValue(BytecodeGenerator&) const;
 
         const Identifier& m_value;
     };
@@ -745,11 +751,13 @@
         BinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
 
         RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0);
+        void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode);
 
         ExpressionNode* lhs() { return m_expr1; };
         ExpressionNode* rhs() { return m_expr2; };
 
     private:
+        void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression);
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
 
     protected:
@@ -1124,24 +1132,17 @@
         ExpressionNode* m_expr;
     };
 
-    class IfNode : public StatementNode {
+    class IfElseNode : public StatementNode {
     public:
-        IfNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock);
+        IfElseNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock);
 
-    protected:
+    private:
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+        bool tryFoldBreakAndContinue(BytecodeGenerator&, StatementNode* ifBlock,
+            Label*& trueTarget, FallThroughMode&);
 
         ExpressionNode* m_condition;
         StatementNode* m_ifBlock;
-    };
-
-    class IfElseNode : public IfNode {
-    public:
-        IfElseNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock);
-
-    private:
-        virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
-
         StatementNode* m_elseBlock;
     };
 
@@ -1198,8 +1199,10 @@
     public:
         ContinueNode(VM*, const JSTokenLocation&);
         ContinueNode(const JSTokenLocation&, const Identifier&);
+        Label* trivialTarget(BytecodeGenerator&);
         
     private:
+        virtual bool isContinue() const { return true; }
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
 
         const Identifier& m_ident;
@@ -1209,8 +1212,10 @@
     public:
         BreakNode(VM*, const JSTokenLocation&);
         BreakNode(const JSTokenLocation&, const Identifier&);
+        Label* trivialTarget(BytecodeGenerator&);
         
     private:
+        virtual bool isBreak() const { return true; }
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
 
         const Identifier& m_ident;

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (149235 => 149236)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2013-04-27 06:43:33 UTC (rev 149236)
@@ -26,10 +26,11 @@
 #include "ASTBuilder.h"
 #include "CodeBlock.h"
 #include "Debugger.h"
-#include "VM.h"
+#include "JSCJSValueInlines.h"
 #include "Lexer.h"
 #include "NodeInfo.h"
 #include "SourceProvider.h"
+#include "VM.h"
 #include <utility>
 #include <wtf/HashFunctions.h>
 #include <wtf/OwnPtr.h>
@@ -1011,7 +1012,7 @@
     failIfFalse(trueBlock);
 
     if (!match(ELSE))
-        return context.createIfStatement(ifLocation, condition, trueBlock, start, end);
+        return context.createIfStatement(ifLocation, condition, trueBlock, 0, start, end);
 
     Vector<TreeExpression> exprStack;
     Vector<pair<int, int> > posStack;
@@ -1056,7 +1057,7 @@
         posStack.removeLast();
         JSTokenLocation elseLocation = tokenLocationStack.last();
         tokenLocationStack.removeLast();
-        statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, pos.first, pos.second));
+        statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, 0, pos.first, pos.second));
     }
 
     while (!exprStack.isEmpty()) {

Modified: trunk/Source/_javascript_Core/parser/ResultType.h (149235 => 149236)


--- trunk/Source/_javascript_Core/parser/ResultType.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/parser/ResultType.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -62,6 +62,11 @@
             return (m_type & TypeBits) == TypeMaybeString;
         }
 
+        bool definitelyIsBoolean()
+        {
+            return (m_type & TypeBits) == TypeMaybeBool;
+        }
+
         bool mightBeNumber()
         {
             return m_type & TypeMaybeNumber;

Modified: trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h (149235 => 149236)


--- trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValueInlines.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -800,7 +800,7 @@
     if (isDouble())
         return (asDouble() > 0.0 || asDouble() < 0.0) ? TrueTriState : FalseTriState; // false for NaN
     if (isCell())
-        return MixedTriState;
+        return asCell()->pureToBoolean();
     return isTrue() ? TrueTriState : FalseTriState;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (149235 => 149236)


--- trunk/Source/_javascript_Core/runtime/JSCell.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -96,6 +96,7 @@
     JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
     bool toBoolean(ExecState*) const;
+    TriState pureToBoolean() const;
     JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
     JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const;
 

Modified: trunk/Source/_javascript_Core/runtime/JSCellInlines.h (149235 => 149236)


--- trunk/Source/_javascript_Core/runtime/JSCellInlines.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/_javascript_Core/runtime/JSCellInlines.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -192,6 +192,13 @@
     return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
 }
 
+inline TriState JSCell::pureToBoolean() const
+{
+    if (isString()) 
+        return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
+    return MixedTriState;
+}
+
 } // namespace JSC
 
 #endif // JSCellInlines_h

Modified: trunk/Source/WTF/ChangeLog (149235 => 149236)


--- trunk/Source/WTF/ChangeLog	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/WTF/ChangeLog	2013-04-27 06:43:33 UTC (rev 149236)
@@ -1,3 +1,17 @@
+2013-04-26  Geoffrey Garen  <[email protected]>
+
+        Filled out more cases of branch folding in bytecode when emitting expressions into a branching context
+        https://bugs.webkit.org/show_bug.cgi?id=115057
+
+        Reviewed by Filip Pizlo.
+
+        Added a helper constructor for TriState so clients can make one without
+        branching or making assumptions about the integer values of TriStates.
+
+        * wtf/TriState.h:
+        (WTF::triState):
+        (WTF):
+
 2013-04-26  Roger Fong  <[email protected]>
 
         Make Apple Windows VS2010 build results into and get dependencies from __32 suffixed folders.

Modified: trunk/Source/WTF/wtf/TriState.h (149235 => 149236)


--- trunk/Source/WTF/wtf/TriState.h	2013-04-27 06:33:34 UTC (rev 149235)
+++ trunk/Source/WTF/wtf/TriState.h	2013-04-27 06:43:33 UTC (rev 149236)
@@ -34,8 +34,13 @@
     MixedTriState
 };
 
+inline TriState triState(bool boolean)
+{
+    return static_cast<TriState>(boolean);
 }
 
+}
+
 using WTF::TriState;
 using WTF::FalseTriState;
 using WTF::TrueTriState;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to