Ignore:
Timestamp:
Aug 22, 2014, 12:54:30 PM (11 years ago)
Author:
[email protected]
Message:

REGRESSION(r163179): Sporadic crash in js/dom/line-column-numbers.html test
https://bugs.webkit.org/show_bug.cgi?id=136111

Reviewed by Filip Pizlo.

The problem was that we weren't properly handling VM::topVMEntryFrame in two ways.

First in the case where we get an exception of a stack overflow during setup of the direct
callee frame of a VM entry frame, we need to throw the exception in the caller's frame.
This requires unrolling topVMEntryFrame while creating the exception object. This is
accomplished with the renamed NativeCallFrameTracerWithRestore object. As part of this,
split the JIT rollback exception handling to call a new helper,
callLookupExceptionHandlerFromCallerFrame, which will unroll the callFrame and VMEntryFrame.

Second, when we unwind to find a handler, we also need to unwind topVMCallFrame for the
case where we end up (re)throwing another exception after entering the catch block, but
before another vmEntry call. Added VM::vmEntryFrameForThrow as a way similar to
VM::callFrameForThrow to pass the appropriate VMENtryFrame to the catch block.

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::compileExceptionHandlers):

  • ftl/FTLCompile.cpp:

(JSC::FTL::fixFunctionBasedOnStackMaps):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileExceptionHandlers):
Split out the unroll cases to use the new helper callLookupExceptionHandlerFromCallerFrame()
to unwind both the callFrame and topVMEntryFrame.

  • interpreter/Interpreter.cpp:

(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::Interpreter::unwind):

  • jit/JITExceptions.cpp:

(JSC::genericUnwind):
Added VMEntryFrame as another component to unwind.

  • interpreter/Interpreter.h:

(JSC::NativeCallFrameTracer::NativeCallFrameTracer):
(JSC::NativeCallFrameTracerWithRestore::NativeCallFrameTracerWithRestore):
(JSC::NativeCallFrameTracerWithRestore::~NativeCallFrameTracerWithRestore):
Renamed and changed to save and restore topCallFrame and topVMEntryFrame around the setting of
both values.

  • interpreter/StackVisitor.cpp:

(JSC::StackVisitor::gotoNextFrame):
(JSC::StackVisitor::readNonInlinedFrame):

  • interpreter/StackVisitor.h:

(JSC::StackVisitor::Frame::vmEntryFrame):
Added code to unwind the VMEntryFrame.

  • jit/CCallHelpers.h:

(JSC::CCallHelpers::jumpToExceptionHandler): Updated comment to indicate that the value
the handler should use for VM::topEntryFrame is in VM::vmEntryFrameForThrow.

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_catch):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_catch):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:

Added code to update VM::topVMEntryFrame from VM::vmEntryFrameForThrowOffset.

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:

(JSC::operationThrowStackOverflowError):
(JSC::operationCallArityCheck):
(JSC::operationConstructArityCheck):

  • runtime/VM.h:

(JSC::VM::vmEntryFrameForThrowOffset):
(JSC::VM::topVMEntryFrameOffset):
Added as the side channel to return the topVMEntryFrame that the handler should use.

