Changeset 155013 in webkit


Ignore:
Timestamp:
Sep 3, 2013, 5:26:57 PM (12 years ago)
Author:
mark.lam@apple.com
Message:

Converting StackIterator to a callback interface.
https://bugs.webkit.org/show_bug.cgi?id=120564.

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

  • API/JSContextRef.cpp:

(BacktraceFunctor::BacktraceFunctor):
(BacktraceFunctor::operator()):
(JSContextCreateBacktrace):

  • interpreter/CallFrame.cpp:
  • interpreter/CallFrame.h:
  • interpreter/Interpreter.cpp:

(JSC::DumpRegisterFunctor::DumpRegisterFunctor):
(JSC::DumpRegisterFunctor::operator()):
(JSC::Interpreter::dumpRegisters):
(JSC::unwindCallFrame):
(JSC::GetStackTraceFunctor::GetStackTraceFunctor):
(JSC::GetStackTraceFunctor::operator()):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::stackTraceAsString):
(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::Interpreter::unwind):

  • interpreter/Interpreter.h:
  • interpreter/StackIterator.cpp:

(JSC::StackIterator::numberOfFrames):
(JSC::StackIterator::gotoFrameAtIndex):
(JSC::StackIterator::gotoNextFrameWithFilter):
(JSC::StackIterator::resetIterator):
(JSC::StackIterator::Frame::print):
(debugPrintCallFrame):
(DebugPrintStackFunctor::operator()):
(debugPrintStack): Added for debugging convenience.

  • interpreter/StackIterator.h:

(JSC::StackIterator::Frame::index):
(JSC::StackIterator::iterate):

  • jsc.cpp:

(FunctionJSCStackFunctor::FunctionJSCStackFunctor):
(FunctionJSCStackFunctor::operator()):
(functionJSCStack):

  • profiler/ProfileGenerator.cpp:

(JSC::AddParentForConsoleStartFunctor::AddParentForConsoleStartFunctor):
(JSC::AddParentForConsoleStartFunctor::foundParent):
(JSC::AddParentForConsoleStartFunctor::operator()):
(JSC::ProfileGenerator::addParentForConsoleStart):

  • runtime/JSFunction.cpp:

(JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor):
(JSC::RetrieveArgumentsFunctor::result):
(JSC::RetrieveArgumentsFunctor::operator()):
(JSC::retrieveArguments):
(JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor):
(JSC::RetrieveCallerFunctionFunctor::result):
(JSC::RetrieveCallerFunctionFunctor::operator()):
(JSC::retrieveCallerFunction):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::GlobalFuncProtoGetterFunctor::GlobalFuncProtoGetterFunctor):
(JSC::GlobalFuncProtoGetterFunctor::result):
(JSC::GlobalFuncProtoGetterFunctor::operator()):
(JSC::globalFuncProtoGetter):
(JSC::GlobalFuncProtoSetterFunctor::GlobalFuncProtoSetterFunctor):
(JSC::GlobalFuncProtoSetterFunctor::allowsAccess):
(JSC::GlobalFuncProtoSetterFunctor::operator()):
(JSC::globalFuncProtoSetter):

  • runtime/ObjectConstructor.cpp:

(JSC::ObjectConstructorGetPrototypeOfFunctor::ObjectConstructorGetPrototypeOfFunctor):
(JSC::ObjectConstructorGetPrototypeOfFunctor::result):
(JSC::ObjectConstructorGetPrototypeOfFunctor::operator()):
(JSC::objectConstructorGetPrototypeOf):

Source/WebCore:

No new tests.

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::SendFunctor::SendFunctor):
(WebCore::SendFunctor::hasViableFrame):
(WebCore::SendFunctor::operator()):
(WebCore::JSXMLHttpRequest::send):

  • bindings/js/ScriptCallStackFactory.cpp:

(WebCore::CreateScriptCallStackFunctor::CreateScriptCallStackFunctor):
(WebCore::CreateScriptCallStackFunctor::operator()):
(WebCore::createScriptCallStack):
(WebCore::CreateScriptCallStackForConsoleFunctor::CreateScriptCallStackForConsoleFunctor):
(WebCore::CreateScriptCallStackForConsoleFunctor::operator()):

