Changeset 38349 in webkit for trunk/JavaScriptCore/VM/Machine.cpp


Ignore:
Timestamp:
Nov 12, 2008, 4:48:23 PM (17 years ago)
Author:
[email protected]
Message:

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

Reviewed by Sam Weinig.


Fixed https://bugs.webkit.org/show_bug.cgi?id=22192
+37 failures in fast/profiler


along with Darin's review comments in
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

  • VM/Machine.cpp: (JSC::returnToThrowTrampoline): (JSC::throwStackOverflowError): (JSC::Machine::cti_register_file_check): (JSC::Machine::cti_op_call_arityCheck): (JSC::Machine::cti_vm_throw): Moved the throw logic into a function, since functions are better than macros.
  • bytecompiler/CodeGenerator.cpp: (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct): Ensure that the function register is preserved if profiling is enabled, since the profiler uses that register.
  • runtime/JSGlobalData.h: Renamed throwReturnAddress to exceptionLocation, because I had a hard time understanding what "throwReturnAddress" meant.
File:
1 edited

Legend:

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

    r38330 r38349  
    581581}
    582582
    583 NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, int argv, int argc, JSValue*& exceptionValue)
     583NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue*& exceptionValue)
    584584{
    585585    if (argc < 2)
    586586        return jsUndefined();
    587587
    588     JSValue* program = callFrame[argv + 1].jsValue(callFrame);
     588    JSValue* program = argv[1].jsValue(callFrame);
    589589
    590590    if (!program->isString())
     
    593593    UString programSource = asString(program)->value();
    594594
     595    ScopeChainNode* scopeChain = callFrame->scopeChain();
    595596    CodeBlock* codeBlock = callFrame->codeBlock();
    596597    RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache.get(callFrame, programSource, scopeChain, exceptionValue);
     
    598599    JSValue* result = jsUndefined();
    599600    if (evalNode)
    600         result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, thisObj, callFrame->registers() - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
     601        result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, callFrame->thisValue()->toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
    601602
    602603    return result;
     
    656657#ifndef NDEBUG
    657658
    658 void Machine::dumpCallFrame(const RegisterFile* registerFile, CallFrame* callFrame)
    659 {
    660     JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
    661 
    662     CodeBlock* codeBlock = callFrame->codeBlock();
    663     codeBlock->dump(globalObject->globalExec());
    664 
    665     dumpRegisters(registerFile, callFrame);
    666 }
    667 
    668 void Machine::dumpRegisters(const RegisterFile* registerFile, CallFrame* callFrame)
     659void Machine::dumpCallFrame(CallFrame* callFrame)
     660{
     661    callFrame->codeBlock()->dump(callFrame);
     662    dumpRegisters(callFrame);
     663}
     664
     665void Machine::dumpRegisters(CallFrame* callFrame)
    669666{
    670667    printf("Register frame: \n\n");
     
    674671
    675672    CodeBlock* codeBlock = callFrame->codeBlock();
     673    RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->machine->registerFile();
    676674    const Register* it;
    677675    const Register* end;
     
    10241022}
    10251023
    1026 JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
     1024JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue** exception)
    10271025{
    10281026    ASSERT(!scopeChain->globalData->exception);
     
    10701068
    10711069    Register* oldEnd = m_registerFile.end();
    1072     Register* newEnd = m_registerFile.start() + registerOffset + codeBlock->numCalleeRegisters;
     1070    Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->numCalleeRegisters;
    10731071    if (!m_registerFile.grow(newEnd)) {
    10741072        *exception = createStackOverflowError(callFrame);
     
    10761074    }
    10771075
    1078     CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + registerOffset);
     1076    CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
    10791077
    10801078    // a 0 codeBlock indicates a built-in caller
     
    32653263    }
    32663264    BEGIN_OPCODE(op_call_eval) {
    3267         /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
     3265        /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
    32683266
    32693267           Call a function named "eval" with no explicit "this" value
     
    32783276        int dst = vPC[1].u.operand;
    32793277        int func = vPC[2].u.operand;
    3280         int thisVal = vPC[3].u.operand;
    3281         int firstArg = vPC[4].u.operand;
    3282         int argCount = vPC[5].u.operand;
     3278        int argCount = vPC[3].u.operand;
     3279        int registerOffset = vPC[4].u.operand;
    32833280
    32843281        JSValue* funcVal = callFrame[func].jsValue(callFrame);
    3285         JSValue* baseVal = callFrame[thisVal].jsValue(callFrame);
    3286 
    3287         ScopeChainNode* scopeChain = callFrame->scopeChain();
    3288         if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
    3289             JSObject* thisObject = asObject(callFrame[callFrame->codeBlock()->thisRegister].jsValue(callFrame));
    3290             JSValue* result = callEval(callFrame, thisObject, scopeChain, registerFile, firstArg, argCount, exceptionValue);
     3282
     3283        Register* newCallFrame = callFrame->registers() + registerOffset;
     3284        Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
     3285        JSValue* thisValue = argv[0].jsValue(callFrame);
     3286        JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
     3287
     3288        if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
     3289            JSValue* result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
    32913290            if (exceptionValue)
    32923291                goto vm_throw;
    3293 
    32943292            callFrame[dst] = result;
    32953293
    3296             vPC += 7;
     3294            vPC += 5;
    32973295            NEXT_OPCODE;
    32983296        }
    32993297
    3300         // We didn't find the blessed version of eval, so reset vPC and process
    3301         // this instruction as a normal function call, supplying the proper 'this'
    3302         // value.
    3303         callFrame[thisVal] = baseVal->toThisObject(callFrame);
     3298        // We didn't find the blessed version of eval, so process this
     3299        // instruction as a normal function call.
    33043300
    33053301#if HAVE(COMPUTED_GOTO)
     
    33123308    }
    33133309    BEGIN_OPCODE(op_call) {
    3314         /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
    3315 
    3316            Perform a function call. Specifically, call register func
    3317            with a "this" value of register thisVal, and put the result
    3318            in register dst.
    3319 
    3320            The arguments start at register firstArg and go up to
    3321            argCount, but the "this" value is considered an implicit
    3322            first argument, so the argCount should be one greater than
    3323            the number of explicit arguments passed, and the register
    3324            after firstArg should contain the actual first
    3325            argument. This opcode will copy from the thisVal register
    3326            to the firstArg register, unless the register index of
    3327            thisVal is the special missing this object marker, which is
    3328            2^31-1; in that case, the global object will be used as the
    3329            "this" value.
    3330 
    3331            If func is a native code function, then this opcode calls
    3332            it and returns the value immediately.
    3333 
    3334            But if it is a JS function, then the current scope chain
    3335            and code block is set to the function's, and we slide the
    3336            register window so that the arguments would form the first
    3337            few local registers of the called function's register
    3338            window. In addition, a call frame header is written
    3339            immediately before the arguments; see the call frame
    3340            documentation for an explanation of how many registers a
    3341            call frame takes and what they contain. That many registers
    3342            before the firstArg register will be overwritten by the
    3343            call. In addition, any registers higher than firstArg +
    3344            argCount may be overwritten. Once this setup is complete,
    3345            execution continues from the called function's first
    3346            argument, and does not return until a "ret" opcode is
    3347            encountered.
     3310        /* call dst(r) func(r) argCount(n) registerOffset(n)
     3311
     3312           Perform a function call.
     3313           
     3314           registerOffset is the distance the callFrame pointer should move
     3315           before the VM initializes the new call frame's header.
     3316           
     3317           dst is where op_ret should store its result.
    33483318         */
    33493319
    33503320        int dst = vPC[1].u.operand;
    33513321        int func = vPC[2].u.operand;
    3352         int thisVal = vPC[3].u.operand;
    3353         int firstArg = vPC[4].u.operand;
    3354         int argCount = vPC[5].u.operand;
    3355         int registerOffset = vPC[6].u.operand;
     3322        int argCount = vPC[3].u.operand;
     3323        int registerOffset = vPC[4].u.operand;
    33563324
    33573325        JSValue* v = callFrame[func].jsValue(callFrame);
     
    33653333            CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
    33663334
    3367             callFrame[firstArg] = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame);
    3368            
    33693335            CallFrame* previousCallFrame = callFrame;
    33703336
     
    33763342            }
    33773343
    3378             callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
     3344            callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
    33793345            vPC = newCodeBlock->instructions.begin();
    33803346
     
    33873353
    33883354        if (callType == CallTypeHost) {
    3389             JSValue* thisValue = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame);
    3390             ArgList args(callFrame->registers() + firstArg + 1, argCount - 1);
    3391 
    33923355            ScopeChainNode* scopeChain = callFrame->scopeChain();
    33933356            CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
    3394             newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
     3357            newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
     3358
     3359            Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
     3360            ArgList args(thisRegister + 1, argCount - 1);
     3361
     3362            // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
     3363            JSValue* thisValue = thisRegister->jsValue(callFrame);
     3364            if (thisValue == jsNull())
     3365                thisValue = callFrame->globalThisValue();
    33953366
    33963367            JSValue* returnValue;
     
    34033374            callFrame[dst] = returnValue;
    34043375
    3405             vPC += 7;
     3376            vPC += 5;
    34063377            NEXT_OPCODE;
    34073378        }
     
    35733544    }
    35743545    BEGIN_OPCODE(op_construct) {
    3575         /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
    3576 
    3577            Invoke register "constr" as a constructor. For JS
     3546        /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
     3547
     3548           Invoke register "func" as a constructor. For JS
    35783549           functions, the calling convention is exactly as for the
    35793550           "call" opcode, except that the "this" value is a newly
    3580            created Object. For native constructors, a null "this"
    3581            value is passed. In either case, the firstArg and argCount
     3551           created Object. For native constructors, no "this"
     3552           value is passed. In either case, the argCount and registerOffset
    35823553           registers are interpreted as for the "call" opcode.
    35833554
    3584            Register constrProto must contain the prototype property of
    3585            register constsr. This is to enable polymorphic inline
     3555           Register proto must contain the prototype property of
     3556           register func. This is to enable polymorphic inline
    35863557           caching of this lookup.
    35873558        */
    35883559
    35893560        int dst = vPC[1].u.operand;
    3590         int constr = vPC[2].u.operand;
    3591         int constrProto = vPC[3].u.operand;
    3592         int firstArg = vPC[4].u.operand;
    3593         int argCount = vPC[5].u.operand;
    3594         int registerOffset = vPC[6].u.operand;
    3595 
    3596         JSValue* v = callFrame[constr].jsValue(callFrame);
     3561        int func = vPC[2].u.operand;
     3562        int argCount = vPC[3].u.operand;
     3563        int registerOffset = vPC[4].u.operand;
     3564        int proto = vPC[5].u.operand;
     3565        int thisRegister = vPC[6].u.operand;
     3566
     3567        JSValue* v = callFrame[func].jsValue(callFrame);
    35973568
    35983569        ConstructData constructData;
     
    36053576
    36063577            StructureID* structure;
    3607             JSValue* prototype = callFrame[constrProto].jsValue(callFrame);
     3578            JSValue* prototype = callFrame[proto].jsValue(callFrame);
    36083579            if (prototype->isObject())
    36093580                structure = asObject(prototype)->inheritorID();
     
    36123583            JSObject* newObject = new (globalData) JSObject(structure);
    36133584
    3614             callFrame[firstArg] = newObject; // "this" value
     3585            callFrame[thisRegister] = newObject; // "this" value
    36153586
    36163587            CallFrame* previousCallFrame = callFrame;
     
    36343605
    36353606        if (constructType == ConstructTypeHost) {
    3636             ArgList args(callFrame->registers() + firstArg + 1, argCount - 1);
     3607            ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
    36373608
    36383609            ScopeChainNode* scopeChain = callFrame->scopeChain();
     
    43264297// good to keep the code size down by leaving as much of the exception
    43274298// handling code out of line as possible.
    4328 static NEVER_INLINE void setUpThrowTrampolineReturnAddress(JSGlobalData* globalData, void*& returnAddress)
     4299static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot)
    43294300{
    43304301    ASSERT(globalData->exception);
    4331     globalData->throwReturnAddress = returnAddress;
    4332     ctiSetReturnAddress(&returnAddress, reinterpret_cast<void*>(ctiVMThrowTrampoline));
     4302    globalData->exceptionLocation = exceptionLocation;
     4303    ctiSetReturnAddress(&returnAddressSlot, reinterpret_cast<void*>(ctiVMThrowTrampoline));
     4304}
     4305
     4306static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot)
     4307{
     4308    globalData->exception = createStackOverflowError(callFrame);
     4309    returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot);
    43334310}
    43344311
     
    43454322    } while (0)
    43464323#define VM_THROW_EXCEPTION_AT_END() \
    4347     setUpThrowTrampolineReturnAddress(ARG_globalData, CTI_RETURN_ADDRESS)
     4324    returnToThrowTrampoline(ARG_globalData, CTI_RETURN_ADDRESS, CTI_RETURN_ADDRESS)
    43484325
    43494326#define VM_CHECK_EXCEPTION() \
     
    44534430}
    44544431
    4455 NEVER_INLINE void Machine::throwStackOverflowPreviousFrame(CallFrame* callFrame, JSGlobalData* globalData, void*& returnAddress)
    4456 {
    4457     globalData->exception = createStackOverflowError(callFrame->callerFrame());
    4458     globalData->throwReturnAddress = callFrame->returnPC();
    4459     ctiSetReturnAddress(&returnAddress, reinterpret_cast<void*>(ctiVMThrowTrampoline));
    4460 }
    4461 
    44624432void Machine::cti_register_file_check(CTI_ARGS)
    44634433{
     
    44674437        return;
    44684438
    4469     ARG_setCallFrame(ARG_callFrame->callerFrame());
    4470     throwStackOverflowPreviousFrame(ARG_callFrame, ARG_globalData, CTI_RETURN_ADDRESS);
     4439    // Rewind to the previous call frame because op_call already optimistically
     4440    // moved the call frame forward.
     4441    CallFrame* oldCallFrame = ARG_callFrame->callerFrame();
     4442    ARG_setCallFrame(oldCallFrame);
     4443    throwStackOverflowError(oldCallFrame, ARG_globalData, oldCallFrame->returnPC(), CTI_RETURN_ADDRESS);
    44714444}
    44724445
     
    47454718        Register* newEnd = r + newCodeBlock->numCalleeRegisters;
    47464719        if (!ARG_registerFile->grow(newEnd)) {
    4747             ARG_globalData->exception = createStackOverflowError(oldCallFrame);
    4748             VM_THROW_EXCEPTION_2();
     4720            // Rewind to the previous call frame because op_call already optimistically
     4721            // moved the call frame forward.
     4722            ARG_setCallFrame(oldCallFrame);
     4723            throwStackOverflowError(oldCallFrame, ARG_globalData, CTI_RETURN_ADDRESS, CTI_RETURN_ADDRESS);
     4724            VoidPtrPairValue pair = {{ 0, 0 }};
     4725            return pair.i;
    47494726        }
    47504727
     
    48114788            SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
    48124789
    4813             // All host methods should be calling toThisObject, but this is not presently the case.
     4790            // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
    48144791            JSValue* thisValue = argv[0].jsValue(callFrame);
    48154792            if (thisValue == jsNull())
     
    49354912
    49364913    StructureID* structure;
    4937     if (ARG_src5->isObject())
    4938         structure = asObject(ARG_src5)->inheritorID();
     4914    if (ARG_src4->isObject())
     4915        structure = asObject(ARG_src4)->inheritorID();
    49394916    else
    49404917        structure = asFunction(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure();
     
    49504927    JSValue* constrVal = ARG_src1;
    49514928    int argCount = ARG_int3;
    4952     int firstArg = ARG_int6;
     4929    int thisRegister = ARG_int5;
    49534930
    49544931    ConstructData constructData;
     
    49564933
    49574934    if (constructType == ConstructTypeHost) {
    4958         ArgList argList(callFrame->registers() + firstArg + 1, argCount - 1);
     4935        ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
    49594936
    49604937        JSValue* returnValue;
     
    49704947    ASSERT(constructType == ConstructTypeNone);
    49714948
    4972     ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr4, callFrame->codeBlock());
     4949    ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame->codeBlock());
    49734950    VM_THROW_EXCEPTION();
    49744951}
     
    55695546    CallFrame* callFrame = ARG_callFrame;
    55705547    RegisterFile* registerFile = ARG_registerFile;
    5571     CodeBlock* codeBlock = callFrame->codeBlock();
    5572     ScopeChainNode* scopeChain = callFrame->scopeChain();
    55735548
    55745549    Machine* machine = ARG_globalData->machine;
     
    55775552    int registerOffset = ARG_int2;
    55785553    int argCount = ARG_int3;
    5579     JSValue* baseVal = ARG_src5;
    5580 
    5581     if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
    5582         JSObject* thisObject = callFrame[codeBlock->thisRegister].jsValue(callFrame)->toThisObject(callFrame);
     5554
     5555    Register* newCallFrame = callFrame->registers() + registerOffset;
     5556    Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
     5557    JSValue* thisValue = argv[0].jsValue(callFrame);
     5558    JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
     5559
     5560    if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
    55835561        JSValue* exceptionValue = noValue();
    5584         JSValue* result = machine->callEval(callFrame, thisObject, scopeChain, registerFile, registerOffset - RegisterFile::CallFrameHeaderSize - argCount, argCount, exceptionValue);
     5562        JSValue* result = machine->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
    55855563        if (UNLIKELY(exceptionValue != noValue())) {
    55865564            ARG_globalData->exception = exceptionValue;
     
    59455923    CallFrame* callFrame = ARG_callFrame;
    59465924    CodeBlock* codeBlock = callFrame->codeBlock();
    5947 
    5948     ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(ARG_globalData->throwReturnAddress));
    5949     unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(ARG_globalData->throwReturnAddress);
    5950 
    5951     JSValue* exceptionValue = ARG_globalData->exception;
     5925    JSGlobalData* globalData = ARG_globalData;
     5926
     5927    ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(globalData->exceptionLocation));
     5928    unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(globalData->exceptionLocation);
     5929
     5930    JSValue* exceptionValue = globalData->exception;
    59525931    ASSERT(exceptionValue);
    5953     ARG_globalData->exception = noValue();
    5954 
    5955     Instruction* handlerVPC = ARG_globalData->machine->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, false);
     5932    globalData->exception = noValue();
     5933
     5934    Instruction* handlerVPC = globalData->machine->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, false);
    59565935
    59575936    if (!handlerVPC) {
Note: See TracChangeset for help on using the changeset viewer.