Changeset 38322 in webkit for trunk/JavaScriptCore/VM/CTI.cpp


Ignore:
Timestamp:
Nov 11, 2008, 4:32:38 PM (17 years ago)
Author:
[email protected]
Message:

2008-11-11 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.


Fixed https://bugs.webkit.org/show_bug.cgi?id=22174
Simplified op_call by nixing its responsibility for moving the value of
"this" into the first argument slot.

Instead, the caller emits an explicit load or mov instruction, or relies
on implicit knowledge that "this" is already in the first argument slot.
As a result, two operands to op_call are gone: firstArg and thisVal.


SunSpider and v8 tests show no change in bytecode or CTI.

  • VM/CTI.cpp: (JSC::CTI::compileOpCallSetupArgs): (JSC::CTI::compileOpCallEvalSetupArgs): (JSC::CTI::compileOpConstructSetupArgs): Split apart these three versions of setting up arguments to op_call, because they're more different than they are the same -- even more so with this patch.

(JSC::CTI::compileOpCall): Updated for the fact that op_construct doesn't
match op_call anymore.

(JSC::CTI::privateCompileMainPass):
(JSC::CTI::privateCompileSlowCases): Merged a few call cases. Updated
for changes mentioned above.

  • VM/CTI.h:
  • VM/CodeBlock.cpp: (JSC::CodeBlock::dump): Updated for new bytecode format of call / construct.
  • VM/Machine.cpp: (JSC::Machine::callEval): Updated for new bytecode format of call / construct.

(JSC::Machine::dumpCallFrame):
(JSC::Machine::dumpRegisters): Simplified these debugging functions,
taking advantage of the new call frame layout.

(JSC::Machine::execute): Fixed up the eval version of execute to be
friendlier to calls in the new format.

(JSC::Machine::privateExecute): Implemented the new call format in
bytecode.

(JSC::Machine::cti_op_call_NotJSFunction):
(JSC::Machine::cti_op_construct_JSConstruct):
(JSC::Machine::cti_op_construct_NotJSConstruct):
(JSC::Machine::cti_op_call_eval): Updated CTI helpers to match the new
call format.


Fixed a latent bug in stack overflow checking that is now hit because
the register layout has changed a bit -- namely: when throwing a stack
overflow exception inside an op_call helper, we need to account for the
fact that the current call frame is only half-constructed, and use the
parent call frame instead.

  • VM/Machine.h:
  • bytecompiler/CodeGenerator.cpp: (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitCallEval): (JSC::CodeGenerator::emitConstruct):
  • bytecompiler/CodeGenerator.h: Updated codegen to match the new call format.
  • parser/Nodes.cpp: (JSC::EvalFunctionCallNode::emitCode): (JSC::FunctionCallValueNode::emitCode): (JSC::FunctionCallResolveNode::emitCode): (JSC::FunctionCallBracketNode::emitCode): (JSC::FunctionCallDotNode::emitCode):
  • parser/Nodes.h: (JSC::ScopeNode::neededConstants): ditto

2008-11-10 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.