Location:
trunk/Source
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSContextRef.cpp

    r153218 r155013  
    213213    return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
    214214}
    215    
     215
     216class BacktraceFunctor {
     217public:
     218    BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture)
     219        : m_builder(builder)
     220        , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture)
     221    {
     222    }
     223
     224    StackIterator::Status operator()(StackIterator& iter)
     225    {
     226        if (m_remainingCapacityForFrameCapture) {
     227            // If callee is unknown, but we've not added any frame yet, we should
     228            // still add the frame, because something called us, and gave us arguments.
     229            JSObject* callee = iter->callee();
     230            if (!callee && iter->index())
     231                return StackIterator::Done;
     232
     233            StringBuilder& builder = m_builder;
     234            if (!builder.isEmpty())
     235                builder.append('\n');
     236            builder.append('#');
     237            builder.appendNumber(iter->index());
     238            builder.append(' ');
     239            builder.append(iter->functionName());
     240            builder.appendLiteral("() at ");
     241            builder.append(iter->sourceURL());
     242            if (iter->isJSFrame()) {
     243                builder.append(':');
     244                unsigned lineNumber;
     245                unsigned unusedColumn;
     246                iter->computeLineAndColumn(lineNumber, unusedColumn);
     247                builder.appendNumber(lineNumber);
     248            }
     249
     250            if (!callee)
     251                return StackIterator::Done;
     252
     253            m_remainingCapacityForFrameCapture--;
     254            return StackIterator::Continue;
     255        }
     256        return StackIterator::Done;
     257    }
     258
     259private:
     260    StringBuilder& m_builder;
     261    unsigned m_remainingCapacityForFrameCapture;
     262};
     263
    216264JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
    217265{
     
    224272    StringBuilder builder;
    225273    CallFrame* frame = exec->vm().topCallFrame;
    226     size_t i = 0;
     274
    227275    ASSERT(maxStackSize);
    228     for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter, ++i) {
    229         JSObject* callee = iter->callee();
    230         // If callee is unknown, but we've not added any frame yet, we should
    231         // still add the frame, because something called us, and gave us arguments.
    232         if (!callee && i)
    233             break;
    234 
    235         if (!builder.isEmpty())
    236             builder.append('\n');
    237         builder.append('#');
    238         builder.appendNumber(i);
    239         builder.append(' ');
    240         builder.append(iter->functionName());
    241         builder.appendLiteral("() at ");
    242         builder.append(iter->sourceURL());
    243         if (iter->isJSFrame()) {
    244             builder.append(':');
    245             unsigned lineNumber;
    246             unsigned unusedColumn;
    247             iter->computeLineAndColumn(lineNumber, unusedColumn);
    248             builder.appendNumber(lineNumber);
    249         }
    250 
    251         if (!callee)
    252             break;
    253     }
     276    BacktraceFunctor functor(builder, maxStackSize);
     277    StackIterator iter = frame->begin();
     278    iter.iterate(functor);
    254279
    255280    return OpaqueJSString::create(builder.toString()).leakRef();
  • trunk/Source/JavaScriptCore/ChangeLog

    r155008 r155013  
     12013-09-03  Mark Lam  <mark.lam@apple.com>
     2
     3        Converting StackIterator to a callback interface.
     4        https://bugs.webkit.org/show_bug.cgi?id=120564.
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * API/JSContextRef.cpp:
     9        (BacktraceFunctor::BacktraceFunctor):
     10        (BacktraceFunctor::operator()):
     11        (JSContextCreateBacktrace):
     12        * interpreter/CallFrame.cpp:
     13        * interpreter/CallFrame.h:
     14        * interpreter/Interpreter.cpp:
     15        (JSC::DumpRegisterFunctor::DumpRegisterFunctor):
     16        (JSC::DumpRegisterFunctor::operator()):
     17        (JSC::Interpreter::dumpRegisters):
     18        (JSC::unwindCallFrame):
     19        (JSC::GetStackTraceFunctor::GetStackTraceFunctor):
     20        (JSC::GetStackTraceFunctor::operator()):
     21        (JSC::Interpreter::getStackTrace):
     22        (JSC::Interpreter::stackTraceAsString):
     23        (JSC::UnwindFunctor::UnwindFunctor):
     24        (JSC::UnwindFunctor::operator()):
     25        (JSC::Interpreter::unwind):
     26        * interpreter/Interpreter.h:
     27        * interpreter/StackIterator.cpp:
     28        (JSC::StackIterator::numberOfFrames):
     29        (JSC::StackIterator::gotoFrameAtIndex):
     30        (JSC::StackIterator::gotoNextFrameWithFilter):
     31        (JSC::StackIterator::resetIterator):
     32        (JSC::StackIterator::Frame::print):
     33        (debugPrintCallFrame):
     34        (DebugPrintStackFunctor::operator()):
     35        (debugPrintStack): Added for debugging convenience.
     36        * interpreter/StackIterator.h:
     37        (JSC::StackIterator::Frame::index):
     38        (JSC::StackIterator::iterate):
     39        * jsc.cpp:
     40        (FunctionJSCStackFunctor::FunctionJSCStackFunctor):
     41        (FunctionJSCStackFunctor::operator()):
     42        (functionJSCStack):
     43        * profiler/ProfileGenerator.cpp:
     44        (JSC::AddParentForConsoleStartFunctor::AddParentForConsoleStartFunctor):
     45        (JSC::AddParentForConsoleStartFunctor::foundParent):
     46        (JSC::AddParentForConsoleStartFunctor::operator()):
     47        (JSC::ProfileGenerator::addParentForConsoleStart):
     48        * runtime/JSFunction.cpp:
     49        (JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor):
     50        (JSC::RetrieveArgumentsFunctor::result):
     51        (JSC::RetrieveArgumentsFunctor::operator()):
     52        (JSC::retrieveArguments):
     53        (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor):
     54        (JSC::RetrieveCallerFunctionFunctor::result):
     55        (JSC::RetrieveCallerFunctionFunctor::operator()):
     56        (JSC::retrieveCallerFunction):
     57        * runtime/JSGlobalObjectFunctions.cpp:
     58        (JSC::GlobalFuncProtoGetterFunctor::GlobalFuncProtoGetterFunctor):
     59        (JSC::GlobalFuncProtoGetterFunctor::result):
     60        (JSC::GlobalFuncProtoGetterFunctor::operator()):
     61        (JSC::globalFuncProtoGetter):
     62        (JSC::GlobalFuncProtoSetterFunctor::GlobalFuncProtoSetterFunctor):
     63        (JSC::GlobalFuncProtoSetterFunctor::allowsAccess):
     64        (JSC::GlobalFuncProtoSetterFunctor::operator()):
     65        (JSC::globalFuncProtoSetter):
     66        * runtime/ObjectConstructor.cpp:
     67        (JSC::ObjectConstructorGetPrototypeOfFunctor::ObjectConstructorGetPrototypeOfFunctor):
     68        (JSC::ObjectConstructorGetPrototypeOfFunctor::result):
     69        (JSC::ObjectConstructorGetPrototypeOfFunctor::operator()):
     70        (JSC::objectConstructorGetPrototypeOf):
     71
    1722013-09-03  Oliver Hunt  <oliver@apple.com>
    273
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.cpp

    r154821 r155013  
    104104}
    105105
    106 StackIterator CallFrame::find(JSFunction* calleeFunctionObj, StackIterator::FrameFilter filter)
    107 {
    108     ASSERT(this);
    109     StackIterator iter = StackIterator(this, filter);
    110     iter.find(calleeFunctionObj);
    111     return iter;
    112 }
    113 
    114106} // namespace JSC
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.h

    r154902 r155013  
    285285
    286286        JS_EXPORT_PRIVATE StackIterator begin(StackIterator::FrameFilter = 0);
    287         JS_EXPORT_PRIVATE StackIterator find(JSFunction* calleeFunctionObj, StackIterator::FrameFilter = 0);
    288         StackIterator end() { return StackIterator::end(); }
    289287
    290288    private:
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r154935 r155013  
    275275}
    276276
     277class DumpRegisterFunctor {
     278public:
     279    DumpRegisterFunctor(const Register*& it)
     280        : m_hasSkippedFirstFrame(false)
     281        , m_it(it)
     282    {
     283    }
     284
     285    StackIterator::Status operator()(StackIterator& iter)
     286    {
     287        if (!m_hasSkippedFirstFrame) {
     288            m_hasSkippedFirstFrame = true;
     289            return StackIterator::Continue;
     290        }
     291
     292        unsigned line = 0;
     293        unsigned unusedColumn = 0;
     294        iter->computeLineAndColumn(line, unusedColumn);
     295        dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", m_it, iter->bytecodeOffset(), line);
     296        ++m_it;
     297        return StackIterator::Done;
     298    }
     299
     300private:
     301    bool m_hasSkippedFirstFrame;
     302    const Register*& m_it;
     303};
     304
    277305void Interpreter::dumpRegisters(CallFrame* callFrame)
    278306{
     
    310338        dataLogF("[ReturnJITPC]              | %10p | %p \n", it, pc.jitReturnAddress().value());
    311339#endif
     340
     341    DumpRegisterFunctor functor(it);
    312342    StackIterator iter = callFrame->begin();
    313     ++iter;
    314     if (iter != callFrame->end()) {
    315         unsigned line = 0;
    316         unsigned unusedColumn = 0;
    317         iter->computeLineAndColumn(line, unusedColumn);
    318         dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, iter->bytecodeOffset(), line);
    319         ++it;
    320     }
     343    iter.iterate(functor);
     344
    321345    dataLogF("[CodeBlock]                | %10p | %p \n", it, callFrame->codeBlock());
    322346    ++it;
     
    367391}
    368392
    369 NEVER_INLINE bool Interpreter::unwindCallFrame(StackIterator& iter, JSValue exceptionValue)
     393static bool unwindCallFrame(StackIterator& iter, JSValue exceptionValue)
    370394{
    371395    CallFrame* callFrame = iter->callFrame();
     
    475499}
    476500
     501class GetStackTraceFunctor {
     502public:
     503    GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity)
     504        : m_vm(vm)
     505        , m_results(results)
     506        , m_remainingCapacityForFrameCapture(remainingCapacity)
     507    {
     508    }
     509
     510    StackIterator::Status operator()(StackIterator& iter)
     511    {
     512        VM& vm = m_vm;
     513        if (m_remainingCapacityForFrameCapture) {
     514            if (iter->isJSFrame()) {
     515                CodeBlock* codeBlock = iter->codeBlock();
     516                StackFrame s = {
     517                    Strong<JSObject>(vm, iter->callee()),
     518                    getStackFrameCodeType(iter),
     519                    Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()),
     520                    Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
     521                    codeBlock->source(),
     522                    codeBlock->ownerExecutable()->lineNo(),
     523                    codeBlock->firstLineColumnOffset(),
     524                    codeBlock->sourceOffset(),
     525                    iter->bytecodeOffset(),
     526                    iter->sourceURL()
     527                };
     528                m_results.append(s);
     529            } else {
     530                StackFrame s = { Strong<JSObject>(vm, iter->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
     531                m_results.append(s);
     532            }
     533   
     534            m_remainingCapacityForFrameCapture--;
     535            return StackIterator::Continue;
     536        }
     537        return StackIterator::Done;
     538    }
     539
     540private:
     541    VM& m_vm;
     542    Vector<StackFrame>& m_results;
     543    size_t m_remainingCapacityForFrameCapture;
     544};
     545
    477546void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
    478547{
     
    482551    if (!callFrame)
    483552        return;
     553
     554    GetStackTraceFunctor functor(vm, results, maxStackSize);
    484555    StackIterator iter = callFrame->begin();
    485     for (; iter != callFrame->end() && maxStackSize--; ++iter) {
    486         if (iter->isJSFrame()) {
    487             CodeBlock* codeBlock = iter->codeBlock();
    488             StackFrame s = {
    489                 Strong<JSObject>(vm, iter->callee()),
    490                 getStackFrameCodeType(iter),
    491                 Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()),
    492                 Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
    493                 codeBlock->source(),
    494                 codeBlock->ownerExecutable()->lineNo(),
    495                 codeBlock->firstLineColumnOffset(),
    496                 codeBlock->sourceOffset(),
    497                 iter->bytecodeOffset(),
    498                 iter->sourceURL()
    499             };
    500             results.append(s);
    501         } else {
    502             StackFrame s = { Strong<JSObject>(vm, iter->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
    503             results.append(s);
    504         }
    505     }
    506 }
    507 JSString* Interpreter:: stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace)
     556    iter.iterate(functor);
     557}
     558
     559JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace)
    508560{
    509561    // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
     
    516568    return jsString(&exec->vm(), builder.toString());
    517569}
     570
     571class UnwindFunctor {
     572public:
     573    UnwindFunctor(CallFrame*& callFrame, JSValue& exceptionValue, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
     574        : m_callFrame(callFrame)
     575        , m_exceptionValue(exceptionValue)
     576        , m_isTermination(isTermination)
     577        , m_codeBlock(codeBlock)
     578        , m_handler(handler)
     579    {
     580    }
     581
     582    StackIterator::Status operator()(StackIterator& iter)
     583    {
     584        VM& vm = m_callFrame->vm();
     585        m_callFrame = iter->callFrame();
     586        m_codeBlock = iter->codeBlock();
     587        unsigned bytecodeOffset = iter->bytecodeOffset();
     588
     589        if (m_isTermination || !(m_handler = m_codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
     590        if (!unwindCallFrame(iter, m_exceptionValue)) {
     591            if (LegacyProfiler* profiler = vm.enabledProfiler())
     592                profiler->exceptionUnwind(m_callFrame);
     593            return StackIterator::Done;
     594        }
     595    } else
     596        return StackIterator::Done;
     597
     598    return StackIterator::Continue;
     599}
     600
     601private:
     602    CallFrame*& m_callFrame;
     603    JSValue& m_exceptionValue;
     604    bool m_isTermination;
     605    CodeBlock*& m_codeBlock;
     606    HandlerInfo*& m_handler;
     607};
    518608
    519609NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
     
    550640    VM& vm = callFrame->vm();
    551641    ASSERT(callFrame == vm.topCallFrame);
    552     for (StackIterator iter = callFrame->begin(); iter != callFrame->end(); ++iter) {
    553         callFrame = iter->callFrame();
    554         codeBlock = iter->codeBlock();
    555         bytecodeOffset = iter->bytecodeOffset();
    556 
    557         if (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
    558             if (!unwindCallFrame(iter, exceptionValue)) {
    559                 if (LegacyProfiler* profiler = vm.enabledProfiler())
    560                     profiler->exceptionUnwind(callFrame);
    561                 return 0;
    562             }
    563         } else
    564             break;
    565     }
    566 
    567     if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler())
     642    UnwindFunctor functor(callFrame, exceptionValue, isTermination, codeBlock, handler);
     643    StackIterator iter = callFrame->begin();
     644    iter.iterate(functor);
     645    if (!handler)
     646        return 0;
     647
     648    if (LegacyProfiler* profiler = vm.enabledProfiler())
    568649        profiler->exceptionUnwind(callFrame);
    569650
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r154797 r155013  
    263263
    264264        void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
    265         NEVER_INLINE bool unwindCallFrame(StackIterator&, JSValue);
    266265
    267266        void dumpRegisters(CallFrame*);
  • trunk/Source/JavaScriptCore/interpreter/StackIterator.cpp

    r154821 r155013  
    4545size_t StackIterator::numberOfFrames()
    4646{
    47     int savedFrameIndex = m_frameIndex;
     47    int savedFrameIndex = m_frame.index();
    4848    resetIterator();
    4949    while (m_frame.callFrame())
    5050        gotoNextFrameWithFilter();
    51     size_t numberOfFrames = m_frameIndex;
     51    size_t numberOfFrames = m_frame.index();
    5252
    5353    resetIterator();
     
    5959void StackIterator::gotoFrameAtIndex(size_t index)
    6060{
    61     while (m_frame.callFrame() && (m_frameIndex != index))
     61    while (m_frame.callFrame() && (m_frame.index() != index))
    6262        gotoNextFrameWithFilter();
    6363}
     
    8484            break;
    8585    }
    86     m_frameIndex++;
     86    m_frame.m_index++;
    8787}
    8888
    8989void StackIterator::resetIterator()
    9090{
    91     m_frameIndex = 0;
     91    m_frame.m_index = 0;
    9292    readFrame(m_startFrame);
    93 }
    94 
    95 StackIterator StackIterator::end()
    96 {
    97     return StackIterator(0, 0);
    98 }
    99 
    100 void StackIterator::find(JSFunction* functionObj)
    101 {
    102     ASSERT(functionObj);
    103     JSObject* targetCallee = jsDynamicCast<JSObject*>(functionObj);
    104     while (m_frame.callFrame()) {
    105         if (m_frame.callee() == targetCallee)
    106             break;
    107         gotoNextFrameWithFilter();
    108     }
    10993}
    11094
     
    405389    int i = indentLevel;
    406390
     391    if (!this->callFrame()) {
     392        printif(i, "frame 0x0\n");
     393        return;
     394    }
     395
    407396    CodeBlock* codeBlock = this->codeBlock();
    408     printif(i, "frame %p {\n", this);
     397    printif(i, "frame %p {\n", this->callFrame());
    409398
    410399    CallFrame* callFrame = m_callFrame;
     
    461450
    462451#ifndef NDEBUG
     452using JSC::StackIterator;
     453
    463454// For debugging use
    464455void debugPrintCallFrame(JSC::CallFrame*);
     
    469460    if (!callFrame)
    470461        return;
    471     JSC::StackIterator iter = callFrame->begin();
     462    StackIterator iter = callFrame->begin();
    472463    iter->print(2);
    473464}
    474465
     466class DebugPrintStackFunctor {
     467public:
     468    StackIterator::Status operator()(StackIterator& iter)
     469    {
     470        iter->print(2);
     471        return StackIterator::Continue;
     472    }
     473};
     474
    475475void debugPrintStack(JSC::CallFrame* topCallFrame)
    476476{
    477477    if (!topCallFrame)
    478478        return;
    479     JSC::StackIterator iter = topCallFrame->begin();
    480     for (; iter != topCallFrame->end(); ++iter)
    481         iter->print(2);
     479    DebugPrintStackFunctor functor;
     480    StackIterator iter = topCallFrame->begin();
     481    iter.iterate(functor);
    482482}
    483483#endif // !NDEBUG
  • trunk/Source/JavaScriptCore/interpreter/StackIterator.h

    r154827 r155013  
    5454        };
    5555
     56        size_t index() const { return m_index; }
    5657        size_t argumentCountIncludingThis() const { return m_argumentCountIncludingThis; }
    5758        CallFrame* callerFrame() const { return m_callerFrame; }
     
    9091        void setToEnd();
    9192
     93        size_t m_index;
    9294        size_t m_argumentCountIncludingThis;
    9395        CallFrame* m_callerFrame;
     
    107109    typedef bool (*FrameFilter)(Frame*);
    108110
     111    enum Status {
     112        Continue = 0,
     113        Done = 1
     114    };
     115
     116    // StackIterator::iterate() expects a Functor that implements the following method:
     117    //     Status operator()(StackIterator&);
     118
     119    template <typename Functor> void iterate(Functor& functor)
     120    {
     121        while (m_frame.callFrame()) {
     122            Status status = functor(*this);
     123            if (status != Continue)
     124                break;
     125            gotoNextFrameWithFilter();
     126        }
     127    }
     128
    109129    JS_EXPORT_PRIVATE size_t numberOfFrames();
    110130
     
    112132    ALWAYS_INLINE Frame* operator->() { return &m_frame; }
    113133
    114     inline bool operator==(const StackIterator&);
    115     bool operator!=(const StackIterator& other) { return !(*this == other); }
    116     void operator++() { gotoNextFrameWithFilter(); }
    117     void find(JSFunction*);
    118 
    119134private:
    120135    JS_EXPORT_PRIVATE StackIterator(CallFrame* startFrame, FrameFilter = 0);
    121136
    122     JS_EXPORT_PRIVATE static StackIterator end();
    123137    void gotoFrameAtIndex(size_t frameIndex);
    124138    void gotoNextFrame();
     
    133147
    134148    CallFrame* m_startFrame;
    135     size_t m_frameIndex;
    136149    FrameFilter m_filter;
    137150    Frame m_frame;
     
    140153};
    141154
    142 inline bool StackIterator::operator==(const StackIterator& other)
    143 {
    144     return (m_frame.callFrame() == other.m_frame.callFrame())
    145 #if ENABLE(DFG_JIT)
    146         && (m_frame.inlineCallFrame() == other.m_frame.inlineCallFrame())
    147 #endif
    148         ;
    149 }
    150 
    151155} // namespace JSC
    152156
  • trunk/Source/JavaScriptCore/jsc.cpp

    r154797 r155013  
    327327}
    328328
     329class FunctionJSCStackFunctor {
     330public:
     331    FunctionJSCStackFunctor(StringBuilder& trace)
     332        : m_trace(trace)
     333    {
     334    }
     335
     336    StackIterator::Status operator()(StackIterator& iter)
     337    {
     338        m_trace.append(String::format("    %zu   %s\n", iter->index(), iter->toString().utf8().data()));
     339        return StackIterator::Continue;
     340    }
     341
     342private:
     343    StringBuilder& m_trace;
     344};
     345
    329346EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
    330347{
     
    332349    trace.appendLiteral("--> Stack trace:\n");
    333350
    334     int i = 0;
    335     for (StackIterator iter = exec->begin(); iter != exec->end(); ++iter, ++i)
    336         trace.append(String::format("    %i   %s\n", i, iter->toString().utf8().data()));
     351    FunctionJSCStackFunctor functor(trace);
     352    StackIterator iter = exec->begin();
     353    iter.iterate(functor);
    337354    fprintf(stderr, "%s", trace.toString().utf8().data());
    338355    return JSValue::encode(jsUndefined());
  • trunk/Source/JavaScriptCore/profiler/ProfileGenerator.cpp

    r153218 r155013  
    5858}
    5959
     60class AddParentForConsoleStartFunctor {
     61public:
     62    AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& head, RefPtr<ProfileNode>& currentNode)
     63        : m_exec(exec)
     64        , m_hasSkippedFirstFrame(false)
     65        , m_foundParent(false)
     66        , m_head(head)
     67        , m_currentNode(currentNode)
     68    {
     69    }
     70
     71    bool foundParent() const { return m_foundParent; }
     72
     73    StackIterator::Status operator()(StackIterator& iter)
     74    {
     75        if (!m_hasSkippedFirstFrame) {
     76            m_hasSkippedFirstFrame = true;
     77            return StackIterator::Continue;
     78        }
     79
     80        unsigned line = 0;
     81        unsigned unusedColumn = 0;
     82        iter->computeLineAndColumn(line, unusedColumn);
     83        m_currentNode = ProfileNode::create(m_exec, LegacyProfiler::createCallIdentifier(m_exec, iter->callee(), iter->sourceURL(), line), m_head.get(), m_head.get());
     84        m_head->insertNode(m_currentNode.get());
     85
     86        m_foundParent = true;
     87        return StackIterator::Done;
     88    }
     89
     90private:
     91    ExecState* m_exec;
     92    bool m_hasSkippedFirstFrame;
     93    bool m_foundParent;
     94    RefPtr<ProfileNode>& m_head;
     95    RefPtr<ProfileNode>& m_currentNode;
     96};
     97
    6098void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
    6199{
     100    AddParentForConsoleStartFunctor functor(exec, m_head, m_currentNode);
    62101    StackIterator iter = exec->begin();
    63     ++iter;
    64     if (iter == exec->end()) {
     102    iter.iterate(functor);
     103
     104    if (!functor.foundParent()) {
    65105        m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, JSValue(), String(), 0), m_head.get(), m_head.get());
    66106        m_head->insertNode(m_currentNode.get());
    67         return;
    68     }
    69     unsigned line = 0;
    70     unsigned unusedColumn = 0;
    71     iter->computeLineAndColumn(line, unusedColumn);
    72     m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, iter->callee(), iter->sourceURL(), line), m_head.get(), m_head.get());
    73     m_head->insertNode(m_currentNode.get());
     107    }
    74108}
    75109
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r154797 r155013  
    183183}
    184184
     185class RetrieveArgumentsFunctor {
     186public:
     187    RetrieveArgumentsFunctor(JSFunction* functionObj)
     188        : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
     189        , m_result(jsNull())
     190    {
     191    }
     192
     193    JSValue result() const { return m_result; }
     194
     195    StackIterator::Status operator()(StackIterator& iter)
     196    {
     197        JSObject* callee = iter->callee();
     198        if (callee != m_targetCallee)
     199            return StackIterator::Continue;
     200
     201        m_result = JSValue(iter->arguments());
     202        return StackIterator::Done;
     203    }
     204
     205private:
     206    JSObject* m_targetCallee;
     207    JSValue m_result;
     208};
     209
    185210static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj)
    186211{
    187     StackIterator iter = exec->find(functionObj);
    188     return iter != exec->end() ? JSValue(iter->arguments()) : jsNull();
     212    RetrieveArgumentsFunctor functor(functionObj);
     213    StackIterator iter = exec->begin();
     214    iter.iterate(functor);
     215    return functor.result();
    189216}
    190217
     
    204231}
    205232
     233class RetrieveCallerFunctionFunctor {
     234public:
     235    RetrieveCallerFunctionFunctor(JSFunction* functionObj)
     236        : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
     237        , m_hasFoundFrame(false)
     238        , m_hasSkippedToCallerFrame(false)
     239        , m_result(jsNull())
     240    {
     241    }
     242
     243    JSValue result() const { return m_result; }
     244
     245    StackIterator::Status operator()(StackIterator& iter)
     246    {
     247        JSObject* callee = iter->callee();
     248        if (!m_hasFoundFrame && (callee != m_targetCallee))
     249            return StackIterator::Continue;
     250
     251        m_hasFoundFrame = true;
     252        if (!m_hasSkippedToCallerFrame) {
     253            m_hasSkippedToCallerFrame = true;
     254            return StackIterator::Continue;
     255        }
     256
     257        if (callee)
     258            m_result = callee;
     259        return StackIterator::Done;
     260    }
     261
     262private:
     263    JSObject* m_targetCallee;
     264    bool m_hasFoundFrame;
     265    bool m_hasSkippedToCallerFrame;
     266    JSValue m_result;
     267};
     268
    206269static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj)
    207270{
    208     StackIterator iter = exec->find(functionObj, skipOverBoundFunctions);
    209     if (iter != exec->end())
    210         ++iter;
    211     return iter != exec->end() && iter->callee() ? iter->callee() : jsNull();
     271    RetrieveCallerFunctionFunctor functor(functionObj);
     272    StackIterator iter = exec->begin(skipOverBoundFunctions);
     273    iter.iterate(functor);
     274    return functor.result();
    212275}
    213276
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r154902 r155013  
    707707}
    708708
     709class GlobalFuncProtoGetterFunctor {
     710public:
     711    GlobalFuncProtoGetterFunctor(JSObject* thisObject)
     712        : m_hasSkippedFirstFrame(false)
     713        , m_thisObject(thisObject)
     714        , m_result(JSValue::encode(jsUndefined()))
     715    {
     716    }
     717
     718    EncodedJSValue result() { return m_result; }
     719
     720    StackIterator::Status operator()(StackIterator& iter)
     721    {
     722        if (!m_hasSkippedFirstFrame) {
     723            m_hasSkippedFirstFrame = true;
     724            return StackIterator::Continue;
     725        }
     726
     727        if (m_thisObject->allowsAccessFrom(iter->callFrame()))
     728            m_result = JSValue::encode(m_thisObject->prototype());
     729
     730        return StackIterator::Done;
     731    }
     732
     733private:
     734    bool m_hasSkippedFirstFrame;
     735    JSObject* m_thisObject;
     736    EncodedJSValue m_result;
     737};
     738
    709739EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
    710740{
     
    714744        return JSValue::encode(exec->thisValue().synthesizePrototype(exec));
    715745
     746    GlobalFuncProtoGetterFunctor functor(thisObject);
    716747    StackIterator iter = exec->begin();
    717     ++iter;
    718     if ((iter == exec->end()) || !thisObject->allowsAccessFrom(iter->callFrame()))
    719         return JSValue::encode(jsUndefined());
    720 
    721     return JSValue::encode(thisObject->prototype());
    722 }
     748    iter.iterate(functor);
     749    return functor.result();
     750}
     751
     752class GlobalFuncProtoSetterFunctor {
     753public:
     754    GlobalFuncProtoSetterFunctor(JSObject* thisObject)
     755        : m_hasSkippedFirstFrame(false)
     756        , m_allowsAccess(false)
     757        , m_thisObject(thisObject)
     758    {
     759    }
     760
     761    bool allowsAccess() const { return m_allowsAccess; }
     762
     763    StackIterator::Status operator()(StackIterator& iter)
     764    {
     765        if (!m_hasSkippedFirstFrame) {
     766            m_hasSkippedFirstFrame = true;
     767            return StackIterator::Continue;
     768        }
     769
     770        m_allowsAccess = m_thisObject->allowsAccessFrom(iter->callFrame());
     771        return StackIterator::Done;
     772    }
     773
     774private:
     775    bool m_hasSkippedFirstFrame;
     776    bool m_allowsAccess;
     777    JSObject* m_thisObject;
     778};
    723779
    724780EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
     
    732788        return JSValue::encode(jsUndefined());
    733789
     790    GlobalFuncProtoSetterFunctor functor(thisObject);
    734791    StackIterator iter = exec->begin();
    735     ++iter;
    736     if ((iter == exec->end()) || !thisObject->allowsAccessFrom(iter->callFrame()))
     792    iter.iterate(functor);
     793    if (!functor.allowsAccess())
    737794        return JSValue::encode(jsUndefined());
    738795
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r154797 r155013  
    132132}
    133133
     134class ObjectConstructorGetPrototypeOfFunctor {
     135public:
     136    ObjectConstructorGetPrototypeOfFunctor(JSObject* object)
     137        : m_hasSkippedFirstFrame(false)
     138        , m_object(object)
     139        , m_result(JSValue::encode(jsUndefined()))
     140    {
     141    }
     142
     143    EncodedJSValue result() const { return m_result; }
     144
     145    StackIterator::Status operator()(StackIterator& iter)
     146    {
     147        if (!m_hasSkippedFirstFrame) {
     148            m_hasSkippedFirstFrame = true;
     149            return StackIterator::Continue;
     150        }
     151
     152    if (m_object->allowsAccessFrom(iter->callFrame()))
     153        m_result = JSValue::encode(m_object->prototype());
     154    return StackIterator::Done;
     155}
     156
     157private:
     158    bool m_hasSkippedFirstFrame;
     159    JSObject* m_object;
     160    EncodedJSValue m_result;
     161};
     162
    134163EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
    135164{
     
    137166        return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested prototype of a value that is not an object.")));
    138167    JSObject* object = asObject(exec->argument(0));
     168    ObjectConstructorGetPrototypeOfFunctor functor(object);
    139169    StackIterator iter = exec->begin();
    140     ++iter;
    141     if ((iter == exec->end()) || !object->allowsAccessFrom(iter->callFrame()))
    142         return JSValue::encode(jsUndefined());
    143     return JSValue::encode(object->prototype());
     170    iter.iterate(functor);
     171    return functor.result();
    144172}
    145173
  • trunk/Source/WebCore/ChangeLog

    r155008 r155013  
     12013-09-03  Mark Lam  <mark.lam@apple.com>
     2
     3        Converting StackIterator to a callback interface.
     4        https://bugs.webkit.org/show_bug.cgi?id=120564.
     5
     6        Reviewed by Filip Pizlo.
     7
     8        No new tests.
     9
     10        * bindings/js/JSXMLHttpRequestCustom.cpp:
     11        (WebCore::SendFunctor::SendFunctor):
     12        (WebCore::SendFunctor::hasViableFrame):
     13        (WebCore::SendFunctor::operator()):
     14        (WebCore::JSXMLHttpRequest::send):
     15        * bindings/js/ScriptCallStackFactory.cpp:
     16        (WebCore::CreateScriptCallStackFunctor::CreateScriptCallStackFunctor):
     17        (WebCore::CreateScriptCallStackFunctor::operator()):
     18        (WebCore::createScriptCallStack):
     19        (WebCore::CreateScriptCallStackForConsoleFunctor::CreateScriptCallStackForConsoleFunctor):
     20        (WebCore::CreateScriptCallStackForConsoleFunctor::operator()):
     21
    1222013-09-03  Oliver Hunt  <oliver@apple.com>
    223
     
    32973318        (WebCore::findDropZone):
    32983319
    3299 <<<<<<< .mine
    330033202013-08-28  Benjamin Poulain  <benjamin@webkit.org>
    33013321
     
    33433363        (WebCore::findDropZone):
    33443364
    3345 =======
    334633652013-08-28  Rob Buis  <rwlbuis@webkit.org>
    33473366
     
    34263445        (WebCore::AXSearchFieldCancelButtonText):
    34273446
    3428 >>>>>>> .r154779
    342934472013-08-28  Eric Carlson  <eric.carlson@apple.com>
    34303448
  • trunk/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp

    r154992 r155013  
    113113}
    114114
     115class SendFunctor {
     116public:
     117    SendFunctor()
     118        : m_hasSkippedFirstFrame(false)
     119        , m_hasViableFrame(false)
     120    {
     121    }
     122
     123    bool hasViableFrame() const { return m_hasViableFrame; }
     124
     125    StackIterator::Status operator()(StackIterator&)
     126    {
     127        if (!m_hasSkippedFirstFrame) {
     128            m_hasSkippedFirstFrame = true;
     129            return StackIterator::Continue;
     130        }
     131
     132        m_hasViableFrame = true;
     133        return StackIterator::Done;
     134    }
     135
     136private:
     137    bool m_hasSkippedFirstFrame;
     138    bool m_hasViableFrame;
     139};
     140
    115141JSValue JSXMLHttpRequest::send(ExecState* exec)
    116142{
     
    139165    }
    140166
     167    SendFunctor functor;
    141168    StackIterator iter = exec->begin();
    142     ++iter;
    143     if (iter != exec->end()) {
     169    iter.iterate(functor);
     170    if (functor.hasViableFrame()) {
    144171        unsigned line = 0;
    145172        unsigned unusuedColumn = 0;
  • trunk/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp

    r154797 r155013  
    5555class ScriptExecutionContext;
    5656
     57class CreateScriptCallStackFunctor {
     58public:
     59    CreateScriptCallStackFunctor(Vector<ScriptCallFrame>& frames,  size_t remainingCapacity)
     60        : m_frames(frames)
     61        , m_remainingCapacityForFrameCapture(remainingCapacity)
     62    {
     63    }
     64
     65    StackIterator::Status operator()(StackIterator& iter)
     66    {
     67        if (m_remainingCapacityForFrameCapture) {
     68            unsigned line;
     69            unsigned column;
     70            iter->computeLineAndColumn(line, column);
     71            m_frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
     72
     73            m_remainingCapacityForFrameCapture--;
     74            return StackIterator::Continue;
     75        }
     76        return StackIterator::Done;
     77    }
     78
     79private:
     80    Vector<ScriptCallFrame>& m_frames;
     81    size_t m_remainingCapacityForFrameCapture;
     82};
     83
    5784PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed)
    5885{
     
    6087    if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
    6188        CallFrame* frame = exec->vm().topCallFrame;
    62         for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter) {
    63             unsigned line;
    64             unsigned column;
    65             iter->computeLineAndColumn(line, column);
    66             frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
    67         }
     89        CreateScriptCallStackFunctor functor(frames, maxStackSize);
     90        StackIterator iter = frame->begin();
     91        iter.iterate(functor);
    6892    }
    6993    if (frames.isEmpty() && !emptyIsAllowed) {
     
    76100}
    77101
     102class CreateScriptCallStackForConsoleFunctor {
     103public:
     104    CreateScriptCallStackForConsoleFunctor(bool needToSkipAFrame,  size_t remainingCapacity, Vector<ScriptCallFrame>& frames)
     105        : m_needToSkipAFrame(needToSkipAFrame)
     106        , m_remainingCapacityForFrameCapture(remainingCapacity)
     107        , m_frames(frames)
     108    {
     109    }
     110
     111    StackIterator::Status operator()(StackIterator& iter)
     112    {
     113        if (m_needToSkipAFrame) {
     114            m_needToSkipAFrame = false;
     115            return StackIterator::Continue;
     116        }
     117
     118        if (m_remainingCapacityForFrameCapture) {
     119            // This early exit is necessary to maintain our old behaviour
     120            // but the stack trace we produce now is complete and handles all
     121            // ways in which code may be running
     122            if (!iter->callee() && m_frames.size())
     123                return StackIterator::Done;
     124
     125            unsigned line;
     126            unsigned column;
     127            iter->computeLineAndColumn(line, column);
     128            m_frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
     129
     130            m_remainingCapacityForFrameCapture--;
     131            return StackIterator::Continue;
     132        }
     133        return StackIterator::Done;
     134    }
     135
     136private:
     137    bool m_needToSkipAFrame;
     138    size_t m_remainingCapacityForFrameCapture;
     139    Vector<ScriptCallFrame>& m_frames;
     140};
     141
    78142PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
    79143{
     
    82146    CallFrame* frame = exec->vm().topCallFrame;
    83147    StackIterator iter = frame->begin();
    84     if (iter.numberOfFrames() > 1)
    85         ++iter;
    86     for (; iter != frame->end() && maxStackSize--; ++iter) {
    87         // This early exit is necessary to maintain our old behaviour
    88         // but the stack trace we produce now is complete and handles all
    89         // ways in which code may be running
    90         if (!iter->callee() && frames.size())
    91             break;
    92         unsigned line;
    93         unsigned column;
    94         iter->computeLineAndColumn(line, column);
    95         frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
    96     }
     148    size_t numberOfFrames = iter.numberOfFrames();
     149    CreateScriptCallStackForConsoleFunctor functor(numberOfFrames > 1, maxStackSize, frames);
     150    iter.iterate(functor);
    97151    return ScriptCallStack::create(frames);
    98152}
Note: See TracChangeset for help on using the changeset viewer.