Changeset 63244 in webkit for trunk/JavaScriptCore/bytecompiler


Ignore:
Timestamp:
Jul 13, 2010, 1:34:11 PM (15 years ago)
Author:
[email protected]
Message:

Bug 42182 - Change how numeric compare functions are detected

Reviewed by Oliver Hunt.

JavaScriptCore:

There are three problems with the current mechanism:

  • It requires that a function executable be bytecode compiled without being JIT generated (in order to copy the bytecode from the numeric compare function). This is a problem since we have an invariant when running with the JIT that functions are never bytecode compiled without also being JIT generated (after checking the codeblock we assume the function has JIT code). To help maintain this invariant
  • This implementation will prevent us from experimenting with alternate compilation paths which do not compile via bytecode.
  • It doesn't work. Functions passing more than two arguments will match if they are comparing their last two arguments, not the first two. Generally the mapping back from bytecode to semantics may be more complex then initially expected.
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::setIsNumericCompareFunction):
(JSC::BytecodeGenerator::argumentNumberFor):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::BlockNode::singleStatement):
(JSC::FunctionBodyNode::emitBytecode):

  • parser/Nodes.h:

(JSC::ExpressionNode::isSubtract):
(JSC::BinaryOpNode::lhs):
(JSC::BinaryOpNode::rhs):
(JSC::SubNode::isSubtract):
(JSC::ReturnNode::value):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:

LayoutTests:

Test case.

  • fast/js/array-sort-numericCompare-expected.txt: Added.
  • fast/js/array-sort-numericCompare.html: Added.
  • fast/js/script-tests/array-sort-numericCompare.js: Added.

(doSort):
(dontSort):

Location:
trunk/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r62896 r63244  
    153153    if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
    154154        symbolTable().clear();
    155        
    156     m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec()));
    157155
    158156#if !ENABLE(OPCODE_SAMPLING)
     
    20462044}
    20472045
     2046void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction)
     2047{
     2048    m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction);
     2049}
     2050
     2051int BytecodeGenerator::argumentNumberFor(const Identifier& ident)
     2052{
     2053    int parameterCount = m_parameters.size(); // includes 'this'
     2054    int index = registerFor(ident)->index() + RegisterFile::CallFrameHeaderSize + parameterCount;
     2055    return (index > 0 && index < parameterCount) ? index : 0;
     2056}
     2057
    20482058} // namespace JSC
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r62896 r63244  
    109109        // require explicit reference counting.
    110110        RegisterID* registerFor(const Identifier&);
    111        
     111
     112        // Returns the agument number if this is an argument, or 0 if not.
     113        int argumentNumberFor(const Identifier&);
     114
     115        void setIsNumericCompareFunction(bool isNumericCompareFunction);
     116
    112117        bool willResolveToArguments(const Identifier&);
    113118        RegisterID* uncheckedRegisterForArguments();
  • trunk/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r62896 r63244  
    13601360}
    13611361
     1362inline StatementNode* BlockNode::singleStatement() const
     1363{
     1364    return m_statements ? m_statements->singleStatement() : 0;
     1365}
     1366
    13621367RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    13631368{
     
    20122017    generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
    20132018    emitStatementsBytecode(generator, generator.ignoredResult());
     2019
    20142020    StatementNode* singleStatement = this->singleStatement();
     2021    ReturnNode* returnNode = 0;
     2022
     2023    // Check for a return statement at the end of a function composed of a single block.
    20152024    if (singleStatement && singleStatement->isBlock()) {
    20162025        StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
    20172026        if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
    2018             return 0;
    2019     }
    2020 
    2021     RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
    2022     generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
    2023     generator.emitReturn(r0);
     2027            returnNode = static_cast<ReturnNode*>(lastStatementInBlock);
     2028    }
     2029
     2030    // If there is no return we must automatically insert one.
     2031    if (!returnNode) {
     2032        RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
     2033        generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
     2034        generator.emitReturn(r0);
     2035        return 0;
     2036    }
     2037
     2038    // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare.
     2039    if (returnNode && static_cast<BlockNode*>(singleStatement)->singleStatement()) {
     2040        ExpressionNode* returnValueExpression = returnNode->value();
     2041        if (returnValueExpression && returnValueExpression->isSubtract()) {
     2042            ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs();
     2043            ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs();
     2044            if (lhsExpression->isResolveNode() && rhsExpression->isResolveNode()) {
     2045                generator.setIsNumericCompareFunction(generator.argumentNumberFor(static_cast<ResolveNode*>(lhsExpression)->identifier()) == 1
     2046                    && generator.argumentNumberFor(static_cast<ResolveNode*>(rhsExpression)->identifier()) == 2);
     2047            }
     2048        }
     2049    }
     2050
    20242051    return 0;
    20252052}
Note: See TracChangeset for help on using the changeset viewer.