Changeset 117542 in webkit


Ignore:
Timestamp:
May 17, 2012, 10:30:16 PM (13 years ago)
Author:
fpizlo@apple.com
Message:

DFG should optimize aliased uses of the Arguments object of the current call frame
https://bugs.webkit.org/show_bug.cgi?id=86552

Source/JavaScriptCore:

Reviewed by Geoff Garen.

Performs must-alias and escape analysis on uses of CreateArguments, and if
a variable is must-aliased to CreateArguments and does not escape, then we
turn all uses of that variable into direct arguments accesses.

36% speed-up on V8/earley leading to a 2.3% speed-up overall in V8.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::uncheckedArgumentsRegister):

  • bytecode/ValueRecovery.h:

(JSC::ValueRecovery::argumentsThatWereNotCreated):
(ValueRecovery):
(JSC::ValueRecovery::dump):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGAdjacencyList.h:

(AdjacencyList):
(JSC::DFG::AdjacencyList::removeEdgeFromBag):

  • dfg/DFGArgumentsSimplificationPhase.cpp:

(JSC::DFG::ArgumentsSimplificationPhase::run):
(ArgumentsSimplificationPhase):
(JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUse):
(JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUses):
(JSC::DFG::ArgumentsSimplificationPhase::observeProperArgumentsUse):
(JSC::DFG::ArgumentsSimplificationPhase::isOKToOptimize):
(JSC::DFG::ArgumentsSimplificationPhase::removeArgumentsReferencingPhantomChild):

  • dfg/DFGAssemblyHelpers.h:

(JSC::DFG::AssemblyHelpers::argumentsRegisterFor):
(AssemblyHelpers):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCFGSimplificationPhase.cpp:

(JSC::DFG::CFGSimplificationPhase::removePotentiallyDeadPhiReference):

  • dfg/DFGGPRInfo.h:

(GPRInfo):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::collectGarbage):
(DFG):

  • dfg/DFGGraph.h:

(Graph):
(JSC::DFG::Graph::executableFor):
(JSC::DFG::Graph::argumentsRegisterFor):
(JSC::DFG::Graph::uncheckedArgumentsRegisterFor):
(JSC::DFG::Graph::clobbersWorld):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOSRExitCompiler.cpp:
  • dfg/DFGOSRExitCompiler.h:

(JSC::DFG::OSRExitCompiler::OSRExitCompiler):
(OSRExitCompiler):

  • dfg/DFGOSRExitCompiler32_64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOSRExitCompiler64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOperations.cpp:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::ValueSource::dump):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGVariableAccessData.h:

(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::mergeIsArgumentsAlias):
(VariableAccessData):
(JSC::DFG::VariableAccessData::isArgumentsAlias):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emitSlow_op_get_argument_by_val):

LayoutTests:

Rubber stamped by Geoff Garen.

Added a bunch of tests that check that our optimizations for aliased uses of the
'arguments' object are robust against various forms of JavaScript crazy.

  • fast/js/dfg-arguments-alias-escape-expected.txt: Added.
  • fast/js/dfg-arguments-alias-escape.html: Added.
  • fast/js/dfg-arguments-alias-expected.txt: Added.
  • fast/js/dfg-arguments-alias.html: Added.
  • fast/js/dfg-arguments-cross-code-origin-expected.txt: Added.
  • fast/js/dfg-arguments-cross-code-origin.html: Added.
  • fast/js/dfg-arguments-mixed-alias-expected.txt: Added.
  • fast/js/dfg-arguments-mixed-alias.html: Added.
  • fast/js/dfg-arguments-osr-exit-expected.txt: Added.
  • fast/js/dfg-arguments-osr-exit.html: Added.
  • fast/js/dfg-arguments-unexpected-escape-expected.txt: Added.
  • fast/js/dfg-arguments-unexpected-escape.html: Added.
  • fast/js/jsc-test-list:
  • fast/js/script-tests/dfg-arguments-alias-escape.js: Added.

(foo):
(bar):

  • fast/js/script-tests/dfg-arguments-alias.js: Added.

(foo):
(bar):

  • fast/js/script-tests/dfg-arguments-cross-code-origin.js: Added.

(foo):
(bar):
(baz):

  • fast/js/script-tests/dfg-arguments-mixed-alias.js: Added.

(foo):
(bar):

  • fast/js/script-tests/dfg-arguments-osr-exit.js: Added.

(baz):
(foo):
(bar):

  • fast/js/script-tests/dfg-arguments-unexpected-escape.js: Added.

(baz):
(foo):
(bar):

Location:
branches/dfgopt
Files:
18 added
28 edited

Legend:

Unmodified
Added
Removed
  • branches/dfgopt/LayoutTests/ChangeLog

    r114449 r117542  
     12012-05-17  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG should optimize aliased uses of the Arguments object of the current call frame
     4        https://bugs.webkit.org/show_bug.cgi?id=86552
     5
     6        Rubber stamped by Geoff Garen.
     7       
     8        Added a bunch of tests that check that our optimizations for aliased uses of the
     9        'arguments' object are robust against various forms of JavaScript crazy.
     10       
     11        * fast/js/dfg-arguments-alias-escape-expected.txt: Added.
     12        * fast/js/dfg-arguments-alias-escape.html: Added.
     13        * fast/js/dfg-arguments-alias-expected.txt: Added.
     14        * fast/js/dfg-arguments-alias.html: Added.
     15        * fast/js/dfg-arguments-cross-code-origin-expected.txt: Added.
     16        * fast/js/dfg-arguments-cross-code-origin.html: Added.
     17        * fast/js/dfg-arguments-mixed-alias-expected.txt: Added.
     18        * fast/js/dfg-arguments-mixed-alias.html: Added.
     19        * fast/js/dfg-arguments-osr-exit-expected.txt: Added.
     20        * fast/js/dfg-arguments-osr-exit.html: Added.
     21        * fast/js/dfg-arguments-unexpected-escape-expected.txt: Added.
     22        * fast/js/dfg-arguments-unexpected-escape.html: Added.
     23        * fast/js/jsc-test-list:
     24        * fast/js/script-tests/dfg-arguments-alias-escape.js: Added.
     25        (foo):
     26        (bar):
     27        * fast/js/script-tests/dfg-arguments-alias.js: Added.
     28        (foo):
     29        (bar):
     30        * fast/js/script-tests/dfg-arguments-cross-code-origin.js: Added.
     31        (foo):
     32        (bar):
     33        (baz):
     34        * fast/js/script-tests/dfg-arguments-mixed-alias.js: Added.
     35        (foo):
     36        (bar):
     37        * fast/js/script-tests/dfg-arguments-osr-exit.js: Added.
     38        (baz):
     39        (foo):
     40        (bar):
     41        * fast/js/script-tests/dfg-arguments-unexpected-escape.js: Added.
     42        (baz):
     43        (foo):
     44        (bar):
     45
    1462012-04-17  Vincent Scheib  <scheib@chromium.org>
    247
  • branches/dfgopt/LayoutTests/fast/js/jsc-test-list

    r107997 r117542  
    6565fast/js/delete-getters-setters
    6666fast/js/delete-then-put
     67fast/js/dfg-arguments-osr-exit
     68fast/js/dfg-arguments-mixed-alias
     69fast/js/dfg-arguments-cross-code-origin
     70fast/js/dfg-arguments-unexpected-escape
     71fast/js/dfg-arguments-alias
     72fast/js/dfg-arguments-alias-escape
    6773fast/js/dfg-array-length-dead
    6874fast/js/dfg-convert-this-dom-window
  • branches/dfgopt/Source/JavaScriptCore/ChangeLog

    r117370 r117542  
     12012-05-17  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG should optimize aliased uses of the Arguments object of the current call frame
     4        https://bugs.webkit.org/show_bug.cgi?id=86552
     5
     6        Reviewed by Geoff Garen.
     7       
     8        Performs must-alias and escape analysis on uses of CreateArguments, and if
     9        a variable is must-aliased to CreateArguments and does not escape, then we
     10        turn all uses of that variable into direct arguments accesses.
     11       
     12        36% speed-up on V8/earley leading to a 2.3% speed-up overall in V8.
     13
     14        * bytecode/CodeBlock.h:
     15        (JSC::CodeBlock::uncheckedArgumentsRegister):
     16        * bytecode/ValueRecovery.h:
     17        (JSC::ValueRecovery::argumentsThatWereNotCreated):
     18        (ValueRecovery):
     19        (JSC::ValueRecovery::dump):
     20        * dfg/DFGAbstractState.cpp:
     21        (JSC::DFG::AbstractState::execute):
     22        * dfg/DFGAdjacencyList.h:
     23        (AdjacencyList):
     24        (JSC::DFG::AdjacencyList::removeEdgeFromBag):
     25        * dfg/DFGArgumentsSimplificationPhase.cpp:
     26        (JSC::DFG::ArgumentsSimplificationPhase::run):
     27        (ArgumentsSimplificationPhase):
     28        (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUse):
     29        (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUses):
     30        (JSC::DFG::ArgumentsSimplificationPhase::observeProperArgumentsUse):
     31        (JSC::DFG::ArgumentsSimplificationPhase::isOKToOptimize):
     32        (JSC::DFG::ArgumentsSimplificationPhase::removeArgumentsReferencingPhantomChild):
     33        * dfg/DFGAssemblyHelpers.h:
     34        (JSC::DFG::AssemblyHelpers::argumentsRegisterFor):
     35        (AssemblyHelpers):
     36        * dfg/DFGByteCodeParser.cpp:
     37        (JSC::DFG::ByteCodeParser::parseBlock):
     38        * dfg/DFGCFGSimplificationPhase.cpp:
     39        (JSC::DFG::CFGSimplificationPhase::removePotentiallyDeadPhiReference):
     40        * dfg/DFGGPRInfo.h:
     41        (GPRInfo):
     42        * dfg/DFGGraph.cpp:
     43        (JSC::DFG::Graph::collectGarbage):
     44        (DFG):
     45        * dfg/DFGGraph.h:
     46        (Graph):
     47        (JSC::DFG::Graph::executableFor):
     48        (JSC::DFG::Graph::argumentsRegisterFor):
     49        (JSC::DFG::Graph::uncheckedArgumentsRegisterFor):
     50        (JSC::DFG::Graph::clobbersWorld):
     51        * dfg/DFGNode.h:
     52        (JSC::DFG::Node::hasHeapPrediction):
     53        * dfg/DFGNodeType.h:
     54        (DFG):
     55        * dfg/DFGOSRExitCompiler.cpp:
     56        * dfg/DFGOSRExitCompiler.h:
     57        (JSC::DFG::OSRExitCompiler::OSRExitCompiler):
     58        (OSRExitCompiler):
     59        * dfg/DFGOSRExitCompiler32_64.cpp:
     60        (JSC::DFG::OSRExitCompiler::compileExit):
     61        * dfg/DFGOSRExitCompiler64.cpp:
     62        (JSC::DFG::OSRExitCompiler::compileExit):
     63        * dfg/DFGOperations.cpp:
     64        * dfg/DFGPredictionPropagationPhase.cpp:
     65        (JSC::DFG::PredictionPropagationPhase::propagate):
     66        * dfg/DFGSpeculativeJIT.cpp:
     67        (JSC::DFG::ValueSource::dump):
     68        (JSC::DFG::SpeculativeJIT::compile):
     69        (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
     70        * dfg/DFGSpeculativeJIT.h:
     71        * dfg/DFGSpeculativeJIT32_64.cpp:
     72        (JSC::DFG::SpeculativeJIT::compile):
     73        * dfg/DFGSpeculativeJIT64.cpp:
     74        (JSC::DFG::SpeculativeJIT::compile):
     75        * dfg/DFGVariableAccessData.h:
     76        (JSC::DFG::VariableAccessData::VariableAccessData):
     77        (JSC::DFG::VariableAccessData::mergeIsArgumentsAlias):
     78        (VariableAccessData):
     79        (JSC::DFG::VariableAccessData::isArgumentsAlias):
     80        * jit/JITOpcodes.cpp:
     81        (JSC::JIT::emitSlow_op_get_argument_by_val):
     82
    1832012-05-16  Filip Pizlo  <fpizlo@apple.com>
    284
  • branches/dfgopt/Source/JavaScriptCore/bytecode/CodeBlock.h

    r116912 r117542  
    448448            return m_argumentsRegister;
    449449        }
     450        int uncheckedArgumentsRegister()
     451        {
     452            if (!usesArguments())
     453                return InvalidVirtualRegister;
     454            return argumentsRegister();
     455        }
    450456        void setActivationRegister(int activationRegister)
    451457        {
  • branches/dfgopt/Source/JavaScriptCore/bytecode/ValueRecovery.h

    r112164 r117542  
    6262    CellDisplacedInRegisterFile,
    6363    BooleanDisplacedInRegisterFile,
     64    // It's an Arguments object.
     65    ArgumentsThatWereNotCreated,
    6466    // It's a constant.
    6567    Constant,
     
    188190        result.m_technique = Constant;
    189191        result.m_source.constant = JSValue::encode(value);
     192        return result;
     193    }
     194   
     195    static ValueRecovery argumentsThatWereNotCreated()
     196    {
     197        ValueRecovery result;
     198        result.m_technique = ArgumentsThatWereNotCreated;
    190199        return result;
    191200    }
     
    316325            fprintf(out, "*bool(%d)", virtualRegister());
    317326            break;
     327        case ArgumentsThatWereNotCreated:
     328            fprintf(out, "arguments");
     329            break;
    318330        case Constant:
    319331            fprintf(out, "[%s]", constant().description());
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r117370 r117542  
    10961096       
    10971097    case GetMyArgumentsLength:
    1098         if (!m_graph.m_executablesWhoseArgumentsEscaped.contains(
    1099                 m_graph.executableFor(node.codeOrigin))) {
    1100             // We know that this executable does not escape its arguments, so we can optimize
    1101             // the arguments a bit. Note that this is not sufficient to force constant folding
    1102             // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
    1103             // We perform further optimizations on this later on.
    1104             if (node.codeOrigin.inlineCallFrame) {
    1105                 forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
    1106                 break;
    1107             }
    1108             forNode(nodeIndex).set(PredictInt32);
    1109             break;
    1110         }
     1098        // We know that this executable does not escape its arguments, so we can optimize
     1099        // the arguments a bit. Note that this is not sufficient to force constant folding
     1100        // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
     1101        // We perform further optimizations on this later on.
     1102        if (node.codeOrigin.inlineCallFrame) {
     1103            forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
     1104            break;
     1105        }
     1106        forNode(nodeIndex).set(PredictInt32);
     1107        break;
     1108       
     1109    case GetMyArgumentsLengthSafe:
    11111110        // This potentially clobbers all structures if the arguments object had a getter
    11121111        // installed on the length property.
     
    11181117       
    11191118    case GetMyArgumentByVal:
    1120         if (!m_graph.m_executablesWhoseArgumentsEscaped.contains(
    1121                 m_graph.executableFor(node.codeOrigin))) {
    1122             // We know that this executable does not escape its arguments, so we can optimize
    1123             // the arguments a bit. Note that this ends up being further optimized by the
    1124             // ArgumentsSimplificationPhase.
    1125             forNode(node.child1()).filter(PredictInt32);
    1126             forNode(nodeIndex).makeTop();
    1127             break;
    1128         }
     1119        // We know that this executable does not escape its arguments, so we can optimize
     1120        // the arguments a bit. Note that this ends up being further optimized by the
     1121        // ArgumentsSimplificationPhase.
     1122        forNode(node.child1()).filter(PredictInt32);
     1123        forNode(nodeIndex).makeTop();
     1124        break;
     1125       
     1126    case GetMyArgumentByValSafe:
    11291127        // This potentially clobbers all structures if the property we're accessing has
    11301128        // a getter. We don't speculate against this.
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h

    r115512 r117542  
    129129        initialize();
    130130    }
     131   
     132    // Call this if you wish to remove an edge and the node treats the list of children
     133    // as a "bag" - an unordered set where the index of the edge does not matter.
     134    void removeEdgeFromBag(unsigned edgeIndex)
     135    {
     136        for (unsigned i = edgeIndex; i < Size - 1; ++i)
     137            setChild(i, child(i + 1));
     138        setChild(Size - 1, Edge());
     139    }
    131140
    132141    unsigned firstChild() const
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp

    r117017 r117542  
    3535#include "DFGPhase.h"
    3636#include "DFGValidate.h"
     37#include <wtf/HashSet.h>
     38#include <wtf/HashMap.h>
    3739
    3840namespace JSC { namespace DFG {
     41
     42namespace {
     43
     44template<typename T>
     45struct NullableHashTraits : public HashTraits<T> {
     46    static const bool emptyValueIsZero = false;
     47    static T emptyValue() { return reinterpret_cast<T>(1); }
     48};
     49
     50struct ArgumentsAliasingData {
     51    InlineCallFrame* callContext;
     52    bool callContextSet;
     53    bool multipleCallContexts;
     54   
     55    bool assignedFromArguments;
     56    bool assignedFromManyThings;
     57   
     58    bool escapes;
     59   
     60    ArgumentsAliasingData()
     61        : callContext(0)
     62        , callContextSet(false)
     63        , multipleCallContexts(false)
     64        , assignedFromArguments(false)
     65        , assignedFromManyThings(false)
     66        , escapes(false)
     67    {
     68    }
     69   
     70    void mergeCallContext(InlineCallFrame* newCallContext)
     71    {
     72        if (multipleCallContexts)
     73            return;
     74       
     75        if (!callContextSet) {
     76            callContext = newCallContext;
     77            callContextSet = true;
     78            return;
     79        }
     80       
     81        if (callContext == newCallContext)
     82            return;
     83       
     84        multipleCallContexts = true;
     85    }
     86   
     87    bool callContextIsValid()
     88    {
     89        return callContextSet && !multipleCallContexts;
     90    }
     91   
     92    void mergeArgumentsAssignment()
     93    {
     94        assignedFromArguments = true;
     95    }
     96   
     97    void mergeNonArgumentsAssignment()
     98    {
     99        assignedFromManyThings = true;
     100    }
     101   
     102    bool argumentsAssignmentIsValid()
     103    {
     104        return assignedFromArguments && !assignedFromManyThings;
     105    }
     106   
     107    bool isValid()
     108    {
     109        return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
     110    }
     111};
     112
     113} // end anonymous namespace
    39114
    40115class ArgumentsSimplificationPhase : public Phase {
     
    52127        bool changed = false;
    53128       
    54         InsertionSet<NodeIndex> insertionSet;
    55        
     129        // Record which arguments are known to escape no matter what.
     130        for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;) {
     131            InlineCallFrame* inlineCallFrame = &codeBlock()->inlineCallFrames()[i];
     132            if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
     133                    m_graph.executableFor(inlineCallFrame)))
     134                m_createsArguments.add(inlineCallFrame);
     135        }
     136       
     137        // Create data for variable access datas that we will want to analyze.
     138        for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
     139            VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
     140            if (!variableAccessData->isRoot())
     141                continue;
     142            if (variableAccessData->isCaptured())
     143                continue;
     144            m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
     145        }
     146       
     147        // Figure out which variables alias the arguments and nothing else, and are
     148        // used only for GetByVal and GetArgumentsLength accesses. At the same time,
     149        // identify uses of CreateArguments that are not consistent with the arguments
     150        // being aliased only to variables that satisfy these constraints.
    56151        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
    57152            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
     
    61156                NodeIndex nodeIndex = block->at(indexInBlock);
    62157                Node& node = m_graph[nodeIndex];
     158                if (!node.shouldGenerate())
     159                    continue;
    63160                switch (node.op()) {
    64                 case GetMyArgumentsLength: {
    65                     if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
    66                             m_graph.executableFor(node.codeOrigin)))
    67                         break;
     161                case CreateArguments: {
     162                    // Ignore this op. If we see a lone CreateArguments then we want to
     163                    // completely ignore it because:
     164                    // 1) The default would be to see that the child is a GetLocal on the
     165                    //    arguments register and conclude that we have an arguments escape.
     166                    // 2) The fact that a CreateArguments exists does not mean that it
     167                    //    will continue to exist after we're done with this phase. As far
     168                    //    as this phase is concerned, a CreateArguments only "exists" if it
     169                    //    is used in a manner that necessitates its existance.
     170                    break;
     171                }
     172                   
     173                case SetLocal: {
     174                    Node& source = m_graph[node.child1()];
     175                    VariableAccessData* variableAccessData = node.variableAccessData();
     176                    if (source.op() != CreateArguments) {
     177                        // Make sure that the source of the SetLocal knows that if it's
     178                        // a variable that we think is aliased to the arguments, then it
     179                        // may escape at this point. In future, we could track transitive
     180                        // aliasing. But not yet.
     181                        observeBadArgumentsUse(node.child1());
     182                       
     183                        if (variableAccessData->isCaptured())
     184                            break;
     185                       
     186                        // Make sure that if it's a variable that we think is aliased to
     187                        // the arguments, that we know that it might actually not be.
     188                        ArgumentsAliasingData& data =
     189                            m_argumentsAliasing.find(variableAccessData)->second;
     190                        data.mergeNonArgumentsAssignment();
     191                        data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     192                        break;
     193                    }
     194                    int argumentsRegister =
     195                        m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
     196                    if (variableAccessData->local() == argumentsRegister
     197                        || variableAccessData->local() ==
     198                            unmodifiedArgumentsRegister(argumentsRegister)) {
     199                        if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame)
     200                            break;
     201                        m_createsArguments.add(source.codeOrigin.inlineCallFrame);
     202                        break;
     203                    }
     204                    if (variableAccessData->isCaptured()) {
     205                        m_createsArguments.add(source.codeOrigin.inlineCallFrame);
     206                        break;
     207                    }
     208                    ArgumentsAliasingData& data =
     209                        m_argumentsAliasing.find(variableAccessData)->second;
     210                    data.mergeArgumentsAssignment();
     211                    // This ensures that the variable's uses are in the same context as
     212                    // the arguments it is aliasing.
     213                    data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     214                    data.mergeCallContext(source.codeOrigin.inlineCallFrame);
     215                    break;
     216                }
     217                   
     218                case GetLocal:
     219                case Phi: {
     220                    VariableAccessData* variableAccessData = node.variableAccessData();
     221                    if (variableAccessData->isCaptured())
     222                        break;
     223                    ArgumentsAliasingData& data =
     224                        m_argumentsAliasing.find(variableAccessData)->second;
     225                    data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     226                    break;
     227                }
     228                   
     229                case Flush: {
     230                    VariableAccessData* variableAccessData = node.variableAccessData();
     231                    if (variableAccessData->isCaptured())
     232                        break;
     233                    ArgumentsAliasingData& data =
     234                        m_argumentsAliasing.find(variableAccessData)->second;
     235                    data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     236                   
     237                    // If a variable is used in a flush then by definition it escapes.
     238                    data.escapes = true;
     239                    break;
     240                }
     241                   
     242                case SetArgument: {
     243                    VariableAccessData* variableAccessData = node.variableAccessData();
     244                    if (variableAccessData->isCaptured())
     245                        break;
     246                    ArgumentsAliasingData& data =
     247                        m_argumentsAliasing.find(variableAccessData)->second;
     248                    data.mergeNonArgumentsAssignment();
     249                    data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     250                    break;
     251                }
     252                   
     253                case GetByVal: {
     254                    if (!node.prediction()
     255                        || !m_graph[node.child1()].prediction()
     256                        || !m_graph[node.child2()].prediction()) {
     257                        observeBadArgumentsUses(node);
     258                        break;
     259                    }
     260                   
     261                    if (!isActionableArrayPrediction(m_graph[node.child1()].prediction())
     262                        || !m_graph[node.child2()].shouldSpeculateInteger()) {
     263                        observeBadArgumentsUses(node);
     264                        break;
     265                    }
     266                   
     267                    if (m_graph[node.child1()].shouldSpeculateArguments()) {
     268                        // If arguments is used as an index, then it's an escaping use.
     269                        // That's so awful and pretty much impossible since it would
     270                        // imply that the arguments were predicted integer, but it's
     271                        // good to be defensive and thorough.
     272                        observeBadArgumentsUse(node.child2());
     273                        observeProperArgumentsUse(node, node.child1());
     274                        break;
     275                    }
     276                   
     277                    observeBadArgumentsUses(node);
     278                    break;
     279                }
     280                   
     281                case GetArgumentsLength: {
     282                    observeProperArgumentsUse(node, node.child1());
     283                    break;
     284                }
     285                   
     286                default:
     287                    observeBadArgumentsUses(node);
     288                    break;
     289                }
     290            }
     291        }
     292
     293        // Now we know which variables are aliased to arguments. But if any of them are
     294        // found to have escaped, or were otherwise invalidated, then we need to mark
     295        // the arguments as requiring creation. This is a property of SetLocals to
     296        // variables that are neither the correct arguments register nor are marked as
     297        // being arguments-aliased.
     298        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
     299            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
     300            if (!block)
     301                continue;
     302            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
     303                NodeIndex nodeIndex = block->at(indexInBlock);
     304                Node& node = m_graph[nodeIndex];
     305                if (!node.shouldGenerate())
     306                    continue;
     307                if (node.op() != SetLocal)
     308                    continue;
     309                Node& source = m_graph[node.child1()];
     310                if (source.op() != CreateArguments)
     311                    continue;
     312                VariableAccessData* variableAccessData = node.variableAccessData();
     313                if (variableAccessData->isCaptured()) {
     314                    // The captured case would have already been taken care of in the
     315                    // previous pass.
     316                    continue;
     317                }
     318               
     319                ArgumentsAliasingData& data =
     320                    m_argumentsAliasing.find(variableAccessData)->second;
     321                if (data.isValid())
     322                    continue;
     323               
     324                m_createsArguments.add(source.codeOrigin.inlineCallFrame);
     325            }
     326        }
     327       
     328#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
     329        dataLog("Arguments aliasing states:\n");
     330        for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
     331            VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
     332            if (!variableAccessData->isRoot())
     333                continue;
     334            dataLog("   r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
     335            if (variableAccessData->isCaptured())
     336                dataLog("Captured");
     337            else {
     338                ArgumentsAliasingData& data =
     339                    m_argumentsAliasing.find(variableAccessData)->second;
     340                bool first = true;
     341                if (data.callContextIsValid()) {
     342                    if (!first)
     343                        dataLog(", ");
     344                    dataLog("Have Call Context: %p", data.callContext);
     345                    first = false;
     346                    if (!m_createsArguments.contains(data.callContext))
     347                        dataLog(" (Does Not Create Arguments)");
     348                }
     349                if (data.argumentsAssignmentIsValid()) {
     350                    if (!first)
     351                        dataLog(", ");
     352                    dataLog("Arguments Assignment Is Valid");
     353                    first = false;
     354                }
     355                if (!data.escapes) {
     356                    if (!first)
     357                        dataLog(", ");
     358                    dataLog("Does Not Escape");
     359                    first = false;
     360                }
     361                if (!first)
     362                    dataLog(", ");
     363                if (data.isValid()) {
     364                    if (m_createsArguments.contains(data.callContext))
     365                        dataLog("VALID");
     366                    else
     367                        dataLog("INVALID (due to argument creation)");
     368                } else
     369                    dataLog("INVALID (due to bad variable use)");
     370            }
     371            dataLog("\n");
     372        }
     373#endif
     374       
     375        InsertionSet<NodeIndex> insertionSet;
     376       
     377        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
     378            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
     379            if (!block)
     380                continue;
     381            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
     382                NodeIndex nodeIndex = block->at(indexInBlock);
     383                Node& node = m_graph[nodeIndex];
     384                if (!node.shouldGenerate())
     385                    continue;
     386               
     387                switch (node.op()) {
     388                case SetLocal: {
     389                    Node& source = m_graph[node.child1()];
     390                    if (source.op() != CreateArguments)
     391                        break;
     392                   
     393                    VariableAccessData* variableAccessData = node.variableAccessData();
     394                   
     395                    // If this is a store into the arguments register for an InlineCallFrame*
     396                    // that does not create arguments, then kill it.
     397                    int argumentsRegister =
     398                        m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
     399                    if ((variableAccessData->local() == argumentsRegister
     400                         || variableAccessData->local()
     401                             == unmodifiedArgumentsRegister(argumentsRegister))
     402                        && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) {
     403                        // Find the Flush. It should be the next instruction.
     404                        Node& flush = m_graph[block->at(indexInBlock + 1)];
     405                        ASSERT(flush.op() == Flush);
     406                        ASSERT(flush.variableAccessData() == variableAccessData);
     407                        ASSERT(flush.child1() == nodeIndex);
     408                        // Be defensive in release mode.
     409                        if (flush.op() != Flush
     410                            || flush.variableAccessData() != variableAccessData
     411                            || flush.child1() != nodeIndex)
     412                            break;
     413                        flush.setOpAndDefaultFlags(Nop);
     414                        m_graph.clearAndDerefChild1(flush);
     415                        flush.setRefCount(0);
     416                        changed = true;
     417                        break;
     418                    }
     419                   
     420                    if (variableAccessData->isCaptured())
     421                        break;
     422                   
     423                    // If this is a store into a VariableAccessData* that is marked as
     424                    // arguments aliasing for an InlineCallFrame* that does not create
     425                    // arguments, then flag the VariableAccessData as being an
     426                    // arguments-aliased. This'll let the OSR exit machinery do the right
     427                    // things. Note also that the SetLocal should become dead as soon as
     428                    // we replace all uses of this variable with GetMyArgumentsLength and
     429                    // GetMyArgumentByVal.
     430                    if (m_argumentsAliasing.find(variableAccessData)->second.isValid()
     431                        && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) {
     432                        changed |= variableAccessData->mergeIsArgumentsAlias(true);
     433                        break;
     434                    }
     435                    break;
     436                }
     437                   
     438                case Phantom: {
     439                    // It's highly likely that we will have a Phantom referencing either
     440                    // CreateArguments, or a local op for the arguments register, or a
     441                    // local op for an arguments-aliased variable. In any of those cases,
     442                    // we should remote the phantom reference, since:
     443                    // 1) Phantoms only exist to aid OSR exit. But arguments simplification
     444                    //    has its own OSR exit story, which is to inform OSR exit to reify
     445                    //    the arguments as necessary.
     446                    // 2) The Phantom may keep the CreateArguments node alive, which is
     447                    //    precisely what we don't want.
     448                    for (unsigned i = 0; i < AdjacencyList::Size; ++i)
     449                        removeArgumentsReferencingPhantomChild(node, i);
     450                    break;
     451                }
     452                   
     453                case GetByVal: {
     454                    if (!node.prediction()
     455                        || !m_graph[node.child1()].prediction()
     456                        || !m_graph[node.child2()].prediction())
     457                        break;
     458                   
     459                    if (!isActionableArrayPrediction(m_graph[node.child1()].prediction())
     460                        || !m_graph[node.child2()].shouldSpeculateInteger())
     461                        break;
     462                   
     463                    if (m_graph[node.child1()].shouldSpeculateArguments()) {
     464                        // This can be simplified to GetMyArgumentByVal if we know that
     465                        // it satisfies either condition (1) or (2):
     466                        // 1) Its first child is a valid ArgumentsAliasingData and the
     467                        //    InlineCallFrame* is not marked as creating arguments.
     468                        // 2) Its first child is CreateArguments and its InlineCallFrame*
     469                        //    is not marked as creating arguments.
     470                       
     471                        if (!isOKToOptimize(m_graph[node.child1()]))
     472                            break;
     473                       
     474                        m_graph.deref(node.child1());
     475                        node.children.child1() = node.children.child2();
     476                        node.children.child2() = Edge();
     477                        node.setOpAndDefaultFlags(GetMyArgumentByVal);
     478                        changed = true;
     479                        --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
     480                        break;
     481                    }
     482                    break;
     483                }
     484                   
     485                case GetArgumentsLength: {
     486                    if (!isOKToOptimize(m_graph[node.child1()]))
     487                        break;
     488                   
     489                    m_graph.deref(node.child1());
     490                    node.children.child1() = Edge();
     491                    node.setOpAndDefaultFlags(GetMyArgumentsLength);
     492                    changed = true;
     493                    --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
     494                    break;
     495                }
     496                   
     497                case GetMyArgumentsLength:
     498                case GetMyArgumentsLengthSafe: {
     499                    if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
     500                        ASSERT(node.op() == GetMyArgumentsLengthSafe);
     501                        break;
     502                    }
     503                    if (node.op() == GetMyArgumentsLengthSafe) {
     504                        node.setOp(GetMyArgumentsLength);
     505                        changed = true;
     506                    }
    68507                    if (!node.codeOrigin.inlineCallFrame)
    69508                        break;
     
    83522                }
    84523                   
    85                 case GetMyArgumentByVal: {
    86                     if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
    87                             m_graph.executableFor(node.codeOrigin)))
    88                         break;
     524                case GetMyArgumentByVal:
     525                case GetMyArgumentByValSafe: {
     526                    if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
     527                        ASSERT(node.op() == GetMyArgumentByValSafe);
     528                        break;
     529                    }
     530                    if (node.op() == GetMyArgumentByValSafe) {
     531                        node.setOp(GetMyArgumentByVal);
     532                        changed = true;
     533                    }
    89534                    if (!node.codeOrigin.inlineCallFrame)
    90535                        break;
     
    139584        }
    140585       
     586        if (changed)
     587            m_graph.collectGarbage();
     588       
    141589        return changed;
     590    }
     591   
     592private:
     593    HashSet<InlineCallFrame*,
     594            DefaultHash<InlineCallFrame*>::Hash,
     595            NullableHashTraits<InlineCallFrame*> > m_createsArguments;
     596    HashMap<VariableAccessData*, ArgumentsAliasingData,
     597            DefaultHash<VariableAccessData*>::Hash,
     598            NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
     599
     600    void observeBadArgumentsUse(Edge edge)
     601    {
     602        if (!edge)
     603            return;
     604       
     605        Node& child = m_graph[edge];
     606        if (child.op() != GetLocal)
     607            return;
     608       
     609        if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)) {
     610            m_createsArguments.add(child.codeOrigin.inlineCallFrame);
     611            return;
     612        }
     613       
     614        VariableAccessData* variableAccessData = child.variableAccessData();
     615        if (variableAccessData->isCaptured())
     616            return;
     617       
     618        ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
     619        data.escapes = true;
     620    }
     621   
     622    void observeBadArgumentsUses(Node& node)
     623    {
     624        for (unsigned i = m_graph.numChildren(node); i--;)
     625            observeBadArgumentsUse(m_graph.child(node, i));
     626    }
     627   
     628    void observeProperArgumentsUse(Node& node, Edge edge)
     629    {
     630        Node& child = m_graph[edge];
     631        if (child.op() != GetLocal) {
     632            // When can this happen? At least two cases that I can think
     633            // of:
     634            //
     635            // 1) Aliased use of arguments in the same basic block,
     636            //    like:
     637            //
     638            //    var a = arguments;
     639            //    var x = arguments[i];
     640            //
     641            // 2) If we're accessing arguments we got from the heap!
     642                           
     643            if (child.op() == CreateArguments
     644                && node.codeOrigin.inlineCallFrame
     645                   != child.codeOrigin.inlineCallFrame)
     646                m_createsArguments.add(child.codeOrigin.inlineCallFrame);
     647           
     648            return;
     649        }
     650                       
     651        VariableAccessData* variableAccessData = child.variableAccessData();
     652        if (variableAccessData->isCaptured())
     653            return;
     654                       
     655        ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
     656        data.mergeCallContext(node.codeOrigin.inlineCallFrame);
     657    }
     658   
     659    bool isOKToOptimize(Node& source)
     660    {
     661        switch (source.op()) {
     662        case GetLocal: {
     663            VariableAccessData* variableAccessData = source.variableAccessData();
     664            if (variableAccessData->isCaptured())
     665                break;
     666            ArgumentsAliasingData& data =
     667                m_argumentsAliasing.find(variableAccessData)->second;
     668            if (!data.isValid())
     669                break;
     670            if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
     671                break;
     672                           
     673            return true;
     674        }
     675                           
     676        case CreateArguments: {
     677            if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
     678                break;
     679                           
     680            return true;
     681        }
     682                           
     683        default:
     684            break;
     685        }
     686       
     687        return false;
     688    }
     689   
     690    void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex)
     691    {
     692        Edge edge = node.children.child(edgeIndex);
     693        if (!edge)
     694            return;
     695       
     696        Node& child = m_graph[edge];
     697        switch (child.op()) {
     698        case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
     699        case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
     700        case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
     701            VariableAccessData* variableAccessData = child.variableAccessData();
     702            bool isDeadArgumentsRegister =
     703                variableAccessData->local() ==
     704                    m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
     705                && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
     706            bool isAliasedArgumentsRegister =
     707                !variableAccessData->isCaptured()
     708                && m_argumentsAliasing.find(variableAccessData)->second.isValid()
     709                && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
     710            if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
     711                break;
     712            m_graph.deref(edge);
     713            node.children.removeEdgeFromBag(edgeIndex);
     714            break;
     715        }
     716           
     717        case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
     718            if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame))
     719                break;
     720            m_graph.deref(edge);
     721            node.children.removeEdgeFromBag(edgeIndex);
     722            break;
     723        }
     724           
     725        default:
     726            break;
     727        }
    142728    }
    143729};
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h

    r117017 r117542  
    312312    }
    313313   
    314     int argumentsRegisterFor(const CodeOrigin& codeOrigin)
    315     {
    316         if (!codeOrigin.inlineCallFrame)
     314    int argumentsRegisterFor(InlineCallFrame* inlineCallFrame)
     315    {
     316        if (!inlineCallFrame)
    317317            return codeBlock()->argumentsRegister();
    318318       
    319319        return baselineCodeBlockForInlineCallFrame(
    320             codeOrigin.inlineCallFrame)->argumentsRegister() +
    321             codeOrigin.inlineCallFrame->stackOffset;
     320            inlineCallFrame)->argumentsRegister() + inlineCallFrame->stackOffset;
     321    }
     322   
     323    int argumentsRegisterFor(const CodeOrigin& codeOrigin)
     324    {
     325        return argumentsRegisterFor(codeOrigin.inlineCallFrame);
    322326    }
    323327   
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r117017 r117542  
    24542454        case op_create_arguments: {
    24552455            m_graph.m_hasArguments = true;
    2456             m_graph.m_executablesWhoseArgumentsEscaped.add(m_inlineStackTop->executable());
    24572456            NodeIndex createArguments = addToGraph(CreateArguments, get(currentInstruction[1].u.operand));
    24582457            set(currentInstruction[1].u.operand, createArguments);
     
    24742473        case op_get_arguments_length: {
    24752474            m_graph.m_hasArguments = true;
    2476             set(currentInstruction[1].u.operand, addToGraph(GetMyArgumentsLength));
     2475            set(currentInstruction[1].u.operand, addToGraph(GetMyArgumentsLengthSafe));
    24772476            NEXT_OPCODE(op_get_arguments_length);
    24782477        }
     
    24822481            set(currentInstruction[1].u.operand,
    24832482                addToGraph(
    2484                     GetMyArgumentByVal, OpInfo(0), OpInfo(getPrediction()),
     2483                    GetMyArgumentByValSafe, OpInfo(0), OpInfo(getPrediction()),
    24852484                    get(currentInstruction[3].u.operand)));
    24862485            NEXT_OPCODE(op_get_argument_by_val);
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp

    r117370 r117542  
    396396        if (phiNode.shouldGenerate())
    397397            m_graph.deref(myNodeIndex);
    398         for (unsigned i = edgeIndex; i < AdjacencyList::Size - 1; ++i)
    399             phiNode.children.setChild(i, phiNode.children.child(i + 1));
    400         phiNode.children.setChild(AdjacencyList::Size - 1, Edge());
     398        phiNode.children.removeEdgeFromBag(edgeIndex);
    401399    }
    402400   
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGGPRInfo.h

    r114434 r117542  
    272272    static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2
    273273    static const GPRReg argumentGPR1 = X86Registers::edx; // regT1
     274    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
     275    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
    274276    static const GPRReg returnValueGPR = X86Registers::eax; // regT0
    275277    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
     
    341343    static const GPRReg argumentGPR4 = X86Registers::r8;  // regT6
    342344    static const GPRReg argumentGPR5 = X86Registers::r9;  // regT7
     345    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
     346    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
    343347    static const GPRReg returnValueGPR = X86Registers::eax; // regT0
    344348    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
     
    411415    // any change introducing a problem here is likely to be immediately apparent!
    412416    static const GPRReg argumentGPR3 = ARMRegisters::r3; // FIXME!
     417    static const GPRReg nonArgGPR0 = X86Registers::r4; // regT3
     418    static const GPRReg nonArgGPR1 = X86Registers::r8; // regT4
    413419    static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0
    414420    static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r116912 r117542  
    403403}
    404404
     405void Graph::collectGarbage()
     406{
     407    // First reset the counts to 0 for all nodes.
     408    for (unsigned i = size(); i--;)
     409        at(i).setRefCount(0);
     410   
     411    // Now find the roots: the nodes that are must-generate. Set their ref counts to
     412    // 1 and put them on the worklist.
     413    Vector<NodeIndex, 128> worklist;
     414    for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) {
     415        BasicBlock* block = m_blocks[blockIndex].get();
     416        if (!block)
     417            continue;
     418        for (unsigned indexInBlock = block->size(); indexInBlock--;) {
     419            NodeIndex nodeIndex = block->at(indexInBlock);
     420            Node& node = at(nodeIndex);
     421            if (!(node.flags() & NodeMustGenerate))
     422                continue;
     423            node.setRefCount(1);
     424            worklist.append(nodeIndex);
     425        }
     426    }
     427   
     428    while (!worklist.isEmpty()) {
     429        NodeIndex nodeIndex = worklist.last();
     430        worklist.removeLast();
     431        Node& node = at(nodeIndex);
     432        ASSERT(node.shouldGenerate()); // It should not be on the worklist unless it's ref'ed.
     433        if (node.flags() & NodeHasVarArgs) {
     434            for (unsigned childIdx = node.firstChild();
     435                 childIdx < node.firstChild() + node.numChildren();
     436                 ++childIdx) {
     437                NodeIndex childNodeIndex = m_varArgChildren[childIdx].index();
     438                if (!at(childNodeIndex).ref())
     439                    continue;
     440                worklist.append(childNodeIndex);
     441            }
     442        } else if (node.child1()) {
     443            if (at(node.child1()).ref())
     444                worklist.append(node.child1().index());
     445            if (node.child2()) {
     446                if (at(node.child2()).ref())
     447                    worklist.append(node.child2().index());
     448                if (node.child3()) {
     449                    if (at(node.child3()).ref())
     450                        worklist.append(node.child3().index());
     451                }
     452            }
     453        }
     454    }
     455}
     456
    405457void Graph::determineReachability()
    406458{
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGGraph.h

    r117370 r117542  
    162162    }
    163163   
     164    // Call this if you've modified the reference counts of nodes that deal with
     165    // local variables. This is necessary because local variable references can form
     166    // cycles, and hence reference counting is not enough. This will reset the
     167    // reference counts according to reachability.
     168    void collectGarbage();
     169   
    164170    void convertToConstant(NodeIndex nodeIndex, unsigned constantNumber)
    165171    {
     
    305311    }
    306312   
     313    ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame)
     314    {
     315        if (!inlineCallFrame)
     316            return m_codeBlock->ownerExecutable();
     317       
     318        return inlineCallFrame->executable.get();
     319    }
     320   
    307321    ExecutableBase* executableFor(const CodeOrigin& codeOrigin)
    308322    {
     323        return executableFor(codeOrigin.inlineCallFrame);
     324    }
     325   
     326    CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
     327    {
     328        return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
     329    }
     330   
     331    int argumentsRegisterFor(const CodeOrigin& codeOrigin)
     332    {
    309333        if (!codeOrigin.inlineCallFrame)
    310             return m_codeBlock->ownerExecutable();
    311        
    312         return codeOrigin.inlineCallFrame->executable.get();
    313     }
    314    
    315     CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
    316     {
    317         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
     334            return m_codeBlock->argumentsRegister();
     335       
     336        return baselineCodeBlockForInlineCallFrame(
     337            codeOrigin.inlineCallFrame)->argumentsRegister() +
     338            codeOrigin.inlineCallFrame->stackOffset;
     339    }
     340   
     341    int uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin)
     342    {
     343        if (!codeOrigin.inlineCallFrame)
     344            return m_codeBlock->uncheckedArgumentsRegister();
     345       
     346        CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(
     347            codeOrigin.inlineCallFrame);
     348        if (!codeBlock->usesArguments())
     349            return InvalidVirtualRegister;
     350       
     351        return codeBlock->argumentsRegister() +
     352            codeOrigin.inlineCallFrame->stackOffset;
    318353    }
    319354   
     
    413448        case GetByVal:
    414449            return !byValIsPure(node);
    415         case GetMyArgumentByVal:
    416             return m_executablesWhoseArgumentsEscaped.contains(
    417                 executableFor(node.codeOrigin));
    418450        default:
    419451            ASSERT_NOT_REACHED();
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGNode.h

    r117017 r117542  
    529529        case GetByVal:
    530530        case GetMyArgumentByVal:
     531        case GetMyArgumentByValSafe:
    531532        case Call:
    532533        case Construct:
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGNodeType.h

    r117017 r117542  
    6464    macro(GetLocalUnlinked, NodeResultJS) \
    6565    \
    66     /* Marker for arguments being set. */\
     66    /* Marker for an argument being set at the prologue of a function. */\
    6767    macro(SetArgument, 0) \
    6868    \
     
    199199    macro(CreateArguments, NodeResultJS) \
    200200    macro(TearOffArguments, NodeMustGenerate) \
    201     macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
    202     macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
     201    macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate) \
     202    macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \
     203    macro(GetMyArgumentsLengthSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
     204    macro(GetMyArgumentByValSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
    203205    macro(CheckArgumentsNotCreated, NodeMustGenerate) \
    204206    \
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp

    r115694 r117542  
    7373
    7474    {
    75         AssemblyHelpers jit(globalData, codeBlock);
     75        CCallHelpers jit(globalData, codeBlock);
    7676        OSRExitCompiler exitCompiler(jit);
    7777       
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h

    r113552 r117542  
    3232
    3333#include "DFGAssemblyHelpers.h"
     34#include "DFGCCallHelpers.h"
    3435#include "DFGOSRExit.h"
    3536#include "DFGOperations.h"
     
    4344class OSRExitCompiler {
    4445public:
    45     OSRExitCompiler(AssemblyHelpers& jit)
     46    OSRExitCompiler(CCallHelpers& jit)
    4647        : m_jit(jit)
    4748    {
     
    7374    void handleExitCounts(const OSRExit&);
    7475   
    75     AssemblyHelpers& m_jit;
     76    CCallHelpers& m_jit;
    7677    Vector<unsigned> m_poisonScratchIndices;
    7778};
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp

    r113552 r117542  
    131131    bool haveConstants = false;
    132132    bool haveUndefined = false;
     133    bool haveArguments = false;
    133134   
    134135    for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
     
    192193            if (recovery.constant().isUndefined())
    193194                haveUndefined = true;
     195            break;
     196           
     197        case ArgumentsThatWereNotCreated:
     198            haveArguments = true;
    194199            break;
    195200           
     
    527532    }
    528533   
    529     // 11) Adjust the old JIT's execute counter. Since we are exiting OSR, we know
     534    // 11) Create arguments if necessary and place them into the appropriate aliased
     535    //     registers.
     536   
     537    if (haveArguments) {
     538        for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
     539            const ValueRecovery& recovery = exit.valueRecovery(index);
     540            if (recovery.technique() != ArgumentsThatWereNotCreated)
     541                continue;
     542            int operand = exit.operandForIndex(index);
     543            // Find the right inline call frame.
     544            InlineCallFrame* inlineCallFrame = 0;
     545            for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
     546                 current;
     547                 current = current->caller.inlineCallFrame) {
     548                if (current->stackOffset <= operand) {
     549                    inlineCallFrame = current;
     550                    break;
     551                }
     552            }
     553            int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame);
     554           
     555            m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0);
     556            AssemblyHelpers::Jump haveArguments = m_jit.branch32(
     557                AssemblyHelpers::NotEqual,
     558                AssemblyHelpers::tagFor(argumentsRegister),
     559                AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag));
     560           
     561            if (inlineCallFrame) {
     562                m_jit.setupArgumentsWithExecState(
     563                    AssemblyHelpers::TrustedImmPtr(inlineCallFrame));
     564                m_jit.move(
     565                    AssemblyHelpers::TrustedImmPtr(
     566                        bitwise_cast<void*>(operationCreateInlinedArguments)),
     567                    GPRInfo::nonArgGPR0);
     568            } else {
     569                m_jit.setupArgumentsExecState();
     570                m_jit.move(
     571                    AssemblyHelpers::TrustedImmPtr(
     572                        bitwise_cast<void*>(operationCreateArguments)),
     573                    GPRInfo::nonArgGPR0);
     574            }
     575            m_jit.call(GPRInfo::nonArgGPR0);
     576            m_jit.store32(
     577                AssemblyHelpers::TrustedImm32(JSValue::CellTag),
     578                AssemblyHelpers::tagFor(argumentsRegister));
     579            m_jit.store32(
     580                GPRInfo::returnValueGPR,
     581                AssemblyHelpers::payloadFor(argumentsRegister));
     582            m_jit.store32(
     583                AssemblyHelpers::TrustedImm32(JSValue::CellTag),
     584                AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister)));
     585            m_jit.store32(
     586                GPRInfo::returnValueGPR,
     587                AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister)));
     588            m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
     589           
     590            haveArguments.link(&m_jit);
     591            m_jit.store32(
     592                AssemblyHelpers::TrustedImm32(JSValue::CellTag),
     593                AssemblyHelpers::tagFor(operand));
     594            m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand));
     595        }
     596    }
     597   
     598    // 12) Adjust the old JIT's execute counter. Since we are exiting OSR, we know
    530599    //     that all new calls into this code will go to the new JIT, so the execute
    531600    //     counter only affects call frames that performed OSR exit and call frames
     
    565634    handleExitCounts(exit);
    566635   
    567     // 12) Load the result of the last bytecode operation into regT0.
     636    // 13) Load the result of the last bytecode operation into regT0.
    568637   
    569638    if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) {
     
    572641    }
    573642   
    574     // 13) Fix call frame (s).
     643    // 14) Fix call frame (s).
    575644   
    576645    ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT);
     
    611680        m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
    612681
    613     // 14) Jump into the corresponding baseline JIT code.
     682    // 15) Jump into the corresponding baseline JIT code.
    614683   
    615684    CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin);
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp

    r113552 r117542  
    128128    bool haveUndefined = false;
    129129    bool haveUInt32s = false;
     130    bool haveArguments = false;
    130131   
    131132    for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
     
    183184            if (recovery.constant().isUndefined())
    184185                haveUndefined = true;
     186            break;
     187           
     188        case ArgumentsThatWereNotCreated:
     189            haveArguments = true;
    185190            break;
    186191           
     
    506511    }
    507512   
    508     // 13) Adjust the old JIT's execute counter. Since we are exiting OSR, we know
     513    // 13) Create arguments if necessary and place them into the appropriate aliased
     514    //     registers.
     515   
     516    if (haveArguments) {
     517        for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
     518            const ValueRecovery& recovery = exit.valueRecovery(index);
     519            if (recovery.technique() != ArgumentsThatWereNotCreated)
     520                continue;
     521            int operand = exit.operandForIndex(index);
     522            // Find the right inline call frame.
     523            InlineCallFrame* inlineCallFrame = 0;
     524            for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame;
     525                 current;
     526                 current = current->caller.inlineCallFrame) {
     527                if (current->stackOffset <= operand) {
     528                    inlineCallFrame = current;
     529                    break;
     530                }
     531            }
     532            int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame);
     533           
     534            m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0);
     535            AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr(
     536                AssemblyHelpers::NonZero, GPRInfo::regT0);
     537           
     538            if (inlineCallFrame) {
     539                m_jit.setupArgumentsWithExecState(
     540                    AssemblyHelpers::TrustedImmPtr(inlineCallFrame));
     541                m_jit.move(
     542                    AssemblyHelpers::TrustedImmPtr(
     543                        bitwise_cast<void*>(operationCreateInlinedArguments)),
     544                    GPRInfo::nonArgGPR0);
     545            } else {
     546                m_jit.setupArgumentsExecState();
     547                m_jit.move(
     548                    AssemblyHelpers::TrustedImmPtr(
     549                        bitwise_cast<void*>(operationCreateArguments)),
     550                    GPRInfo::nonArgGPR0);
     551            }
     552            m_jit.call(GPRInfo::nonArgGPR0);
     553            m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister));
     554            m_jit.storePtr(
     555                GPRInfo::returnValueGPR,
     556                AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister)));
     557            m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms.
     558           
     559            haveArguments.link(&m_jit);
     560            m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
     561        }
     562    }
     563   
     564    // 14) Adjust the old JIT's execute counter. Since we are exiting OSR, we know
    509565    //     that all new calls into this code will go to the new JIT, so the execute
    510566    //     counter only affects call frames that performed OSR exit and call frames
     
    544600    handleExitCounts(exit);
    545601   
    546     // 14) Load the result of the last bytecode operation into regT0.
     602    // 15) Load the result of the last bytecode operation into regT0.
    547603   
    548604    if (exit.m_lastSetOperand != std::numeric_limits<int>::max())
    549605        m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
    550606   
    551     // 15) Fix call frame(s).
     607    // 16) Fix call frame(s).
    552608   
    553609    ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT);
     
    585641        m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
    586642   
    587     // 16) Jump into the corresponding baseline JIT code.
     643    // 17) Jump into the corresponding baseline JIT code.
    588644   
    589645    CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin);
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r116838 r117542  
    10251025JSCell* DFG_OPERATION operationCreateArguments(ExecState* exec)
    10261026{
    1027     return Arguments::create(exec->globalData(), exec);
     1027    // NB: This needs to be exceedingly careful with top call frame tracking, since it
     1028    // may be called from OSR exit, while the state of the call stack is bizarre.
     1029    Arguments* result = Arguments::create(exec->globalData(), exec);
     1030    ASSERT(!exec->globalData().exception);
     1031    return result;
    10281032}
    10291033
     
    10311035    ExecState* exec, InlineCallFrame* inlineCallFrame)
    10321036{
    1033     return Arguments::create(exec->globalData(), exec, inlineCallFrame);
     1037    // NB: This needs to be exceedingly careful with top call frame tracking, since it
     1038    // may be called from OSR exit, while the state of the call stack is bizarre.
     1039    Arguments* result = Arguments::create(exec->globalData(), exec, inlineCallFrame);
     1040    ASSERT(!exec->globalData().exception);
     1041    return result;
    10341042}
    10351043
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r117017 r117542  
    438438        }
    439439           
    440         case GetMyArgumentByVal: {
     440        case GetMyArgumentByValSafe: {
    441441            changed |= mergePrediction(node.getHeapPrediction());
    442442            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
     
    444444        }
    445445           
    446         case GetMyArgumentsLength: {
     446        case GetMyArgumentsLengthSafe: {
    447447            changed |= setPrediction(PredictInt32);
    448448            break;
     
    617617        case GetStringLength:
    618618        case Int32ToDouble:
    619         case GetLocalUnlinked: {
     619        case GetLocalUnlinked:
     620        case GetMyArgumentsLength:
     621        case GetMyArgumentByVal: {
    620622            // This node should never be visible at this stage of compilation. It is
    621623            // inserted by fixup(), which follows this phase.
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r116555 r117542  
    801801    case DoubleInRegisterFile:
    802802        fprintf(out, "Double");
     803        break;
     804    case ArgumentsSource:
     805        fprintf(out, "Arguments");
    803806        break;
    804807    case HaveNode:
     
    987990        else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
    988991            m_variables[i] = ValueSource(DoubleInRegisterFile);
     992        else if (at(nodeIndex).variableAccessData()->isArgumentsAlias())
     993            m_variables[i] = ValueSource(ArgumentsSource);
    989994        else
    990995            m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
     
    13461351    case DoubleInRegisterFile:
    13471352        return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble();
     1353       
     1354    case ArgumentsSource:
     1355        return ValueRecovery::argumentsThatWereNotCreated();
    13481356
    13491357    case HaveNode: {
    13501358        if (isConstant(valueSource.nodeIndex()))
    13511359            return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex()));
    1352    
     1360       
    13531361        Node* nodePtr = &at(valueSource.nodeIndex());
    13541362        if (!nodePtr->shouldGenerate()) {
     1363            if (nodePtr->op() == CreateArguments)
     1364                return ValueRecovery::argumentsThatWereNotCreated();
    13551365            // It's legitimately dead. As in, nobody will ever use this node, or operand,
    13561366            // ever. Set it to Undefined to make the GC happy after the OSR.
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r116838 r117542  
    5757    BooleanInRegisterFile,
    5858    DoubleInRegisterFile,
     59    ArgumentsSource,
    5960    HaveNode
    6061};
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r117017 r117542  
    39103910       
    39113911    case GetMyArgumentsLength: {
    3912         if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains(
    3913                 m_jit.graph().executableFor(node.codeOrigin))) {
    3914             GPRTemporary result(this);
    3915             GPRReg resultGPR = result.gpr();
    3916            
    3917             speculationCheck(
    3918                 ArgumentsEscaped, JSValueRegs(), NoNode,
    3919                 m_jit.branch32(
    3920                     JITCompiler::NotEqual,
    3921                     JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
    3922                     TrustedImm32(JSValue::EmptyValueTag)));
    3923            
    3924             ASSERT(!node.codeOrigin.inlineCallFrame);
    3925             m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
    3926             m_jit.sub32(TrustedImm32(1), resultGPR);
    3927             integerResult(resultGPR, m_compileIndex);
    3928             break;
    3929         }
    3930        
     3912        GPRTemporary result(this);
     3913        GPRReg resultGPR = result.gpr();
     3914       
     3915        speculationCheck(
     3916            ArgumentsEscaped, JSValueRegs(), NoNode,
     3917            m_jit.branch32(
     3918                JITCompiler::NotEqual,
     3919                JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
     3920                TrustedImm32(JSValue::EmptyValueTag)));
     3921       
     3922        ASSERT(!node.codeOrigin.inlineCallFrame);
     3923        m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
     3924        m_jit.sub32(TrustedImm32(1), resultGPR);
     3925        integerResult(resultGPR, m_compileIndex);
     3926        break;
     3927    }
     3928       
     3929    case GetMyArgumentsLengthSafe: {
    39313930        GPRTemporary resultPayload(this);
    39323931        GPRTemporary resultTag(this);
     
    39713970        GPRReg resultTagGPR = resultTag.gpr();
    39723971       
    3973         if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains(
    3974                 m_jit.graph().executableFor(node.codeOrigin))) {
    3975             speculationCheck(
    3976                 ArgumentsEscaped, JSValueRegs(), NoNode,
    3977                 m_jit.branch32(
    3978                     JITCompiler::NotEqual,
    3979                     JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
    3980                     TrustedImm32(JSValue::EmptyValueTag)));
    3981            
    3982             m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
    3983            
    3984             if (node.codeOrigin.inlineCallFrame) {
    3985                 speculationCheck(
    3986                     Uncountable, JSValueRegs(), NoNode,
    3987                     m_jit.branch32(
    3988                         JITCompiler::AboveOrEqual,
    3989                         resultPayloadGPR,
    3990                         Imm32(node.codeOrigin.inlineCallFrame->arguments.size())));
    3991             } else {
    3992                 speculationCheck(
    3993                     Uncountable, JSValueRegs(), NoNode,
    3994                     m_jit.branch32(
    3995                         JITCompiler::AboveOrEqual,
    3996                         resultPayloadGPR,
    3997                         JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
    3998             }
    3999        
    4000             m_jit.neg32(resultPayloadGPR);
    4001        
    4002             size_t baseOffset =
    4003                 ((node.codeOrigin.inlineCallFrame
    4004                   ? node.codeOrigin.inlineCallFrame->stackOffset
    4005                   : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
    4006             m_jit.load32(
    4007                 JITCompiler::BaseIndex(
    4008                     GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
    4009                     baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
    4010                 resultTagGPR);
    4011             m_jit.load32(
    4012                 JITCompiler::BaseIndex(
    4013                     GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
    4014                     baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
    4015                 resultPayloadGPR);
    4016            
    4017             jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
    4018             break;
    4019         }
    4020        
    4021         JITCompiler::JumpList slowPath;
    4022         slowPath.append(
     3972        speculationCheck(
     3973            ArgumentsEscaped, JSValueRegs(), NoNode,
    40233974            m_jit.branch32(
    40243975                JITCompiler::NotEqual,
    40253976                JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
    40263977                TrustedImm32(JSValue::EmptyValueTag)));
    4027        
     3978           
    40283979        m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
     3980           
    40293981        if (node.codeOrigin.inlineCallFrame) {
    4030             slowPath.append(
     3982            speculationCheck(
     3983                Uncountable, JSValueRegs(), NoNode,
    40313984                m_jit.branch32(
    40323985                    JITCompiler::AboveOrEqual,
     
    40343987                    Imm32(node.codeOrigin.inlineCallFrame->arguments.size())));
    40353988        } else {
    4036             slowPath.append(
     3989            speculationCheck(
     3990                Uncountable, JSValueRegs(), NoNode,
    40373991                m_jit.branch32(
    40383992                    JITCompiler::AboveOrEqual,
     
    40574011                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
    40584012            resultPayloadGPR);
     4013           
     4014        jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
     4015        break;
     4016    }
     4017    case GetMyArgumentByValSafe: {
     4018        SpeculateStrictInt32Operand index(this, node.child1());
     4019        GPRTemporary resultPayload(this);
     4020        GPRTemporary resultTag(this);
     4021        GPRReg indexGPR = index.gpr();
     4022        GPRReg resultPayloadGPR = resultPayload.gpr();
     4023        GPRReg resultTagGPR = resultTag.gpr();
     4024       
     4025        JITCompiler::JumpList slowPath;
     4026        slowPath.append(
     4027            m_jit.branch32(
     4028                JITCompiler::NotEqual,
     4029                JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
     4030                TrustedImm32(JSValue::EmptyValueTag)));
     4031       
     4032        m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
     4033        if (node.codeOrigin.inlineCallFrame) {
     4034            slowPath.append(
     4035                m_jit.branch32(
     4036                    JITCompiler::AboveOrEqual,
     4037                    resultPayloadGPR,
     4038                    Imm32(node.codeOrigin.inlineCallFrame->arguments.size())));
     4039        } else {
     4040            slowPath.append(
     4041                m_jit.branch32(
     4042                    JITCompiler::AboveOrEqual,
     4043                    resultPayloadGPR,
     4044                    JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
     4045        }
     4046       
     4047        m_jit.neg32(resultPayloadGPR);
     4048       
     4049        size_t baseOffset =
     4050            ((node.codeOrigin.inlineCallFrame
     4051              ? node.codeOrigin.inlineCallFrame->stackOffset
     4052              : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
     4053        m_jit.load32(
     4054            JITCompiler::BaseIndex(
     4055                GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
     4056                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
     4057            resultTagGPR);
     4058        m_jit.load32(
     4059            JITCompiler::BaseIndex(
     4060                GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
     4061                baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
     4062            resultPayloadGPR);
    40594063       
    40604064        addSlowPathGenerator(
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r117017 r117542  
    38913891        GPRReg resultGPR = result.gpr();
    38923892       
    3893         if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains(
    3894                 m_jit.graph().executableFor(node.codeOrigin))) {
    3895             speculationCheck(
    3896                 ArgumentsEscaped, JSValueRegs(), NoNode,
    3897                 m_jit.branchTestPtr(
    3898                     JITCompiler::NonZero,
    3899                     JITCompiler::addressFor(
    3900                         m_jit.argumentsRegisterFor(node.codeOrigin))));
    3901            
    3902             ASSERT(!node.codeOrigin.inlineCallFrame);
    3903             m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
    3904             m_jit.sub32(TrustedImm32(1), resultGPR);
    3905             integerResult(resultGPR, m_compileIndex);
    3906             break;
    3907         }
     3893        speculationCheck(
     3894            ArgumentsEscaped, JSValueRegs(), NoNode,
     3895            m_jit.branchTestPtr(
     3896                JITCompiler::NonZero,
     3897                JITCompiler::addressFor(
     3898                    m_jit.argumentsRegisterFor(node.codeOrigin))));
     3899       
     3900        ASSERT(!node.codeOrigin.inlineCallFrame);
     3901        m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
     3902        m_jit.sub32(TrustedImm32(1), resultGPR);
     3903        integerResult(resultGPR, m_compileIndex);
     3904        break;
     3905    }
     3906       
     3907    case GetMyArgumentsLengthSafe: {
     3908        GPRTemporary result(this);
     3909        GPRReg resultGPR = result.gpr();
    39083910       
    39093911        JITCompiler::Jump created = m_jit.branchTestPtr(
     
    39443946        GPRReg resultGPR = result.gpr();
    39453947       
    3946         if (!m_jit.graph().m_executablesWhoseArgumentsEscaped.contains(
    3947                 m_jit.graph().executableFor(node.codeOrigin))) {
     3948        speculationCheck(
     3949            ArgumentsEscaped, JSValueRegs(), NoNode,
     3950            m_jit.branchTestPtr(
     3951                JITCompiler::NonZero,
     3952                JITCompiler::addressFor(
     3953                    m_jit.argumentsRegisterFor(node.codeOrigin))));
     3954
     3955        m_jit.add32(TrustedImm32(1), indexGPR, resultGPR);
     3956        if (node.codeOrigin.inlineCallFrame) {
    39483957            speculationCheck(
    3949                 ArgumentsEscaped, JSValueRegs(), NoNode,
    3950                 m_jit.branchTestPtr(
    3951                     JITCompiler::NonZero,
    3952                     JITCompiler::addressFor(
    3953                         m_jit.argumentsRegisterFor(node.codeOrigin))));
    3954 
    3955             m_jit.add32(TrustedImm32(1), indexGPR, resultGPR);
    3956             if (node.codeOrigin.inlineCallFrame) {
    3957                 speculationCheck(
    3958                     Uncountable, JSValueRegs(), NoNode,
    3959                     m_jit.branch32(
    3960                         JITCompiler::AboveOrEqual,
    3961                         resultGPR,
    3962                         Imm32(node.codeOrigin.inlineCallFrame->arguments.size())));
    3963             } else {
    3964                 speculationCheck(
    3965                     Uncountable, JSValueRegs(), NoNode,
    3966                     m_jit.branch32(
    3967                         JITCompiler::AboveOrEqual,
    3968                         resultGPR,
    3969                         JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
    3970             }
    3971            
    3972             m_jit.neg32(resultGPR);
    3973             m_jit.signExtend32ToPtr(resultGPR, resultGPR);
    3974            
    3975             m_jit.loadPtr(
    3976                 JITCompiler::BaseIndex(
    3977                     GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
    3978                     ((node.codeOrigin.inlineCallFrame
    3979                       ? node.codeOrigin.inlineCallFrame->stackOffset
    3980                       : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
    3981                 resultGPR);
    3982 
    3983             jsValueResult(resultGPR, m_compileIndex);
    3984             break;
    3985         }
     3958                Uncountable, JSValueRegs(), NoNode,
     3959                m_jit.branch32(
     3960                    JITCompiler::AboveOrEqual,
     3961                    resultGPR,
     3962                    Imm32(node.codeOrigin.inlineCallFrame->arguments.size())));
     3963        } else {
     3964            speculationCheck(
     3965                Uncountable, JSValueRegs(), NoNode,
     3966                m_jit.branch32(
     3967                    JITCompiler::AboveOrEqual,
     3968                    resultGPR,
     3969                    JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
     3970        }
     3971           
     3972        m_jit.neg32(resultGPR);
     3973        m_jit.signExtend32ToPtr(resultGPR, resultGPR);
     3974           
     3975        m_jit.loadPtr(
     3976            JITCompiler::BaseIndex(
     3977                GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
     3978                ((node.codeOrigin.inlineCallFrame
     3979                  ? node.codeOrigin.inlineCallFrame->stackOffset
     3980                  : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
     3981            resultGPR);
     3982
     3983        jsValueResult(resultGPR, m_compileIndex);
     3984        break;
     3985    }
     3986       
     3987    case GetMyArgumentByValSafe: {
     3988        SpeculateStrictInt32Operand index(this, node.child1());
     3989        GPRTemporary result(this);
     3990        GPRReg indexGPR = index.gpr();
     3991        GPRReg resultGPR = result.gpr();
    39863992       
    39873993        JITCompiler::JumpList slowPath;
  • branches/dfgopt/Source/JavaScriptCore/dfg/DFGVariableAccessData.h

    r116555 r117542  
    4848        , m_flags(0)
    4949        , m_doubleFormatState(EmptyDoubleFormatState)
     50        , m_isCaptured(false)
     51        , m_isArgumentsAlias(false)
    5052    {
    5153        clearVotes();
     
    5961        , m_doubleFormatState(EmptyDoubleFormatState)
    6062        , m_isCaptured(isCaptured)
     63        , m_isArgumentsAlias(false)
    6164    {
    6265        clearVotes();
     
    8689    {
    8790        return m_isCaptured;
     91    }
     92   
     93    bool mergeIsArgumentsAlias(bool isArgumentsAlias)
     94    {
     95        bool newIsArgumentsAlias = m_isArgumentsAlias | isArgumentsAlias;
     96        if (newIsArgumentsAlias == m_isArgumentsAlias)
     97            return false;
     98        m_isArgumentsAlias = newIsArgumentsAlias;
     99        return true;
     100    }
     101   
     102    bool isArgumentsAlias()
     103    {
     104        return m_isArgumentsAlias;
    88105    }
    89106   
     
    238255   
    239256    bool m_isCaptured;
     257    bool m_isArgumentsAlias;
    240258};
    241259
  • branches/dfgopt/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r116467 r117542  
    15671567    stubCall.addArgument(arguments, regT2);
    15681568    stubCall.addArgument(property, regT2);
    1569     stubCall.call(dst);
     1569    stubCall.callWithValueProfiling(dst);
    15701570}
    15711571
Note: See TracChangeset for help on using the changeset viewer.