Ignore:
Timestamp:
Dec 11, 2011, 4:35:51 PM (13 years ago)
Author:
[email protected]
Message:

v8 benchmark takes 12-13 million function call slow paths due to extra arguments
https://bugs.webkit.org/show_bug.cgi?id=74244

Reviewed by Filip Pizlo.

.arguments function of order the Reversed

10% speedup on v8-raytrace, 1.7% speedup on v8 overall, neutral on Kraken
and SunSpider.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::valueProfileForArgument): Clarified that the interface
to this function is an argument number.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitConstruct):
(JSC::BytecodeGenerator::isArgumentNumber): Switched to using CallFrame
helper functions for computing offsets for arguments, rather than doing
the math by hand.

Switched to iterating argument offsets backwards (--) instead of forwards (++).

  • bytecompiler/BytecodeGenerator.h:

(JSC::CallArguments::thisRegister):
(JSC::CallArguments::argumentRegister):
(JSC::CallArguments::registerOffset): Updated for arguments being reversed.

  • bytecompiler/NodesCodegen.cpp: Allocate arguments in reverse order.
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::flush):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::processPhiStack): Use abstract argument indices
that just-in-time convert to bytecode operands (i.e., indexes in the register
file) through helper functions. This means only one piece of code needs
to know how arguments are laid out in the register file.

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump): Ditto.

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::valueProfileFor): Ditto.

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::compileFunction): The whole point of this patch:
Treat too many arguments as an arity match.

  • dfg/DFGOSRExit.h:

(JSC::DFG::OSRExit::variableForIndex):
(JSC::DFG::OSRExit::operandForIndex): Use helper functions, as above.

  • dfg/DFGOperands.h:

(JSC::DFG::operandToArgument):
(JSC::DFG::argumentToOperand): These are now the only two lines of code in
the DFG compiler that know how arguments are laid out in memory.

(JSC::DFG::Operands::operand):
(JSC::DFG::Operands::setOperand): Use helper functions, as above.

  • dfg/DFGOperations.cpp: The whole point of this patch:

Treat too many arguments as an arity match.

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::emitCall): Use helper functions, as above.

Also, don't tag the caller frame slot as a cell, because it's not a cell.

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::emitCall): Use helper functions, as above.

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compile): Use helper functions, as above.

(JSC::DFG::SpeculativeJIT::checkArgumentTypes): Use already-computed
argument virtual register instead of recomputing by hand.

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callFrameSlot):
(JSC::DFG::SpeculativeJIT::argumentSlot):
(JSC::DFG::SpeculativeJIT::callFrameTagSlot):
(JSC::DFG::SpeculativeJIT::callFramePayloadSlot):
(JSC::DFG::SpeculativeJIT::argumentTagSlot):
(JSC::DFG::SpeculativeJIT::argumentPayloadSlot): Added a few helper
functions for dealing with callee arguments specifically. These still
build on top of our other helper functions, and have no direct knowledge
of how arguments are laid out in the register file.

(JSC::DFG::SpeculativeJIT::resetCallArguments):
(JSC::DFG::SpeculativeJIT::addCallArgument): Renamed argumentIndex to
argumentOffset to match CallFrame naming.

(JSC::DFG::SpeculativeJIT::valueSourceReferenceForOperand): Use helper
functions, as above.

  • interpreter/CallFrame.h:

(JSC::ExecState::argumentOffset):
(JSC::ExecState::argumentOffsetIncludingThis):
(JSC::ExecState::argument):
(JSC::ExecState::setArgument):
(JSC::ExecState::thisArgumentOffset):
(JSC::ExecState::thisValue):
(JSC::ExecState::setThisValue):
(JSC::ExecState::offsetFor):
(JSC::ExecState::hostThisRegister):
(JSC::ExecState::hostThisValue): Added a bunch of helper functions for
computing where an argument is in the register file. Anything in the
runtime that needs to access arguments should use these helpers.

  • interpreter/CallFrameClosure.h:

(JSC::CallFrameClosure::setThis):
(JSC::CallFrameClosure::setArgument):
(JSC::CallFrameClosure::resetCallFrame): This stuff is a lot simpler, now
that too many arguments counts as an arity match and doesn't require
preserving two copies of our arguments.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::slideRegisterWindowForCall): Only need to do something
special if the caller provided too few arguments.

Key simplification: We never need to maintain two copies of our arguments
anymore.

(JSC::eval):
(JSC::loadVarargs): Use helper functions.

(JSC::Interpreter::unwindCallFrame): Updated for new interface.

(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall): Seriously, though: use helper
functions.