Location:
trunk/Source/JavaScriptCore/interpreter
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r172665 r172867  
    646646class UnwindFunctor {
    647647public:
    648     UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
    649         : m_callFrame(callFrame)
     648    UnwindFunctor(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
     649        : m_vmEntryFrame(vmEntryFrame)
     650        , m_callFrame(callFrame)
    650651        , m_isTermination(isTermination)
    651652        , m_codeBlock(codeBlock)
     
    657658    {
    658659        VM& vm = m_callFrame->vm();
     660        m_vmEntryFrame = visitor->vmEntryFrame();
    659661        m_callFrame = visitor->callFrame();
    660662        m_codeBlock = visitor->codeBlock();
     
    674676
    675677private:
     678    VMEntryFrame*& m_vmEntryFrame;
    676679    CallFrame*& m_callFrame;
    677680    bool m_isTermination;
     
    680683};
    681684
    682 NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue)
     685NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, JSValue& exceptionValue)
    683686{
    684687    CodeBlock* codeBlock = callFrame->codeBlock();
     
    725728    VM& vm = callFrame->vm();
    726729    ASSERT(callFrame == vm.topCallFrame);
    727     UnwindFunctor functor(callFrame, isTermination, codeBlock, handler);
     730    UnwindFunctor functor(vmEntryFrame, callFrame, isTermination, codeBlock, handler);
    728731    callFrame->iterate(functor);
    729732    if (!handler)
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r172792 r172867  
    176176            ASSERT(vm);
    177177            ASSERT(callFrame);
    178             ASSERT(callFrame < vm->topVMEntryFrame);
    179178            vm->topCallFrame = callFrame;
    180179        }
    181 
    182         ALWAYS_INLINE NativeCallFrameTracer(VM* vm, VMEntryFrame* vmEntryFrame, CallFrame* callFrame)
     180    };
     181
     182    class NativeCallFrameTracerWithRestore {
     183    public:
     184        ALWAYS_INLINE NativeCallFrameTracerWithRestore(VM* vm, VMEntryFrame* vmEntryFrame, CallFrame* callFrame)
     185            : m_vm(vm)
    183186        {
    184187            ASSERT(vm);
    185188            ASSERT(callFrame);
    186             ASSERT(callFrame < vmEntryFrame);
     189            m_savedTopVMEntryFrame = vm->topVMEntryFrame;
     190            m_savedTopCallFrame = vm->topCallFrame;
    187191            vm->topVMEntryFrame = vmEntryFrame;
    188192            vm->topCallFrame = callFrame;
    189193        }
     194
     195        ALWAYS_INLINE ~NativeCallFrameTracerWithRestore()
     196        {
     197            m_vm->topVMEntryFrame = m_savedTopVMEntryFrame;
     198            m_vm->topCallFrame = m_savedTopCallFrame;
     199        }
     200
     201    private:
     202        VM* m_vm;
     203        VMEntryFrame* m_savedTopVMEntryFrame;
     204        CallFrame* m_savedTopCallFrame;
    190205    };
    191206
     
    237252        SamplingTool* sampler() { return m_sampler.get(); }
    238253
    239         NEVER_INLINE HandlerInfo* unwind(CallFrame*&, JSValue&);
     254        NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&, CallFrame*&, JSValue&);
    240255        NEVER_INLINE void debug(CallFrame*, DebugHookID);
    241256        JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
  • trunk/Source/JavaScriptCore/interpreter/StackVisitor.cpp

    r172807 r172867  
    6262        CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
    6363        readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
    64 
    65     } else
     64        return;
     65    }
    6666#endif // ENABLE(DFG_JIT)
    67         readFrame(m_frame.callerFrame());
     67    m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
     68    readFrame(m_frame.callerFrame());
    6869}
    6970
     
    117118    m_frame.m_callFrame = callFrame;
    118119    m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
    119     VMEntryFrame* currentVMEntryFrame = m_frame.m_VMEntryFrame;
    120     m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_VMEntryFrame);
    121     m_frame.m_callerIsVMEntryFrame = currentVMEntryFrame != m_frame.m_VMEntryFrame;
     120    m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
     121    m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
     122    m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
    122123    m_frame.m_callee = callFrame->callee();
    123124    m_frame.m_scope = callFrame->scope();
  • trunk/Source/JavaScriptCore/interpreter/StackVisitor.h

    r172665 r172867  
    8282        Arguments* createArguments();
    8383        Arguments* existingArguments();
     84        VMEntryFrame* vmEntryFrame() const { return m_VMEntryFrame; }
    8485        CallFrame* callFrame() const { return m_callFrame; }
    8586       
     
    9899        size_t m_argumentCountIncludingThis;
    99100        VMEntryFrame* m_VMEntryFrame;
     101        VMEntryFrame* m_CallerVMEntryFrame;
    100102        CallFrame* m_callerFrame;
    101103        JSObject* m_callee;
Note: See TracChangeset for help on using the changeset viewer.