Changeset 132143 in webkit
- Timestamp:
- Oct 22, 2012 3:09:58 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r132141 r132143 1 2012-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 1 13 2012-10-22 Andreas Kling <kling@webkit.org> 2 14 -
trunk/LayoutTests/fast/js/global-recursion-on-full-stack-expected.txt
r115861 r132143 1 CONSOLE MESSAGE: 1 CONSOLE MESSAGE: RangeError: Maximum call stack size exceeded. 2 2 This tests global code recursion when the JS stack is full. 3 3 PASS: 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: 1 CONSOLE MESSAGE: RangeError: Maximum call stack size exceeded. 3 2 This tests that having infinite recursion in XMLHttpRequest event handler does not crash. 4 3 PASS -
trunk/Source/JavaScriptCore/API/JSContextRef.cpp
r128091 r132143 55 55 { 56 56 initializeThreading(); 57 return toRef(JSGlobalData::createContextGroup( ThreadStackTypeSmall).leakRef());57 return toRef(JSGlobalData::createContextGroup().leakRef()); 58 58 } 59 59 … … 90 90 initializeThreading(); 91 91 92 RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup( ThreadStackTypeSmall);92 RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup(); 93 93 94 94 APIEntryShim entryShim(globalData.get(), false); -
trunk/Source/JavaScriptCore/ChangeLog
r131997 r132143 1 2012-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 1 76 2012-10-20 Martin Robinson <mrobinson@igalia.com> 2 77 -
trunk/Source/JavaScriptCore/JavaScriptCore.order
r131225 r132143 121 121 __ZN3JSCL17createJSLockCountEv 122 122 __ZN3JSC12JSGlobalData14sharedInstanceEv 123 __ZN3JSC12JSGlobalDataC2ENS0_14GlobalDataTypeENS_ 15ThreadStackTypeE123 __ZN3JSC12JSGlobalDataC2ENS0_14GlobalDataTypeENS_8HeapTypeE 124 124 __ZN3JSC21createIdentifierTableEv 125 125 __ZN3JSC17CommonIdentifiersC1EPNS_12JSGlobalDataE … … 441 441 __ZN3WTF10StringImpl11reverseFindEPS0_j 442 442 __ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_ 443 __ZN3JSC12JSGlobalData12createLeakedENS_ 15ThreadStackTypeE443 __ZN3JSC12JSGlobalData12createLeakedENS_8HeapTypeE 444 444 __ZN3JSC24JSObjectWithGlobalObjectC2ERNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureE 445 445 __ZN3JSC8evaluateEPNS_9ExecStateEPNS_14ScopeChainNodeERKNS_10SourceCodeENS_7JSValueE … … 1708 1708 __ZN3JSCL21arrayProtoFuncReverseEPNS_9ExecStateE 1709 1709 __ZN3JSC17ProgramExecutable13visitChildrenERNS_9MarkStackE 1710 __ZN3JSC12JSGlobalData18createContextGroupENS_ 15ThreadStackTypeE1710 __ZN3JSC12JSGlobalData18createContextGroupENS_8HeapTypeE 1711 1711 __ZN3JSC12JSGlobalData22clearBuiltinStructuresEv 1712 1712 __ZN3JSC4Heap7destroyEv … … 1843 1843 __ZN3JSC8JSObject15unwrappedObjectEv 1844 1844 __ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE 1845 __ZN3JSC12JSGlobalData6createENS_ 15ThreadStackTypeE1845 __ZN3JSC12JSGlobalData6createENS_8HeapTypeE 1846 1846 __ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_10JSFunctionEj 1847 1847 __ZN3JSC12JSGlobalData13startSamplingEv -
trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
r131882 r132143 11 11 ??0DropAllLocks@JSLock@JSC@@QAE@PAVJSGlobalData@2@@Z 12 12 ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z 13 ??0ErrorHandlingMode@Interpreter@JSC@@QAE@PAVExecState@2@@Z 14 ??1ErrorHandlingMode@Interpreter@JSC@@QAE@XZ 13 15 ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z 14 16 ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z … … 119 121 ?copyBackingStore@JSObject@JSC@@SAXPAVJSCell@2@AAVCopyVisitor@2@@Z 120 122 ?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@@W4 ThreadStackType@2@W4HeapType@2@@Z123 ?create@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4HeapType@2@@Z 122 124 ?create@OpaqueJSString@@SA?AV?$PassRefPtr@UOpaqueJSString@@@WTF@@ABVString@3@@Z 123 125 ?create@RegExp@JSC@@SAPAV12@AAVJSGlobalData@2@ABVString@WTF@@W4RegExpFlags@2@@Z … … 125 127 ?createError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVString@WTF@@@Z 126 128 ?createInterruptedExecutionException@JSC@@YAPAVJSObject@1@PAVJSGlobalData@1@@Z 127 ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4 ThreadStackType@2@W4HeapType@2@@Z129 ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@W4HeapType@2@@Z 128 130 ?createNotEnoughArgumentsError@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z 129 131 ?createRangeError@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVString@WTF@@@Z -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r131938 r132143 68 68 #include <wtf/StackStats.h> 69 69 #include <wtf/Threading.h> 70 #include <wtf/WTFThreadData.h> 70 71 #include <wtf/text/StringBuilder.h> 71 72 … … 79 80 80 81 namespace JSC { 82 83 Interpreter::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 91 Interpreter::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 115 Interpreter::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 81 199 82 200 static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset); … … 248 366 Interpreter::Interpreter() 249 367 : m_sampleEntryDepth(0) 250 , m_ reentryDepth(0)368 , m_errorHandlingModeReentry(0) 251 369 #if !ASSERT_DISABLED 252 370 , m_initialized(false) … … 755 873 756 874 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())) 758 878 return checkedReturn(throwStackOverflowError(callFrame)); 759 879 … … 891 1011 SamplingTool::CallRecord callRecord(m_sampler.get()); 892 1012 893 m_reentryDepth++;894 1013 #if ENABLE(LLINT_C_LOOP) 895 1014 result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue); … … 897 1016 result = program->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData()); 898 1017 #endif // ENABLE(JIT) 899 900 m_reentryDepth--;901 1018 } 902 1019 … … 918 1035 919 1036 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())) 921 1040 return checkedReturn(throwStackOverflowError(callFrame)); 922 1041 … … 963 1082 SamplingTool::CallRecord callRecord(m_sampler.get()); 964 1083 965 m_reentryDepth++;966 1084 #if ENABLE(LLINT_C_LOOP) 967 1085 result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue); … … 969 1087 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_stack, newCallFrame, callDataScope->globalData()); 970 1088 #endif // ENABLE(JIT) 971 972 m_reentryDepth--;973 1089 } 974 1090 … … 1014 1130 1015 1131 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())) 1017 1135 return checkedReturn(throwStackOverflowError(callFrame)); 1018 1136 … … 1058 1176 SamplingTool::CallRecord callRecord(m_sampler.get()); 1059 1177 1060 m_reentryDepth++;1061 1178 #if ENABLE(LLINT_C_LOOP) 1062 1179 result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue); … … 1064 1181 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, constructDataScope->globalData()); 1065 1182 #endif // ENABLE(JIT) 1066 m_reentryDepth--;1067 1183 } 1068 1184 … … 1112 1228 1113 1229 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())) { 1115 1233 throwStackOverflowError(callFrame); 1116 1234 return CallFrameClosure(); … … 1165 1283 SamplingTool::CallRecord callRecord(m_sampler.get()); 1166 1284 1167 m_reentryDepth++;1168 1285 #if ENABLE(LLINT_C_LOOP) 1169 1286 result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue); … … 1171 1288 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, closure.globalData); 1172 1289 #endif // ENABLE(JIT) 1173 m_reentryDepth--;1174 1290 } 1175 1291 … … 1198 1314 1199 1315 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())) 1201 1319 return checkedReturn(throwStackOverflowError(callFrame)); 1202 1320 … … 1259 1377 { 1260 1378 SamplingTool::CallRecord callRecord(m_sampler.get()); 1261 1262 m_reentryDepth++;1263 1379 1264 1380 #if ENABLE(LLINT_C_LOOP) … … 1267 1383 result = eval->generatedJITCode().execute(&m_stack, newCallFrame, scope->globalData()); 1268 1384 #endif // ENABLE(JIT) 1269 m_reentryDepth--;1270 1385 } 1271 1386 -
trunk/Source/JavaScriptCore/interpreter/Interpreter.h
r130726 r132143 171 171 }; 172 172 173 // We use a smaller reentrancy limit on iPhone because of the high amount of174 // stack space required on the web thread.175 #if PLATFORM(IOS)176 enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 };177 #else178 enum { MaxLargeThreadReentryDepth = 256, MaxSmallThreadReentryDepth = 16 };179 #endif // PLATFORM(IOS)180 181 173 class Interpreter { 182 174 WTF_MAKE_FAST_ALLOCATED; … … 184 176 friend class LLIntOffsetsExtractor; 185 177 friend class JIT; 178 186 179 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 187 188 Interpreter(); 188 189 ~Interpreter(); … … 242 243 243 244 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 244 255 enum ExecutionFlag { Normal, InitializeAndReturn }; 245 256 … … 262 273 OwnPtr<SamplingTool> m_sampler; 263 274 264 int m_reentryDepth;265 266 275 JSStack m_stack; 276 int m_errorHandlingModeReentry; 267 277 268 278 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) -
trunk/Source/JavaScriptCore/interpreter/JSStack.cpp
r130726 r132143 42 42 return staticMutex; 43 43 } 44 44 45 JSStack::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 45 57 JSStack::~JSStack() 46 58 { … … 53 65 bool JSStack::growSlowCase(Register* newEnd) 54 66 { 67 // If we have already committed enough memory to satisfy this request, 68 // just update the end pointer and return. 55 69 if (newEnd <= m_commitEnd) { 56 70 m_end = newEnd; … … 58 72 } 59 73 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. 60 77 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)) 62 79 return false; 63 80 81 // Otherwise, the growth is still within our budget. Go ahead and commit 82 // it and return true. 64 83 m_reservation.commit(m_commitEnd, delta); 65 84 addToCommittedByteCount(delta); … … 105 124 } 106 125 126 void JSStack::enableErrorStackReserve() 127 { 128 m_useableEnd = reservationEnd(); 129 } 130 131 void 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 107 145 } // namespace JSC -
trunk/Source/JavaScriptCore/interpreter/JSStack.h
r130726 r132143 83 83 } 84 84 85 void enableErrorStackReserve(); 86 void disableErrorStackReserve(); 87 85 88 private: 86 89 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 } 87 97 88 98 bool growSlowCase(Register*); … … 91 101 Register* m_end; 92 102 Register* m_commitEnd; 103 Register* m_useableEnd; 93 104 PageReservation m_reservation; 94 105 }; 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 }105 106 106 107 inline void JSStack::shrink(Register* newEnd) -
trunk/Source/JavaScriptCore/jsc.cpp
r131088 r132143 747 747 // comes first. 748 748 CommandLine options(argc, argv); 749 RefPtr<JSGlobalData> globalData = JSGlobalData::create( ThreadStackTypeLarge,LargeHeap);749 RefPtr<JSGlobalData> globalData = JSGlobalData::create(LargeHeap); 750 750 JSLockHolder lock(globalData.get()); 751 751 int result; -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r131236 r132143 40 40 #define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0) 41 41 #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) 42 43 #define failIfFalse(cond) do { if (!(cond)) fail(); } while (0) 43 44 #define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0) … … 55 56 #define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0) 56 57 #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) 58 59 59 60 using namespace std; … … 66 67 , m_source(&source) 67 68 , m_stack(wtfThreadData().stack()) 69 , m_hasStackOverflow(false) 68 70 , m_error(false) 69 71 , m_errorMessage("Parse error") -
trunk/Source/JavaScriptCore/parser/Parser.h
r131938 r132143 897 897 898 898 StackBounds m_stack; 899 bool m_hasStackOverflow; 899 900 bool m_error; 900 901 String m_errorMessage; … … 988 989 // code we assume that it was a syntax error since running out of stack is much less 989 990 // 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) 991 992 *exception = createStackOverflowError(lexicalGlobalObject); 992 993 else if (isEvalNode<ParsedNode>()) -
trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
r127958 r132143 164 164 JSObject* throwStackOverflowError(ExecState* exec) 165 165 { 166 Interpreter::ErrorHandlingMode mode(exec); 166 167 return throwError(exec, createStackOverflowError(exec)); 167 168 } -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp
r129830 r132143 131 131 #endif // ENABLE(!ASSEMBLER) 132 132 133 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType,HeapType heapType)133 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) 134 134 : 135 135 #if ENABLE(ASSEMBLER) … … 172 172 , dynamicGlobalObject(0) 173 173 , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN()) 174 , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)175 174 , m_enabledProfiler(0) 176 175 , m_regExpCache(new RegExpCache(this)) … … 311 310 } 312 311 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);312 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(HeapType heapType) 313 { 314 return adoptRef(new JSGlobalData(APIContextGroup, heapType)); 315 } 316 317 PassRefPtr<JSGlobalData> JSGlobalData::create(HeapType heapType) 318 { 319 return adoptRef(new JSGlobalData(Default, heapType)); 320 } 321 322 PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(HeapType heapType) 323 { 324 return create(heapType); 326 325 } 327 326 … … 336 335 JSGlobalData*& instance = sharedInstanceInternal(); 337 336 if (!instance) { 338 instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall,SmallHeap)).leakRef();337 instance = adoptRef(new JSGlobalData(APIShared, SmallHeap)).leakRef(); 339 338 instance->makeUsableFromMultipleThreads(); 340 339 } -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.h
r130839 r132143 105 105 }; 106 106 107 enum ThreadStackType {108 ThreadStackTypeLarge,109 ThreadStackTypeSmall110 };111 112 107 #if ENABLE(DFG_JIT) 113 108 class ConservativeRoots; … … 165 160 JS_EXPORT_PRIVATE static JSGlobalData& sharedInstance(); 166 161 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); 170 165 JS_EXPORT_PRIVATE ~JSGlobalData(); 171 166 … … 346 341 String cachedDateString; 347 342 double cachedDateStringValue; 348 349 int maxReentryDepth;350 343 351 344 Profiler* m_enabledProfiler; … … 448 441 friend class LLIntOffsetsExtractor; 449 442 450 JSGlobalData(GlobalDataType, ThreadStackType,HeapType);443 JSGlobalData(GlobalDataType, HeapType); 451 444 static JSGlobalData*& sharedInstanceInternal(); 452 445 void createNativeThunk(); -
trunk/Source/JavaScriptCore/runtime/StringRecursionChecker.h
r131938 r132143 23 23 #include "Interpreter.h" 24 24 #include <wtf/StackStats.h> 25 #include <wtf/WTFThreadData.h> 25 26 26 27 namespace JSC { … … 49 50 inline JSValue StringRecursionChecker::performCheck() 50 51 { 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()) 53 54 return throwStackOverflowError(); 54 55 bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry; -
trunk/Source/JavaScriptCore/testRegExp.cpp
r131088 r132143 499 499 int realMain(int argc, char** argv) 500 500 { 501 RefPtr<JSGlobalData> globalData = JSGlobalData::create( ThreadStackTypeLarge,LargeHeap);501 RefPtr<JSGlobalData> globalData = JSGlobalData::create(LargeHeap); 502 502 JSLockHolder lock(globalData.get()); 503 503 -
trunk/Source/WebCore/ChangeLog
r132141 r132143 1 2012-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 1 18 2012-10-22 Andreas Kling <kling@webkit.org> 2 19 -
trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp
r130612 r132143 32 32 #include "JSExceptionBase.h" 33 33 #include "ScriptCallStack.h" 34 #include <interpreter/Interpreter.h> 34 35 #include <runtime/DateInstance.h> 35 36 #include <runtime/Error.h> … … 150 151 return; 151 152 153 Interpreter::ErrorHandlingMode mode(exec); 152 154 String errorMessage = exception.toString(exec)->value(exec); 153 155 JSObject* exceptionObject = exception.toObject(exec); -
trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp
r129685 r132143 182 182 if (!globalData) { 183 183 ScriptController::initializeThreading(); 184 globalData = JSGlobalData::createLeaked( ThreadStackTypeLarge,LargeHeap).leakRef();184 globalData = JSGlobalData::createLeaked(LargeHeap).leakRef(); 185 185 globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds 186 186 #ifndef NDEBUG -
trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp
r128670 r132143 56 56 57 57 WorkerScriptController::WorkerScriptController(WorkerContext* workerContext) 58 : m_globalData(JSGlobalData::create( ThreadStackTypeSmall))58 : m_globalData(JSGlobalData::create()) 59 59 , m_workerContext(workerContext) 60 60 , m_workerContextWrapper(*m_globalData)
Note: See TracChangeset
for help on using the changeset viewer.