(JSC::Interpreter::privateExecute): No need to check for stack overflow
when calling host functions because they have zero callee registers.

(JSC::Interpreter::retrieveArguments): Explicitly tear off the arguments
object, since there's no special constructor for this anymore.

  • interpreter/Interpreter.h: Reduced the C++ re-entry depth because some

workers tests were hitting stack overflow in some of my testing. We should
make this test more exact in future.

  • interpreter/RegisterFile.h: Death to all runtime knowledge of argument

location that does not belong to the CallFrame class!

  • jit/JIT.cpp:

(JSC::JIT::privateCompile): I am a broken record and I use helper functions.

Also, the whole point of this patch: Treat too many arguments as an arity match.

  • jit/JITCall32_64.cpp:

(JSC::JIT::compileLoadVarargs):

  • jit/JITCall.cpp:

(JSC::JIT::compileLoadVarargs): Updated the argument copying math to use
helper functions, for backwards-correctness. Removed the condition
pertaining to declared argument count because, now that arguments are
always in just one place, this optimization is valid for all functions.
Standardized the if predicate for each line of the optimization. This might
fix a bug, but I couldn't get the bug to crash in practice.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_create_arguments):
(JSC::JIT::emit_op_get_argument_by_val):
(JSC::JIT::emitSlow_op_get_argument_by_val):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_create_arguments):
(JSC::JIT::emit_op_get_argument_by_val):
(JSC::JIT::emitSlow_op_get_argument_by_val): Removed cti_op_create_arguments_no_params
optimization because it's no longer an optimization, now that arguments
are always contiguous in a known location.

Updated argument access opcode math for backwards-correctness.

  • jit/JITStubs.cpp:

(JSC::arityCheckFor): Updated just like slideRegisterWindowForCall. This
function is slightly different because it copies the call frame in
addition to the arguments. (In the Interpreter, the call frame is not
set up by this point.)

(JSC::lazyLinkFor): The whole point of this patch: Treat too many
arguments as an arity match.

(JSC::DEFINE_STUB_FUNCTION): Updated for new iterface to tearOff().

  • jit/JITStubs.h:
  • jit/SpecializedThunkJIT.h:

(JSC::SpecializedThunkJIT::loadDoubleArgument):
(JSC::SpecializedThunkJIT::loadCellArgument):
(JSC::SpecializedThunkJIT::loadInt32Argument): Use helper functions! They
build strong bones and teeth!

  • runtime/ArgList.cpp:

(JSC::ArgList::getSlice):
(JSC::MarkedArgumentBuffer::slowAppend):

  • runtime/ArgList.h:

(JSC::MarkedArgumentBuffer::MarkedArgumentBuffer):
(JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer):
(JSC::MarkedArgumentBuffer::at):
(JSC::MarkedArgumentBuffer::clear):
(JSC::MarkedArgumentBuffer::append):
(JSC::MarkedArgumentBuffer::removeLast):
(JSC::MarkedArgumentBuffer::last):
(JSC::ArgList::ArgList):
(JSC::ArgList::at): Updated for backwards-correctness. WTF::Vector doesn't
play nice with backwards-ness, so I changed to using manual allocation.

Fixed a FIXME about not all values being marked in the case of out-of-line
arguments. I had to rewrite the loop anyway, and I didn't feel like
maintaining fidelity to its old bugs.

  • runtime/Arguments.cpp:

(JSC::Arguments::visitChildren):
(JSC::Arguments::copyToArguments):
(JSC::Arguments::fillArgList):
(JSC::Arguments::getOwnPropertySlotByIndex):
(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::getOwnPropertyDescriptor):
(JSC::Arguments::putByIndex):
(JSC::Arguments::put):
(JSC::Arguments::tearOff):

  • runtime/Arguments.h:

(JSC::Arguments::create):
(JSC::Arguments::Arguments):
(JSC::Arguments::argument):
(JSC::Arguments::finishCreation): Secondary benefit of this patch: deleted
lots of tricky code designed to maintain two different copies of function
arguments. Now that arguments are always contiguous in one place in memory,
this complexity can go away.

Reduced down to one create function for the Arguments class, from three.

Moved tearOff() into an out-of-line function because it's huge.

Moved logic about whether to tear off eagerly into the Arguments class,
so we didn't have to duplicate it elsewhere.

  • runtime/JSActivation.cpp:

(JSC::JSActivation::JSActivation):
(JSC::JSActivation::visitChildren): Renamed m_numParametersMinusThis to
m_numCapturedArgs because if the value really were m_numParametersMinusThis
we would be marking too much. (We shouldn't mark 'this' because it can't
be captured.) Also, use helper functions.

  • runtime/JSActivation.h:

(JSC::JSActivation::tearOff): Use helper functions.

  • runtime/JSArray.cpp:

(JSC::JSArray::copyToArguments):

  • runtime/JSArray.h: Use helper functions, as above.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r102489 r102545  
    7777
    7878    // Helper for min and max.
    79     bool handleMinMax(bool usesResult, int resultOperand, NodeType op, int firstArg, int lastArg);
     79    bool handleMinMax(bool usesResult, int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis);
    8080   
    8181    // Handle calls. This resolves issues surrounding inlining and intrinsics.
    8282    void handleCall(Interpreter*, Instruction* currentInstruction, NodeType op, CodeSpecializationKind);
    8383    // Handle inlining. Return true if it succeeded, false if we need to plant a call.
    84     bool handleInlining(bool usesResult, int callTarget, NodeIndex callTargetNodeIndex, int resultOperand, bool certainAboutExpectedFunction, JSFunction*, int firstArg, int lastArg, unsigned nextOffset, CodeSpecializationKind);
     84    bool handleInlining(bool usesResult, int callTarget, NodeIndex callTargetNodeIndex, int resultOperand, bool certainAboutExpectedFunction, JSFunction*, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
    8585    // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
    86     bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int firstArg, int lastArg, PredictedType prediction);
     86    bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction);
    8787    // Prepare to parse a block.
    8888    void prepareToParseBlock();
     
    200200    NodeIndex getArgument(unsigned operand)
    201201    {
    202         unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
     202        unsigned argument = operandToArgument(operand);
    203203        ASSERT(argument < m_numArguments);
    204204
     
    249249    void setArgument(int operand, NodeIndex value)
    250250    {
    251         unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
     251        unsigned argument = operandToArgument(operand);
    252252        ASSERT(argument < m_numArguments);
    253253
     
    267267        int index;
    268268        if (operandIsArgument(operand)) {
    269             index = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
     269            index = operandToArgument(operand);
    270270            nodeIndex = m_currentBlock->variablesAtTail.argument(index);
    271271        } else {
     
    579579        addVarArgChild(get(currentInstruction[1].u.operand));
    580580        int argCount = currentInstruction[2].u.operand;
     581        if (RegisterFile::CallFrameHeaderSize + (unsigned)argCount > m_parameterSlots)
     582            m_parameterSlots = RegisterFile::CallFrameHeaderSize + argCount;
     583
    581584        int registerOffset = currentInstruction[3].u.operand;
    582         int firstArg = registerOffset - argCount - RegisterFile::CallFrameHeaderSize;
    583         for (int argIdx = firstArg + (op == Construct ? 1 : 0); argIdx < firstArg + argCount; argIdx++)
    584             addVarArgChild(get(argIdx));
     585        int dummyThisArgument = op == Call ? 0 : 1;
     586        for (int i = 0 + dummyThisArgument; i < argCount; ++i)
     587            addVarArgChild(get(registerOffset + argumentToOperand(i)));
     588
    585589        NodeIndex call = addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction));
    586590        if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result)
    587591            set(putInstruction[1].u.operand, call);
    588         if (RegisterFile::CallFrameHeaderSize + (unsigned)argCount > m_parameterSlots)
    589             m_parameterSlots = RegisterFile::CallFrameHeaderSize + argCount;
    590592        return call;
    591593    }
     
    896898        callType = UnknownFunction;
    897899    if (callType != UnknownFunction) {
    898         int argCount = currentInstruction[2].u.operand;
     900        int argumentCountIncludingThis = currentInstruction[2].u.operand;
    899901        int registerOffset = currentInstruction[3].u.operand;
    900         int firstArg = registerOffset - argCount - RegisterFile::CallFrameHeaderSize;
    901         int lastArg = firstArg + argCount - 1;
    902                
     902
    903903        // Do we have a result?
    904904        bool usesResult = false;
     
    931931                addToGraph(CheckFunction, OpInfo(expectedFunction), callTarget);
    932932           
    933             if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg, prediction)) {
     933            if (handleIntrinsic(usesResult, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
    934934                if (!certainAboutExpectedFunction) {
    935935                    // Need to keep the call target alive for OSR. We could easily optimize this out if we wanted
     
    941941                return;
    942942            }
    943         } else if (handleInlining(usesResult, currentInstruction[1].u.operand, callTarget, resultOperand, certainAboutExpectedFunction, expectedFunction, firstArg, lastArg, nextOffset, kind))
     943        } else if (handleInlining(usesResult, currentInstruction[1].u.operand, callTarget, resultOperand, certainAboutExpectedFunction, expectedFunction, registerOffset, argumentCountIncludingThis, nextOffset, kind))
    944944            return;
    945945    }
     
    948948}
    949949
    950 bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex callTargetNodeIndex, int resultOperand, bool certainAboutExpectedFunction, JSFunction* expectedFunction, int firstArg, int lastArg, unsigned nextOffset, CodeSpecializationKind kind)
     950bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex callTargetNodeIndex, int resultOperand, bool certainAboutExpectedFunction, JSFunction* expectedFunction, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind)
    951951{
    952952    // First, the really simple checks: do we have an actual JS function?
     
    960960    // Does the number of arguments we're passing match the arity of the target? We could
    961961    // inline arity check failures, but for simplicity we currently don't.
    962     if (static_cast<int>(executable->parameterCount()) + 1 != lastArg - firstArg + 1)
     962    if (static_cast<int>(executable->parameterCount()) + 1 != argumentCountIncludingThis)
    963963        return false;
    964964   
     
    10011001    // FIXME: Don't flush constants!
    10021002   
    1003     for (int arg = firstArg + 1; arg <= lastArg; ++arg)
    1004         flush(arg);
    1005    
    1006     int inlineCallFrameStart = m_inlineStackTop->remapOperand(lastArg) + 1;
     1003    for (int i = 1; i < argumentCountIncludingThis; ++i)
     1004        flush(registerOffset + argumentToOperand(i));
     1005   
     1006    int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize;
    10071007   
    10081008    // Make sure that the area used by the call frame is reserved.
     
    11241124}
    11251125
    1126 bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType op, int firstArg, int lastArg)
     1126bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis)
    11271127{
    11281128    if (!usesResult)
    11291129        return true;
    11301130
    1131     if (lastArg == firstArg) {
     1131    if (argumentCountIncludingThis == 1) { // Math.min()
    11321132        set(resultOperand, constantNaN());
    11331133        return true;
    11341134    }
    11351135     
    1136     if (lastArg == firstArg + 1) {
    1137         set(resultOperand, getToNumber(firstArg + 1));
     1136    if (argumentCountIncludingThis == 2) { // Math.min(x)
     1137        set(resultOperand, getToNumber(registerOffset + argumentToOperand(1)));
    11381138        return true;
    11391139    }
    11401140   
    1141     if (lastArg == firstArg + 2) {
    1142         set(resultOperand, addToGraph(op, OpInfo(NodeUseBottom), getToNumber(firstArg + 1), getToNumber(firstArg + 2)));
     1141    if (argumentCountIncludingThis == 3) { // Math.min(x, y)
     1142        set(resultOperand, addToGraph(op, OpInfo(NodeUseBottom), getToNumber(registerOffset + argumentToOperand(1)), getToNumber(registerOffset + argumentToOperand(2))));
    11431143        return true;
    11441144    }
     
    11481148}
    11491149
    1150 bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int firstArg, int lastArg, PredictedType prediction)
     1150// FIXME: We dead-code-eliminate unused Math intrinsics, but that's invalid because
     1151// they need to perform the ToNumber conversion, which can have side-effects.
     1152bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction)
    11511153{
    11521154    switch (intrinsic) {
     
    11581160        }
    11591161       
    1160         // We don't care about the this argument. If we don't have a first
    1161         // argument then make this JSConstant(NaN).
    1162         int absArg = firstArg + 1;
    1163         if (absArg > lastArg) {
     1162        if (argumentCountIncludingThis == 1) { // Math.abs()
    11641163            set(resultOperand, constantNaN());
    11651164            return true;
     
    11691168            return false;
    11701169
    1171         set(resultOperand, addToGraph(ArithAbs, OpInfo(NodeUseBottom), getToNumber(absArg)));
     1170        set(resultOperand, addToGraph(ArithAbs, OpInfo(NodeUseBottom), getToNumber(registerOffset + argumentToOperand(1))));
    11721171        return true;
    11731172    }
    1174        
     1173
    11751174    case MinIntrinsic:
    1176         return handleMinMax(usesResult, resultOperand, ArithMin, firstArg, lastArg);
     1175        return handleMinMax(usesResult, resultOperand, ArithMin, registerOffset, argumentCountIncludingThis);
    11771176       
    11781177    case MaxIntrinsic:
    1179         return handleMinMax(usesResult, resultOperand, ArithMax, firstArg, lastArg);
     1178        return handleMinMax(usesResult, resultOperand, ArithMax, registerOffset, argumentCountIncludingThis);
    11801179       
    11811180    case SqrtIntrinsic: {
     
    11831182            return true;
    11841183       
    1185         if (firstArg == lastArg) {
     1184        if (argumentCountIncludingThis == 1) { // Math.sqrt()
    11861185            set(resultOperand, constantNaN());
    11871186            return true;
     
    11911190            return false;
    11921191       
    1193         set(resultOperand, addToGraph(ArithSqrt, getToNumber(firstArg + 1)));
     1192        set(resultOperand, addToGraph(ArithSqrt, getToNumber(registerOffset + argumentToOperand(1))));
    11941193        return true;
    11951194    }
    11961195       
    11971196    case ArrayPushIntrinsic: {
    1198         if (firstArg + 1 != lastArg)
     1197        if (argumentCountIncludingThis != 2)
    11991198            return false;
    12001199       
    1201         NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(0), OpInfo(prediction), get(firstArg), get(firstArg + 1));
     1200        NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
    12021201        if (usesResult)
    12031202            set(resultOperand, arrayPush);
     
    12071206       
    12081207    case ArrayPopIntrinsic: {
    1209         if (firstArg != lastArg)
     1208        if (argumentCountIncludingThis != 1)
    12101209            return false;
    12111210       
    1212         NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(0), OpInfo(prediction), get(firstArg));
     1211        NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
    12131212        if (usesResult)
    12141213            set(resultOperand, arrayPop);
     
    12171216
    12181217    case CharCodeAtIntrinsic: {
    1219         if (firstArg + 1 != lastArg)
     1218        if (argumentCountIncludingThis != 2)
    12201219            return false;
    1221         if (!(m_graph[get(firstArg)].prediction() & PredictString))
     1220
     1221        int thisOperand = registerOffset + argumentToOperand(0);
     1222        if (!(m_graph[get(thisOperand)].prediction() & PredictString))
    12221223            return false;
    12231224       
    1224         NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(firstArg), getToInt32(firstArg + 1));
    1225         NodeIndex charCode = addToGraph(StringCharCodeAt, get(firstArg), getToInt32(firstArg + 1), storage);
     1225        int indexOperand = registerOffset + argumentToOperand(1);
     1226        NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand));
     1227        NodeIndex charCode = addToGraph(StringCharCodeAt, get(thisOperand), getToInt32(indexOperand), storage);
     1228
    12261229        if (usesResult)
    12271230            set(resultOperand, charCode);
     
    12301233
    12311234    case CharAtIntrinsic: {
    1232         if (firstArg + 1 != lastArg)
     1235        if (argumentCountIncludingThis != 2)
    12331236            return false;
    1234         if (!(m_graph[get(firstArg)].prediction() & PredictString))
     1237
     1238        int thisOperand = registerOffset + argumentToOperand(0);
     1239        if (!(m_graph[get(thisOperand)].prediction() & PredictString))
    12351240            return false;
    12361241
    1237         NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(firstArg), getToInt32(firstArg + 1));
    1238         NodeIndex charCode = addToGraph(StringCharAt, get(firstArg), getToInt32(firstArg + 1), storage);
     1242        int indexOperand = registerOffset + argumentToOperand(1);
     1243        NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand));
     1244        NodeIndex charCode = addToGraph(StringCharAt, get(thisOperand), getToInt32(indexOperand), storage);
     1245
    12391246        if (usesResult)
    12401247            set(resultOperand, charCode);
     
    12681275        m_graph.m_arguments.resize(m_numArguments);
    12691276        for (unsigned argument = 0; argument < m_numArguments; ++argument) {
    1270             NodeIndex setArgument = addToGraph(SetArgument, OpInfo(newVariableAccessData(argument - m_codeBlock->m_numParameters - RegisterFile::CallFrameHeaderSize)));
     1277            NodeIndex setArgument = addToGraph(SetArgument, OpInfo(newVariableAccessData(argumentToOperand(argument))));
    12711278            m_graph.m_arguments[argument] = setArgument;
    12721279            m_currentBlock->variablesAtHead.setArgumentFirstTime(argument, setArgument);
     
    22082215#endif
    22092216
    2210                 valueInPredecessor = addToGraph(Phi, OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? varNo - m_codeBlock->m_numParameters - RegisterFile::CallFrameHeaderSize : varNo)));
     2217                valueInPredecessor = addToGraph(Phi, OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? argumentToOperand(varNo) : static_cast<int>(varNo))));
    22112218                var = valueInPredecessor;
    22122219                if (stackType == ArgumentPhiStack)
Note: See TracChangeset for help on using the changeset viewer.