Changeset 132143 in webkit


Ignore:
Timestamp:
Oct 22, 2012 3:09:58 PM (12 years ago)
Author:
mark.lam@apple.com
Message:

Change stack recursion checks to be based on stack availability.
https://bugs.webkit.org/show_bug.cgi?id=99872.

Reviewed by Filip Pizlo and Geoffrey Garen.

Source/JavaScriptCore:

  • Remove m_reentryDepth, ThreadStackType which are now obsolete.
  • Replaced the reentryDepth checks with a StackBounds check.
  • Added the Interpreter::StackPolicy class to compute a reasonable stack capacity requirement given the native stack that the interpreter is executing on at that time.
  • Reserved an amount of JSStack space for the use of error handling and enable its use (using Interpreter::ErrorHandlingMode) when we're about to throw or report an exception.
  • Interpreter::StackPolicy also allows more native stack space to be used when in ErrorHandlingMode. This is needed in the case of native stack overflows.
  • Fixed the parser so that it throws a StackOverflowError instead of a SyntaxError when it encounters a stack overflow.
  • API/JSContextRef.cpp:

(JSContextGroupCreate):
(JSGlobalContextCreateInGroup):

(JSC::Interpreter::ErrorHandlingMode::ErrorHandlingMode):
(JSC):
(JSC::Interpreter::ErrorHandlingMode::~ErrorHandlingMode):
(JSC::Interpreter::StackPolicy::StackPolicy):
(JSC::Interpreter::Interpreter):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):

  • interpreter/Interpreter.h:

(JSC):
(Interpreter):
(ErrorHandlingMode):
(StackPolicy):
(JSC::Interpreter::StackPolicy::requiredCapacity):

  • interpreter/JSStack.cpp:

(JSC):
(JSC::JSStack::JSStack):
(JSC::JSStack::growSlowCase):
(JSC::JSStack::enableErrorStackReserve):
(JSC::JSStack::disableErrorStackReserve):

  • interpreter/JSStack.h:

(JSStack):
(JSC::JSStack::reservationEnd):
(JSC):

  • jsc.cpp:

(jscmain):

  • parser/Parser.cpp:

(JSC::::Parser):

  • parser/Parser.h:

(Parser):
(JSC::::parse):

  • runtime/ExceptionHelpers.cpp:

(JSC::throwStackOverflowError):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::createContextGroup):
(JSC::JSGlobalData::create):
(JSC::JSGlobalData::createLeaked):
(JSC::JSGlobalData::sharedInstance):

  • runtime/JSGlobalData.h:

(JSC):
(JSGlobalData):

  • runtime/StringRecursionChecker.h:

(JSC::StringRecursionChecker::performCheck):

  • testRegExp.cpp:

(realMain):

Source/WebCore:

Removed the use of ThreadStackType. Enabled the reserved JSStack space
for error processing before doing work in reportException().

  • bindings/js/JSDOMBinding.cpp:

(WebCore::reportException):

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::commonJSGlobalData):

  • bindings/js/WorkerScriptController.cpp:

(WebCore::WorkerScriptController::WorkerScriptController):

LayoutTests:

Updated test baseline.

  • fast/js/global-recursion-on-full-stack-expected.txt:
  • fast/xmlhttprequest/xmlhttprequest-recursive-sync-event-expected.txt:
Location:
trunk
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r132141 r132143  
     12012-10-22  Mark Lam  <mark.lam@apple.com>
     2
     3        Change stack recursion checks to be based on stack availability.
     4        https://bugs.webkit.org/show_bug.cgi?id=99872.
     5
     6        Reviewed by Filip Pizlo and Geoffrey Garen.
     7
     8        Updated test baseline.
     9
     10        * fast/js/global-recursion-on-full-stack-expected.txt:
     11        * fast/xmlhttprequest/xmlhttprequest-recursive-sync-event-expected.txt:
     12
    1132012-10-22  Andreas Kling  <kling@webkit.org>
    214
  • trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt

    r115861 r132143  
    1 CONSOLE MESSAGE:
     1CONSOLE MESSAGE: RangeError: Maximum call stack size exceeded.
    22This tests global code recursion when the JS stack is full.
    33PASS: Entering global code with a full JS stack did not crash, and did not allow continued recursion.
  • trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-recursive-sync-event-expected.txt

    r104810 r132143  
    1 CONSOLE MESSAGE:
    2 CONSOLE MESSAGE:
     1CONSOLE MESSAGE: RangeError: Maximum call stack size exceeded.
    32This tests that having infinite recursion in XMLHttpRequest event handler does not crash.
    43PASS
  • trunk/Source/JavaScriptCore/API/JSContextRef.cpp

    r128091 r132143  
    5555{
    5656    initializeThreading();
    57     return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).leakRef());
     57    return toRef(JSGlobalData::createContextGroup().leakRef());
    5858}
    5959
     
    9090    initializeThreading();
    9191
    92     RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup(ThreadStackTypeSmall);
     92    RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup();
    9393
    9494    APIEntryShim entryShim(globalData.get(), false);
  • trunk/Source/JavaScriptCore/ChangeLog

    r131997 r132143  
     12012-10-22  Mark Lam  <mark.lam@apple.com>
     2
     3        Change stack recursion checks to be based on stack availability.
     4        https://bugs.webkit.org/show_bug.cgi?id=99872.
     5
     6        Reviewed by Filip Pizlo and Geoffrey Garen.
     7
     8        - Remove m_reentryDepth, ThreadStackType which are now obsolete.
     9        - Replaced the reentryDepth checks with a StackBounds check.
     10        - Added the Interpreter::StackPolicy class to compute a reasonable
     11          stack capacity requirement given the native stack that the
     12          interpreter is executing on at that time.
     13        - Reserved an amount of JSStack space for the use of error handling
     14          and enable its use (using Interpreter::ErrorHandlingMode) when
     15          we're about to throw or report an exception.
     16        - Interpreter::StackPolicy also allows more native stack space
     17          to be used when in ErrorHandlingMode. This is needed in the case
     18          of native stack overflows.
     19        - Fixed the parser so that it throws a StackOverflowError instead of
     20          a SyntaxError when it encounters a stack overflow.
     21
     22        * API/JSContextRef.cpp:
     23        (JSContextGroupCreate):
     24        (JSGlobalContextCreateInGroup):
     25        * JavaScriptCore.order:
     26        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
     27        * interpreter/Interpreter.cpp:
     28        (JSC::Interpreter::ErrorHandlingMode::ErrorHandlingMode):
     29        (JSC):
     30        (JSC::Interpreter::ErrorHandlingMode::~ErrorHandlingMode):
     31        (JSC::Interpreter::StackPolicy::StackPolicy):
     32        (JSC::Interpreter::Interpreter):
     33        (JSC::Interpreter::execute):
     34        (JSC::Interpreter::executeCall):
     35        (JSC::Interpreter::executeConstruct):
     36        (JSC::Interpreter::prepareForRepeatCall):
     37        * interpreter/Interpreter.h:
     38        (JSC):
     39        (Interpreter):
     40        (ErrorHandlingMode):
     41        (StackPolicy):
     42        (JSC::Interpreter::StackPolicy::requiredCapacity):
     43        * interpreter/JSStack.cpp:
     44        (JSC):
     45        (JSC::JSStack::JSStack):
     46        (JSC::JSStack::growSlowCase):
     47        (JSC::JSStack::enableErrorStackReserve):
     48        (JSC::JSStack::disableErrorStackReserve):
     49        * interpreter/JSStack.h:
     50        (JSStack):
     51        (JSC::JSStack::reservationEnd):
     52        (JSC):
     53        * jsc.cpp:
     54        (jscmain):
     55        * parser/Parser.cpp:
     56        (JSC::::Parser):
     57        * parser/Parser.h:
     58        (Parser):
     59        (JSC::::parse):
     60        * runtime/ExceptionHelpers.cpp:
     61        (JSC::throwStackOverflowError):
     62        * runtime/JSGlobalData.cpp:
     63        (JSC::JSGlobalData::JSGlobalData):
     64        (JSC::JSGlobalData::createContextGroup):
     65        (JSC::JSGlobalData::create):
     66        (JSC::JSGlobalData::createLeaked):
     67        (JSC::JSGlobalData::sharedInstance):
     68        * runtime/JSGlobalData.h:
     69        (JSC):
     70        (JSGlobalData):
     71        * runtime/StringRecursionChecker.h:
     72        (JSC::StringRecursionChecker::performCheck):
     73        * testRegExp.cpp:
     74        (realMain):
     75
    1762012-10-20  Martin Robinson  <mrobinson@igalia.com>
    277
  • trunk/Source/JavaScriptCore/JavaScriptCore.order

    r131225 r132143  
    121121__ZN3JSCL17createJSLockCountEv
    122122__ZN3JSC12JSGlobalData14sharedInstanceEv
    123 __ZN3JSC12JSGlobalDataC2ENS0_14GlobalDataTypeENS_15ThreadStackTypeE
     123__ZN3JSC12JSGlobalDataC2ENS0_14GlobalDataTypeENS_8HeapTypeE
    124124__ZN3JSC21createIdentifierTableEv
    125125__ZN3JSC17CommonIdentifiersC1EPNS_12JSGlobalDataE
     
    441441__ZN3WTF10StringImpl11reverseFindEPS0_j
    442442__ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_
    443 __ZN3JSC12JSGlobalData12createLeakedENS_15ThreadStackTypeE
     443__ZN3JSC12JSGlobalData12createLeakedENS_8HeapTypeE
    444444__ZN3JSC24JSObjectWithGlobalObjectC2ERNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureE
    445445__ZN3JSC8evaluateEPNS_9ExecStateEPNS_14ScopeChainNodeERKNS_10SourceCodeENS_7JSValueE
     
    17081708__ZN3JSCL21arrayProtoFuncReverseEPNS_9ExecStateE
    17091709__ZN3JSC17ProgramExecutable13visitChildrenERNS_9MarkStackE
    1710 __ZN3JSC12JSGlobalData18createContextGroupENS_15ThreadStackTypeE
     1710__ZN3JSC12JSGlobalData18createContextGroupENS_8HeapTypeE
    17111711__ZN3JSC12JSGlobalData22clearBuiltinStructuresEv
    17121712__ZN3JSC4Heap7destroyEv
     
    18431843__ZN3JSC8JSObject15unwrappedObjectEv
    18441844__ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE
    1845 __ZN3JSC12JSGlobalData6createENS_15ThreadStackTypeE
     1845__ZN3JSC12JSGlobalData6createENS_8HeapTypeE
    18461846__ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_10JSFunctionEj
    18471847__ZN3JSC12JSGlobalData13startSamplingEv
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r131882 r132143  
    1111    ??0DropAllLocks@JSLock@JSC@@QAE@PAVJSGlobalData@2@@Z
    1212    ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z
     13    ??0ErrorHandlingMode@Interpreter@JSC@@QAE@PAVExecState@2@@Z
     14    ??1ErrorHandlingMode@Interpreter@JSC@@QAE@XZ
    1315    ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z
    1416    ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z
     
    119121    ?copyBackingStore@JSObject@JSC@@SAXPAVJSCell@2@AAVCopyVisitor@2@@Z
    120122    ?create@JSFunction@JSC@@SAPAV12@PAVExecState@2@PAVJSGlobalObject@2@HABVString@WTF@@P6I_J0@ZW4Intrinsic@2@3@Z
    121     ?create@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4ThreadStackType@2@W4HeapType@2@@Z
     123    ?create@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4HeapType@2@@Z
    122124    ?create@OpaqueJSString@@SA?AV?$PassRefPtr@UOpaqueJSString@@@WTF@@ABVString@3@@Z
    123125    ?create@RegExp@JSC@@SAPAV12@AAVJSGlobalData@2@ABVString@WTF@@W4RegExpFlags@2@@Z
     
    125127    ?createError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVString@WTF@@@Z
    126128    ?createInterruptedExecutionException@JSC@@YAPAVJSObject@1@PAVJSGlobalData@1@@Z
    127     ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4ThreadStackType@2@W4HeapType@2@@Z
     129    ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4HeapType@2@@Z
    128130    ?createNotEnoughArgumentsError@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z
    129131    ?createRangeError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVString@WTF@@@Z
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r131938 r132143  
    6868#include <wtf/StackStats.h>
    6969#include <wtf/Threading.h>
     70#include <wtf/WTFThreadData.h>
    7071#include <wtf/text/StringBuilder.h>
    7172
     
    7980
    8081namespace JSC {
     82
     83Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState *exec)
     84    : m_interpreter(*exec->interpreter())
     85{
     86    if (!m_interpreter.m_errorHandlingModeReentry)
     87        m_interpreter.stack().enableErrorStackReserve();
     88    m_interpreter.m_errorHandlingModeReentry++;
     89}
     90
     91Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
     92{
     93    m_interpreter.m_errorHandlingModeReentry--;
     94    ASSERT(m_interpreter.m_errorHandlingModeReentry >= 0);
     95    if (!m_interpreter.m_errorHandlingModeReentry)
     96        m_interpreter.stack().disableErrorStackReserve();
     97}
     98
     99
     100// The Interpreter::StackPolicy class is used to compute a stack capacity
     101// requirement to ensure that we have enough room on the native stack for:
     102// 1. the max cummulative stack used by the interpreter and all code
     103//    paths sub of it up till leaf functions.
     104// 2. the max cummulative stack used by the interpreter before it reaches
     105//    the next checkpoint (execute...() function) in the interpreter.
     106//
     107// The interpreter can be run on different threads and hence, different
     108// native stacks (with different sizes) before exiting out of the first
     109// frame. Hence, the required capacity needs to be re-computed on every
     110// entry into the interpreter.
     111//
     112// Currently the requiredStack is computed based on a policy. See comments
     113// in StackPolicy::StackPolicy() for details.
     114
     115Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBounds& stack)
     116    : m_interpreter(interpreter)
     117{
     118    int size = stack.size();
     119
     120    const int DEFAULT_REQUIRED_STACK = 1024 * 1024;
     121    const int DEFAULT_MINIMUM_USEABLE_STACK = 128 * 1024;
     122    const int DEFAULT_ERROR_MODE_REQUIRED_STACK = 32 * 1024;
     123
     124    // Here's the policy in a nutshell:
     125    //
     126    // 1. If we have a large stack, let JS use as much stack as possible
     127    //    but require that we have at least DEFAULT_REQUIRED_STACK capacity
     128    //    remaining on the stack:
     129    //
     130    //    stack grows this way -->   
     131    //    ---------------------------------------------------------
     132    //    |         ... | <-- DEFAULT_REQUIRED_STACK --> | ...
     133    //    ---------------------------------------------------------
     134    //    ^             ^
     135    //    start         current sp
     136    //
     137    // 2. In event that we're re-entering the interpreter to handle
     138    //    exceptions (in error mode), we'll be a little more generous and
     139    //    require less stack capacity for the interpreter to be re-entered.
     140    //
     141    //    This is needed because we may have just detected an eminent stack
     142    //    overflow based on the normally computed required stack capacity.
     143    //    However, the normal required capacity far exceeds what is needed
     144    //    for exception handling work. Hence, in error mode, we only require
     145    //    DEFAULT_ERROR_MODE_REQUIRED_STACK capacity.
     146    //
     147    //    stack grows this way -->   
     148    //    -----------------------------------------------------------------
     149    //    |         ... | <-- DEFAULT_ERROR_MODE_REQUIRED_STACK --> | ...
     150    //    -----------------------------------------------------------------
     151    //    ^             ^
     152    //    start         current sp
     153    //
     154    //    This smaller requried capacity also means that we won't re-trigger
     155    //    a stack overflow for processing the exception caused by the original
     156    //    StackOverflowError.
     157    //
     158    // 3. If the stack is not large enough, give JS at least a minimum
     159    //    amount of useable stack:
     160    //
     161    //    stack grows this way -->   
     162    //    --------------------------------------------------------------------
     163    //    | <-- DEFAULT_MINIMUM_USEABLE_STACK --> | <-- requiredCapacity --> |
     164    //    --------------------------------------------------------------------
     165    //    ^             ^
     166    //    start         current sp
     167    //
     168    //    The minimum useable capacity is DEFAULT_MINIMUM_USEABLE_STACK.
     169    //    In this case, the requiredCapacity is whatever is left of the
     170    //    total stack capacity after we have give JS its minimum stack
     171    //    i.e. requiredCapcity can even be 0 if there's not enough stack.
     172
     173
     174    // Policy 1: Normal mode: required = DEFAULT_REQUIRED_STACK.
     175    // Policy 2: Erro mode: required = DEFAULT_ERROR_MODE_REQUIRED_STACK.
     176    int requiredCapacity = !m_interpreter.m_errorHandlingModeReentry ?
     177        DEFAULT_REQUIRED_STACK : DEFAULT_ERROR_MODE_REQUIRED_STACK;
     178
     179    int useableStack = size - requiredCapacity;
     180
     181    // Policy 3: Ensure the useable stack is not too small:
     182    if (useableStack < DEFAULT_MINIMUM_USEABLE_STACK)
     183        useableStack = DEFAULT_MINIMUM_USEABLE_STACK;
     184
     185    // Sanity check: Make sure we do not use more space than the stack's
     186    // total capacity:
     187    if (useableStack > size)
     188        useableStack = size;
     189
     190    // Re-compute the requiredCapacity based on the adjusted useable stack
     191    // size:
     192    // interpreter stack checks:
     193    requiredCapacity = size - useableStack;
     194    ASSERT((requiredCapacity >= 0) && (requiredCapacity < size));
     195
     196    m_requiredCapacity = requiredCapacity;   
     197}
     198
    81199
    82200static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset);
     
    248366Interpreter::Interpreter()
    249367    : m_sampleEntryDepth(0)
    250     , m_reentryDepth(0)
     368    , m_errorHandlingModeReentry(0)
    251369#if !ASSERT_DISABLED
    252370    , m_initialized(false)
     
    755873
    756874    StackStats::CheckPoint stackCheckPoint;
    757     if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
     875    const StackBounds& nativeStack = wtfThreadData().stack();
     876    StackPolicy policy(*this, nativeStack);
     877    if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
    758878        return checkedReturn(throwStackOverflowError(callFrame));
    759879
     
    8911011        SamplingTool::CallRecord callRecord(m_sampler.get());
    8921012
    893         m_reentryDepth++;
    8941013#if ENABLE(LLINT_C_LOOP)
    8951014        result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue);
     
    8971016        result = program->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData());
    8981017#endif // ENABLE(JIT)
    899 
    900         m_reentryDepth--;
    9011018    }
    9021019
     
    9181035
    9191036    StackStats::CheckPoint stackCheckPoint;
    920     if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
     1037    const StackBounds& nativeStack = wtfThreadData().stack();
     1038    StackPolicy policy(*this, nativeStack);
     1039    if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
    9211040        return checkedReturn(throwStackOverflowError(callFrame));
    9221041
     
    9631082            SamplingTool::CallRecord callRecord(m_sampler.get());
    9641083
    965             m_reentryDepth++; 
    9661084#if ENABLE(LLINT_C_LOOP)
    9671085            result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue);
     
    9691087            result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_stack, newCallFrame, callDataScope->globalData());
    9701088#endif // ENABLE(JIT)
    971 
    972             m_reentryDepth--;
    9731089        }
    9741090
     
    10141130
    10151131    StackStats::CheckPoint stackCheckPoint;
    1016     if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
     1132    const StackBounds& nativeStack = wtfThreadData().stack();
     1133    StackPolicy policy(*this, nativeStack);
     1134    if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
    10171135        return checkedReturn(throwStackOverflowError(callFrame));
    10181136
     
    10581176            SamplingTool::CallRecord callRecord(m_sampler.get());
    10591177
    1060             m_reentryDepth++; 
    10611178#if ENABLE(LLINT_C_LOOP)
    10621179            result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue);
     
    10641181            result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, constructDataScope->globalData());
    10651182#endif // ENABLE(JIT)
    1066             m_reentryDepth--;
    10671183        }
    10681184
     
    11121228
    11131229    StackStats::CheckPoint stackCheckPoint;
    1114     if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
     1230    const StackBounds& nativeStack = wtfThreadData().stack();
     1231    StackPolicy policy(*this, nativeStack);
     1232    if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) {
    11151233        throwStackOverflowError(callFrame);
    11161234        return CallFrameClosure();
     
    11651283        SamplingTool::CallRecord callRecord(m_sampler.get());
    11661284       
    1167         m_reentryDepth++; 
    11681285#if ENABLE(LLINT_C_LOOP)
    11691286        result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue);
     
    11711288        result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, closure.globalData);
    11721289#endif // ENABLE(JIT)
    1173         m_reentryDepth--;
    11741290    }
    11751291
     
    11981314
    11991315    StackStats::CheckPoint stackCheckPoint;
    1200     if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
     1316    const StackBounds& nativeStack = wtfThreadData().stack();
     1317    StackPolicy policy(*this, nativeStack);
     1318    if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
    12011319        return checkedReturn(throwStackOverflowError(callFrame));
    12021320
     
    12591377    {
    12601378        SamplingTool::CallRecord callRecord(m_sampler.get());
    1261 
    1262         m_reentryDepth++;
    12631379       
    12641380#if ENABLE(LLINT_C_LOOP)
     
    12671383        result = eval->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData());
    12681384#endif // ENABLE(JIT)
    1269         m_reentryDepth--;
    12701385    }
    12711386
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r130726 r132143  
    171171    };
    172172
    173     // We use a smaller reentrancy limit on iPhone because of the high amount of
    174     // stack space required on the web thread.
    175 #if PLATFORM(IOS)
    176     enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 };
    177 #else
    178     enum { MaxLargeThreadReentryDepth = 256, MaxSmallThreadReentryDepth = 16 };
    179 #endif // PLATFORM(IOS)
    180 
    181173    class Interpreter {
    182174        WTF_MAKE_FAST_ALLOCATED;
     
    184176        friend class LLIntOffsetsExtractor;
    185177        friend class JIT;
     178
    186179    public:
     180        class ErrorHandlingMode {
     181        public:
     182            JS_EXPORT_PRIVATE ErrorHandlingMode(ExecState*);
     183            JS_EXPORT_PRIVATE ~ErrorHandlingMode();
     184        private:
     185            Interpreter& m_interpreter;
     186        };
     187
    187188        Interpreter();
    188189        ~Interpreter();
     
    242243
    243244    private:
     245        class StackPolicy {
     246        public:
     247            StackPolicy(Interpreter&, const StackBounds&);
     248            inline size_t requiredCapacity() { return m_requiredCapacity; }
     249
     250        private:
     251            Interpreter& m_interpreter;
     252            size_t m_requiredCapacity;
     253        };
     254
    244255        enum ExecutionFlag { Normal, InitializeAndReturn };
    245256
     
    262273        OwnPtr<SamplingTool> m_sampler;
    263274
    264         int m_reentryDepth;
    265 
    266275        JSStack m_stack;
     276        int m_errorHandlingModeReentry;
    267277       
    268278#if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT)
  • trunk/Source/JavaScriptCore/interpreter/JSStack.cpp

    r130726 r132143  
    4242    return staticMutex;
    4343}   
    44    
     44
     45JSStack::JSStack(size_t capacity)
     46    : m_end(0)
     47{
     48    ASSERT(capacity && isPageAligned(capacity));
     49
     50    m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
     51    m_end = static_cast<Register*>(m_reservation.base());
     52    m_commitEnd = static_cast<Register*>(m_reservation.base());
     53
     54    disableErrorStackReserve();
     55}
     56
    4557JSStack::~JSStack()
    4658{
     
    5365bool JSStack::growSlowCase(Register* newEnd)
    5466{
     67    // If we have already committed enough memory to satisfy this request,
     68    // just update the end pointer and return.
    5569    if (newEnd <= m_commitEnd) {
    5670        m_end = newEnd;
     
    5872    }
    5973
     74    // Compute the chunk size of additional memory to commit, and see if we
     75    // have it is still within our budget. If not, we'll fail to grow and
     76    // return false.
    6077    long delta = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
    61     if (reinterpret_cast<char*>(m_commitEnd) + delta > static_cast<char*>(m_reservation.base()) + m_reservation.size())
     78    if (reinterpret_cast<char*>(m_commitEnd) + delta > reinterpret_cast<char*>(m_useableEnd))
    6279        return false;
    6380
     81    // Otherwise, the growth is still within our budget. Go ahead and commit
     82    // it and return true.
    6483    m_reservation.commit(m_commitEnd, delta);
    6584    addToCommittedByteCount(delta);
     
    105124}
    106125
     126void JSStack::enableErrorStackReserve()
     127{
     128    m_useableEnd = reservationEnd();
     129}
     130
     131void JSStack::disableErrorStackReserve()
     132{
     133    char* useableEnd = reinterpret_cast<char*>(reservationEnd()) - commitSize;
     134    m_useableEnd = reinterpret_cast<Register*>(useableEnd);
     135
     136    // By the time we get here, we are guaranteed to be destructing the last
     137    // Interpreter::ErrorHandlingMode that enabled this reserve in the first
     138    // place. That means the stack space beyond m_useableEnd before we
     139    // enabled the reserve was not previously in use. Hence, it is safe to
     140    // shrink back to that m_useableEnd.
     141    if (m_end > m_useableEnd)
     142        shrink(m_useableEnd);
     143}
     144
    107145} // namespace JSC
  • trunk/Source/JavaScriptCore/interpreter/JSStack.h

    r130726 r132143  
    8383        }
    8484
     85        void enableErrorStackReserve();
     86        void disableErrorStackReserve();
     87
    8588    private:
    8689        friend class LLIntOffsetsExtractor;
     90
     91        Register* reservationEnd() const
     92        {
     93            char* base = static_cast<char*>(m_reservation.base());
     94            char* reservationEnd = base + m_reservation.size();
     95            return reinterpret_cast<Register*>(reservationEnd);
     96        }
    8797
    8898        bool growSlowCase(Register*);
     
    91101        Register* m_end;
    92102        Register* m_commitEnd;
     103        Register* m_useableEnd;
    93104        PageReservation m_reservation;
    94105    };
    95 
    96     inline JSStack::JSStack(size_t capacity)
    97         : m_end(0)
    98     {
    99         ASSERT(capacity && isPageAligned(capacity));
    100 
    101         m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
    102         m_end = static_cast<Register*>(m_reservation.base());
    103         m_commitEnd = static_cast<Register*>(m_reservation.base());
    104     }
    105106
    106107    inline void JSStack::shrink(Register* newEnd)
  • trunk/Source/JavaScriptCore/jsc.cpp

    r131088 r132143  
    747747    // comes first.
    748748    CommandLine options(argc, argv);
    749     RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
     749    RefPtr<JSGlobalData> globalData = JSGlobalData::create(LargeHeap);
    750750    JSLockHolder lock(globalData.get());
    751751    int result;
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r131236 r132143  
    4040#define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0)
    4141#define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0)
     42#define failWithStackOverflow() do { m_error = true; m_hasStackOverflow = true; return 0; } while (0)
    4243#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
    4344#define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0)
     
    5556#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0)
    5657#define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0)
    57 #define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0)
     58#define failIfStackOverflow() do { if (!canRecurse()) failWithStackOverflow(); } while (0)
    5859
    5960using namespace std;
     
    6667    , m_source(&source)
    6768    , m_stack(wtfThreadData().stack())
     69    , m_hasStackOverflow(false)
    6870    , m_error(false)
    6971    , m_errorMessage("Parse error")
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r131938 r132143  
    897897   
    898898    StackBounds m_stack;
     899    bool m_hasStackOverflow;
    899900    bool m_error;
    900901    String m_errorMessage;
     
    988989        // code we assume that it was a syntax error since running out of stack is much less
    989990        // likely, and we are currently unable to distinguish between the two cases.
    990         if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
     991        if (isFunctionBodyNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow)
    991992            *exception = createStackOverflowError(lexicalGlobalObject);
    992993        else if (isEvalNode<ParsedNode>())
  • trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp

    r127958 r132143  
    164164JSObject* throwStackOverflowError(ExecState* exec)
    165165{
     166    Interpreter::ErrorHandlingMode mode(exec);
    166167    return throwError(exec, createStackOverflowError(exec));
    167168}
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp

    r129830 r132143  
    131131#endif // ENABLE(!ASSEMBLER)
    132132
    133 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapType heapType)
     133JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType)
    134134    :
    135135#if ENABLE(ASSEMBLER)
     
    172172    , dynamicGlobalObject(0)
    173173    , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
    174     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
    175174    , m_enabledProfiler(0)
    176175    , m_regExpCache(new RegExpCache(this))
     
    311310}
    312311
    313 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type, HeapType heapType)
    314 {
    315     return adoptRef(new JSGlobalData(APIContextGroup, type, heapType));
    316 }
    317 
    318 PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapType heapType)
    319 {
    320     return adoptRef(new JSGlobalData(Default, type, heapType));
    321 }
    322 
    323 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapType heapType)
    324 {
    325     return create(type, heapType);
     312PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(HeapType heapType)
     313{
     314    return adoptRef(new JSGlobalData(APIContextGroup, heapType));
     315}
     316
     317PassRefPtr<JSGlobalData> JSGlobalData::create(HeapType heapType)
     318{
     319    return adoptRef(new JSGlobalData(Default, heapType));
     320}
     321
     322PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(HeapType heapType)
     323{
     324    return create(heapType);
    326325}
    327326
     
    336335    JSGlobalData*& instance = sharedInstanceInternal();
    337336    if (!instance) {
    338         instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
     337        instance = adoptRef(new JSGlobalData(APIShared, SmallHeap)).leakRef();
    339338        instance->makeUsableFromMultipleThreads();
    340339    }
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.h

    r130839 r132143  
    105105    };
    106106
    107     enum ThreadStackType {
    108         ThreadStackTypeLarge,
    109         ThreadStackTypeSmall
    110     };
    111 
    112107#if ENABLE(DFG_JIT)
    113108    class ConservativeRoots;
     
    165160        JS_EXPORT_PRIVATE static JSGlobalData& sharedInstance();
    166161
    167         JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> create(ThreadStackType, HeapType = SmallHeap);
    168         JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType, HeapType = SmallHeap);
    169         static PassRefPtr<JSGlobalData> createContextGroup(ThreadStackType, HeapType = SmallHeap);
     162        JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> create(HeapType = SmallHeap);
     163        JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> createLeaked(HeapType = SmallHeap);
     164        static PassRefPtr<JSGlobalData> createContextGroup(HeapType = SmallHeap);
    170165        JS_EXPORT_PRIVATE ~JSGlobalData();
    171166
     
    346341        String cachedDateString;
    347342        double cachedDateStringValue;
    348 
    349         int maxReentryDepth;
    350343
    351344        Profiler* m_enabledProfiler;
     
    448441        friend class LLIntOffsetsExtractor;
    449442       
    450         JSGlobalData(GlobalDataType, ThreadStackType, HeapType);
     443        JSGlobalData(GlobalDataType, HeapType);
    451444        static JSGlobalData*& sharedInstanceInternal();
    452445        void createNativeThunk();
  • trunk/Source/JavaScriptCore/runtime/StringRecursionChecker.h

    r131938 r132143  
    2323#include "Interpreter.h"
    2424#include <wtf/StackStats.h>
     25#include <wtf/WTFThreadData.h>
    2526
    2627namespace JSC {
     
    4950inline JSValue StringRecursionChecker::performCheck()
    5051{
    51     int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size();
    52     if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth)
     52    const StackBounds& nativeStack = wtfThreadData().stack();
     53    if (!nativeStack.isSafeToRecurse())
    5354        return throwStackOverflowError();
    5455    bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
  • trunk/Source/JavaScriptCore/testRegExp.cpp

    r131088 r132143  
    499499int realMain(int argc, char** argv)
    500500{
    501     RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
     501    RefPtr<JSGlobalData> globalData = JSGlobalData::create(LargeHeap);
    502502    JSLockHolder lock(globalData.get());
    503503
  • trunk/Source/WebCore/ChangeLog

    r132141 r132143  
     12012-10-22  Mark Lam  <mark.lam@apple.com>
     2
     3        Change stack recursion checks to be based on stack availability.
     4        https://bugs.webkit.org/show_bug.cgi?id=99872.
     5
     6        Reviewed by Filip Pizlo and Geoffrey Garen.
     7
     8        Removed the use of ThreadStackType. Enabled the reserved JSStack space
     9        for error processing before doing work in reportException().
     10
     11        * bindings/js/JSDOMBinding.cpp:
     12        (WebCore::reportException):
     13        * bindings/js/JSDOMWindowBase.cpp:
     14        (WebCore::JSDOMWindowBase::commonJSGlobalData):
     15        * bindings/js/WorkerScriptController.cpp:
     16        (WebCore::WorkerScriptController::WorkerScriptController):
     17
    1182012-10-22  Andreas Kling  <kling@webkit.org>
    219
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp

    r130612 r132143  
    3232#include "JSExceptionBase.h"
    3333#include "ScriptCallStack.h"
     34#include <interpreter/Interpreter.h>
    3435#include <runtime/DateInstance.h>
    3536#include <runtime/Error.h>
     
    150151        return;
    151152
     153    Interpreter::ErrorHandlingMode mode(exec);
    152154    String errorMessage = exception.toString(exec)->value(exec);
    153155    JSObject* exceptionObject = exception.toObject(exec);
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp

    r129685 r132143  
    182182    if (!globalData) {
    183183        ScriptController::initializeThreading();
    184         globalData = JSGlobalData::createLeaked(ThreadStackTypeLarge, LargeHeap).leakRef();
     184        globalData = JSGlobalData::createLeaked(LargeHeap).leakRef();
    185185        globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds
    186186#ifndef NDEBUG
  • trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp

    r128670 r132143  
    5656
    5757WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
    58     : m_globalData(JSGlobalData::create(ThreadStackTypeSmall))
     58    : m_globalData(JSGlobalData::create())
    5959    , m_workerContext(workerContext)
    6060    , m_workerContextWrapper(*m_globalData)
Note: See TracChangeset for help on using the changeset viewer.