Updated a test after fixing https://bugs.webkit.org/show_bug.cgi?id=22174
Simplified op_call by nixing its responsibility for moving the value of
"this" into the first argument slot.

  • fast/js/global-recursion-on-full-stack-expected.txt: This test passes a little differently now, because the register layout has changed. Specifically, the stack overflow now happens in the call to f() instead of the initiation of the <script> tag, so it is caught, and it does not log an exception to the console.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CTI.cpp

    r38306 r38322  
    588588}
    589589
    590 void CTI::compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval)
    591 {
    592     int firstArg = instruction[4].u.operand;
    593     int argCount = instruction[5].u.operand;
    594     int registerOffset = instruction[6].u.operand;
    595 
     590void CTI::compileOpCallSetupArgs(Instruction* instruction)
     591{
     592    int argCount = instruction[3].u.operand;
     593    int registerOffset = instruction[4].u.operand;
     594
     595    // ecx holds func
    596596    emitPutArg(X86::ecx, 0);
    597597    emitPutArgConstant(registerOffset, 4);
    598598    emitPutArgConstant(argCount, 8);
    599599    emitPutArgConstant(reinterpret_cast<unsigned>(instruction), 12);
    600     if (isConstruct) {
    601         emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
    602         emitPutArgConstant(firstArg, 20);
    603     } else if (isEval)
    604         emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
     600}
     601
     602void CTI::compileOpCallEvalSetupArgs(Instruction* instruction)
     603{
     604    int argCount = instruction[3].u.operand;
     605    int registerOffset = instruction[4].u.operand;
     606
     607    // ecx holds func
     608    emitPutArg(X86::ecx, 0);
     609    emitPutArgConstant(registerOffset, 4);
     610    emitPutArgConstant(argCount, 8);
     611    emitPutArgConstant(reinterpret_cast<unsigned>(instruction), 12);
     612}
     613
     614void CTI::compileOpConstructSetupArgs(Instruction* instruction)
     615{
     616    int argCount = instruction[3].u.operand;
     617    int registerOffset = instruction[4].u.operand;
     618    int proto = instruction[5].u.operand;
     619    int thisRegister = instruction[6].u.operand;
     620
     621    // ecx holds func
     622    emitPutArg(X86::ecx, 0);
     623    emitPutArgConstant(registerOffset, 4);
     624    emitPutArgConstant(argCount, 8);
     625    emitGetPutArg(proto, 12, X86::eax);
     626    emitPutArgConstant(thisRegister, 16);
     627    emitPutArgConstant(reinterpret_cast<unsigned>(instruction), 20);
    605628}
    606629
     
    609632    int dst = instruction[1].u.operand;
    610633    int callee = instruction[2].u.operand;
    611     int firstArg = instruction[4].u.operand;
    612     int argCount = instruction[5].u.operand;
    613     int registerOffset = instruction[6].u.operand;
    614 
    615     // Setup this value as the first argument (does not apply to constructors)
    616     if (opcodeID != op_construct) {
    617         int thisVal = instruction[3].u.operand;
    618         if (thisVal == missingThisObjectMarker())
    619             m_jit.movl_i32m(asInteger(jsNull()), firstArg * sizeof(Register), X86::edi);
    620         else {
    621             emitGetArg(thisVal, X86::eax);
    622             emitPutResult(firstArg);
    623         }
    624     }
     634    int argCount = instruction[3].u.operand;
     635    int registerOffset = instruction[4].u.operand;
    625636
    626637    // Handle eval
     
    628639    if (opcodeID == op_call_eval) {
    629640        emitGetArg(callee, X86::ecx);
    630         compileOpCallSetupArgs(instruction, false, true);
     641        compileOpCallEvalSetupArgs(instruction);
    631642
    632643        emitCTICall(instruction, i, Machine::cti_op_call_eval);
     
    648659    // In the case of OpConstruct, call out to a cti_ function to create the new object.
    649660    if (opcodeID == op_construct) {
     661        int proto = instruction[5].u.operand;
     662        int thisRegister = instruction[6].u.operand;
     663
    650664        emitPutArg(X86::ecx, 0);
    651         emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
     665        emitGetPutArg(proto, 12, X86::eax);
    652666        emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
    653         emitPutResult(firstArg);
     667        emitPutResult(thisRegister);
    654668        emitGetArg(callee, X86::ecx);
    655669    }
     
    12861300            break;
    12871301        }
    1288         case op_call: {
     1302        case op_call:
     1303        case op_call_eval:
     1304        case op_construct: {
    12891305            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
    1290             i += 7;
     1306            i += (opcodeID == op_construct ? 7 : 5);
    12911307            break;
    12921308        }
     
    13801396            emitPutResult(instruction[i + 1].u.operand);
    13811397            i += 3;
    1382             break;
    1383         }
    1384         case op_construct: {
    1385             compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
    1386             i += 7;
    13871398            break;
    13881399        }
     
    19121923            emitPutResult(instruction[i + 1].u.operand);
    19131924            i += 5;
    1914             break;
    1915         }
    1916         case op_call_eval: {
    1917             compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
    1918             i += 7;
    19191925            break;
    19201926        }
     
    27682774            int dst = instruction[i + 1].u.operand;
    27692775            int callee = instruction[i + 2].u.operand;
    2770             int firstArg = instruction[i + 4].u.operand;
    2771             int argCount = instruction[i + 5].u.operand;
    2772             int registerOffset = instruction[i + 6].u.operand;
     2776            int argCount = instruction[i + 3].u.operand;
     2777            int registerOffset = instruction[i + 4].u.operand;
    27732778
    27742779            m_jit.link(iter->from, m_jit.label());
    27752780
    27762781            // The arguments have been set up on the hot path for op_call_eval
    2777             if (opcodeID != op_call_eval)
    2778                 compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
     2782            if (opcodeID == op_call)
     2783                compileOpCallSetupArgs(instruction + i);
     2784            else if (opcodeID == op_construct)
     2785                compileOpConstructSetupArgs(instruction + i);
    27792786
    27802787            // Fast check for JS function.
     
    27842791            X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
    27852792
    2786             // First, in the cale of a construct, allocate the new object.
     2793            // First, in the case of a construct, allocate the new object.
    27872794            if (opcodeID == op_construct) {
    27882795                emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
    2789                 emitPutResult(firstArg);
     2796                emitPutResult(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
    27902797                emitGetArg(callee, X86::ecx);
    27912798            }
     
    28282835
    28292836            // The arguments have been set up on the hot path for op_call_eval
    2830             if (opcodeID != op_call_eval)
    2831                 compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
     2837            if (opcodeID == op_call)
     2838                compileOpCallSetupArgs(instruction + i);
     2839            else if (opcodeID == op_construct)
     2840                compileOpConstructSetupArgs(instruction + i);
    28322841
    28332842            // Check for JSFunctions.
     
    28482857            m_jit.link(isJSFunction, m_jit.label());
    28492858
    2850             // First, in the cale of a construct, allocate the new object.
     2859            // First, in the case of a construct, allocate the new object.
    28512860            if (opcodeID == op_construct) {
    28522861                emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
    2853                 emitPutResult(firstArg);
     2862                emitPutResult(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
    28542863                emitGetArg(callee, X86::ecx);
    28552864            }
     
    28962905            ++callLinkInfoIndex;
    28972906
    2898             i += 7;
     2907            i += (opcodeID == op_construct ? 7 : 5);
    28992908            break;
    29002909        }
Note: See TracChangeset for help on using the changeset viewer.