Changeset 204162 in webkit
- Timestamp:
- Aug 4, 2016, 11:46:55 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r204160 r204162 1 2016-08-04 Saam Barati <sbarati@apple.com> 2 3 Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a long time 4 https://bugs.webkit.org/show_bug.cgi?id=151241 5 6 Reviewed by Benjamin Poulain. 7 8 This patch rolls back in the jettisoning policy from https://bugs.webkit.org/show_bug.cgi?id=149727. 9 We can now jettison a CodeBlock when it has been alive for a long time 10 and is only pointed to by its owner executable. I haven't been able to get this 11 patch to crash on anything it used to crash on, so I suspect we've fixed the bugs that 12 were causing this before. I've also added some stress options for this feature that 13 will cause us to either eagerly old-age jettison or to old-age jettison whenever it's legal. 14 These options helped me find a bug where we would ask an Executable to create a CodeBlock, 15 and then the Executable would do some other allocations, causing a GC, immediately causing 16 the CodeBlock to jettison. There is a small chance that this was the bug we were seeing before, 17 however, it's unlikely given that the previous timing metrics require at least 5 second between 18 compiling to jettisoning. 19 20 This patch also enables the stress options for various modes 21 of JSC stress tests. 22 23 * bytecode/CodeBlock.cpp: 24 (JSC::CodeBlock::shouldJettisonDueToWeakReference): 25 (JSC::timeToLive): 26 (JSC::CodeBlock::shouldJettisonDueToOldAge): 27 * interpreter/CallFrame.h: 28 (JSC::ExecState::callee): 29 (JSC::ExecState::unsafeCallee): 30 (JSC::ExecState::codeBlock): 31 (JSC::ExecState::addressOfCodeBlock): 32 (JSC::ExecState::unsafeCodeBlock): 33 (JSC::ExecState::scope): 34 * interpreter/Interpreter.cpp: 35 (JSC::Interpreter::execute): 36 (JSC::Interpreter::executeCall): 37 (JSC::Interpreter::executeConstruct): 38 (JSC::Interpreter::prepareForRepeatCall): 39 * jit/JITOperations.cpp: 40 * llint/LLIntSlowPaths.cpp: 41 (JSC::LLInt::setUpCall): 42 * runtime/Executable.cpp: 43 (JSC::ScriptExecutable::installCode): 44 (JSC::setupJIT): 45 (JSC::ScriptExecutable::prepareForExecutionImpl): 46 * runtime/Executable.h: 47 (JSC::ScriptExecutable::prepareForExecution): 48 * runtime/Options.h: 49 1 50 2016-08-04 Yusuke Suzuki <utatane.tea@gmail.com> 2 51 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r203979 r204162 2652 2652 } 2653 2653 2654 static std::chrono::milliseconds timeToLive(JITCode::JITType jitType) 2655 { 2656 if (UNLIKELY(Options::useEagerCodeBlockJettisonTiming())) { 2657 switch (jitType) { 2658 case JITCode::InterpreterThunk: 2659 return std::chrono::milliseconds(10); 2660 case JITCode::BaselineJIT: 2661 return std::chrono::milliseconds(10 + 20); 2662 case JITCode::DFGJIT: 2663 return std::chrono::milliseconds(40); 2664 case JITCode::FTLJIT: 2665 return std::chrono::milliseconds(120); 2666 default: 2667 return std::chrono::milliseconds::max(); 2668 } 2669 } 2670 2671 switch (jitType) { 2672 case JITCode::InterpreterThunk: 2673 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(5)); 2674 case JITCode::BaselineJIT: 2675 // Effectively 10 additional seconds, since BaselineJIT and 2676 // InterpreterThunk share a CodeBlock. 2677 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(5 + 10)); 2678 case JITCode::DFGJIT: 2679 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(20)); 2680 case JITCode::FTLJIT: 2681 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(60)); 2682 default: 2683 return std::chrono::milliseconds::max(); 2684 } 2685 } 2686 2654 2687 bool CodeBlock::shouldJettisonDueToOldAge() 2655 2688 { 2656 return false; 2689 if (Heap::isMarked(this)) 2690 return false; 2691 2692 if (UNLIKELY(Options::forceCodeBlockToJettisonDueToOldAge())) 2693 return true; 2694 2695 if (timeSinceCreation() < timeToLive(jitType())) 2696 return false; 2697 2698 return true; 2657 2699 } 2658 2700 -
trunk/Source/JavaScriptCore/interpreter/CallFrame.h
r203081 r204162 91 91 SUPPRESS_ASAN JSValue unsafeCallee() const { return this[CallFrameSlot::callee].asanUnsafeJSValue(); } 92 92 CodeBlock* codeBlock() const { return this[CallFrameSlot::codeBlock].Register::codeBlock(); } 93 CodeBlock** addressOfCodeBlock() const { return bitwise_cast<CodeBlock**>(this + CallFrameSlot::codeBlock); } 93 94 SUPPRESS_ASAN CodeBlock* unsafeCodeBlock() const { return this[CallFrameSlot::codeBlock].Register::asanUnsafeCodeBlock(); } 94 95 JSScope* scope(int scopeRegisterOffset) const -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r203790 r204162 945 945 return checkedReturn(callFrame->vm().throwException(callFrame, error)); 946 946 947 if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall)) 948 return checkedReturn(callFrame->vm().throwException(callFrame, error)); 949 950 ProgramCodeBlock* codeBlock = program->codeBlock(); 947 ProgramCodeBlock* codeBlock; 948 { 949 CodeBlock* tempCodeBlock; 950 if (JSObject* error = program->prepareForExecution<ProgramExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock)) 951 return checkedReturn(callFrame->vm().throwException(callFrame, error)); 952 codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock); 953 } 951 954 952 955 if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) … … 996 999 if (isJSCall) { 997 1000 // Compile the callee: 998 JSObject* compileError = callData.js.functionExecutable->prepareForExecution (callFrame, jsCast<JSFunction*>(function), scope, CodeForCall);999 if (UNLIKELY(!!compileError)) {1001 JSObject* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock); 1002 if (UNLIKELY(!!compileError)) 1000 1003 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1001 } 1002 newCodeBlock = callData.js.functionExecutable->codeBlockForCall(); 1004 1003 1005 ASSERT(!!newCodeBlock); 1004 1006 newCodeBlock->m_shouldAlwaysBeInlined = false; … … 1058 1060 if (isJSConstruct) { 1059 1061 // Compile the callee: 1060 JSObject* compileError = constructData.js.functionExecutable->prepareForExecution (callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct);1061 if (UNLIKELY(!!compileError)) {1062 JSObject* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock); 1063 if (UNLIKELY(!!compileError)) 1062 1064 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1063 } 1064 newCodeBlock = constructData.js.functionExecutable->codeBlockForConstruct(); 1065 1065 1066 ASSERT(!!newCodeBlock); 1066 1067 newCodeBlock->m_shouldAlwaysBeInlined = false; … … 1102 1103 1103 1104 // Compile the callee: 1104 JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall); 1105 CodeBlock* newCodeBlock; 1106 JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, function, scope, CodeForCall, newCodeBlock); 1105 1107 if (error) { 1106 1108 callFrame->vm().throwException(callFrame, error); 1107 1109 return CallFrameClosure(); 1108 1110 } 1109 CodeBlock* newCodeBlock = functionExecutable->codeBlockForCall();1110 1111 newCodeBlock->m_shouldAlwaysBeInlined = false; 1111 1112 … … 1177 1178 } 1178 1179 1179 JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall); 1180 if (UNLIKELY(!!compileError)) 1181 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1182 EvalCodeBlock* codeBlock = eval->codeBlock(); 1180 EvalCodeBlock* codeBlock; 1181 { 1182 CodeBlock* tempCodeBlock; 1183 JSObject* compileError = eval->prepareForExecution<EvalExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock); 1184 if (UNLIKELY(!!compileError)) 1185 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1186 codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock); 1187 } 1183 1188 1184 1189 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval. … … 1254 1259 return checkedReturn(throwStackOverflowError(callFrame)); 1255 1260 1256 JSObject* compileError = executable->prepareForExecution(callFrame, nullptr, scope, CodeForCall); 1257 if (UNLIKELY(!!compileError)) 1258 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1259 ModuleProgramCodeBlock* codeBlock = executable->codeBlock(); 1261 ModuleProgramCodeBlock* codeBlock; 1262 { 1263 CodeBlock* tempCodeBlock; 1264 JSObject* compileError = executable->prepareForExecution<ModuleProgramExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock); 1265 if (UNLIKELY(!!compileError)) 1266 return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); 1267 codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock); 1268 } 1260 1269 1261 1270 if (UNLIKELY(vm.shouldTriggerTermination(callFrame))) -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r204010 r204162 901 901 } 902 902 903 JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind); 903 CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock(); 904 JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, callee, scope, kind, *codeBlockSlot); 904 905 if (error) { 905 906 exec->vm().throwException(exec, error); … … 908 909 reinterpret_cast<void*>(KeepTheFrame)); 909 910 } 910 codeBlock = functionExecutable->codeBlockFor(kind);911 codeBlock = *codeBlockSlot; 911 912 ArityCheckMode arity; 912 913 if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->isVarargs()) … … 955 956 } 956 957 957 JSObject* error = functionExecutable->prepareForExecution(execCallee, function, scope, kind); 958 CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock(); 959 JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, function, scope, kind, *codeBlockSlot); 958 960 if (error) { 959 961 exec->vm().throwException(exec, error); -
trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
r203452 r204162 1267 1267 LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee)); 1268 1268 1269 JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind); 1269 CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock(); 1270 JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, callee, scope, kind, *codeBlockSlot); 1270 1271 if (error) 1271 1272 LLINT_CALL_THROW(exec, error); 1272 codeBlock = functionExecutable->codeBlockFor(kind);1273 codeBlock = *codeBlockSlot; 1273 1274 ASSERT(codeBlock); 1274 1275 ArityCheckMode arity; -
trunk/Source/JavaScriptCore/runtime/Executable.cpp
r202734 r204162 178 178 ASSERT(vm.heap.isDeferred()); 179 179 180 CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ()); 180 if (genericCodeBlock) 181 CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ()); 181 182 182 183 CodeBlock* oldCodeBlock = nullptr; … … 400 401 401 402 JSObject* ScriptExecutable::prepareForExecutionImpl( 402 ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind )403 ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock) 403 404 { 404 405 VM& vm = exec->vm(); 405 DeferGC deferGC(vm.heap);406 DeferGCForAWhile deferGC(vm.heap); 406 407 407 408 if (vm.getAndClearFailNextNewCodeBlock()) … … 410 411 JSObject* exception = 0; 411 412 CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception); 413 resultCodeBlock = codeBlock; 412 414 if (!codeBlock) { 413 415 RELEASE_ASSERT(exception); … … 424 426 425 427 installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); 426 return 0;428 return nullptr; 427 429 } 428 430 -
trunk/Source/JavaScriptCore/runtime/Executable.h
r204137 r204162 368 368 CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception); 369 369 CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind); 370 371 JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) 372 { 373 if (hasJITCodeFor(kind)) 374 return 0; 375 return prepareForExecutionImpl(exec, function, scope, kind); 376 } 370 371 // This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock 372 // that is not jettisoned before this function returns. Callers are essentially asking for a strong reference 373 // to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in 374 // their CodeBlock*& reference because it's safe for CodeBlock to be jettisoned if Executable is the only thing 375 // to point to it. This forces callers to have a CodeBlock* in a register or on the stack that will be marked 376 // by conservative GC if a GC happens after we create the CodeBlock. 377 template <typename ExecutableType> 378 JSObject* prepareForExecution(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock); 377 379 378 380 template <typename Functor> void forEachCodeBlock(Functor&&); … … 380 382 private: 381 383 friend class ExecutableBase; 382 JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind );384 JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&); 383 385 384 386 protected: … … 740 742 #endif 741 743 744 template <typename ExecutableType> 745 JSObject* ScriptExecutable::prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock) 746 { 747 if (hasJITCodeFor(kind)) { 748 if (std::is_same<ExecutableType, EvalExecutable>::value) 749 resultCodeBlock = jsCast<CodeBlock*>(jsCast<EvalExecutable*>(this)->codeBlock()); 750 else if (std::is_same<ExecutableType, ProgramExecutable>::value) 751 resultCodeBlock = jsCast<CodeBlock*>(jsCast<ProgramExecutable*>(this)->codeBlock()); 752 else if (std::is_same<ExecutableType, ModuleProgramExecutable>::value) 753 resultCodeBlock = jsCast<CodeBlock*>(jsCast<ModuleProgramExecutable*>(this)->codeBlock()); 754 else if (std::is_same<ExecutableType, FunctionExecutable>::value) 755 resultCodeBlock = jsCast<CodeBlock*>(jsCast<FunctionExecutable*>(this)->codeBlockFor(kind)); 756 else 757 RELEASE_ASSERT_NOT_REACHED(); 758 return nullptr; 759 } 760 return prepareForExecutionImpl(exec, function, scope, kind, resultCodeBlock); 761 } 762 742 763 } // namespace JSC 743 764 -
trunk/Source/JavaScriptCore/runtime/Options.h
r203329 r204162 323 323 v(bool, recordGCPauseTimes, false, Normal, nullptr) \ 324 324 v(bool, logHeapStatisticsAtExit, false, Normal, nullptr) \ 325 v(bool, forceCodeBlockToJettisonDueToOldAge, false, Normal, "If true, this means that anytime we can jettison a CodeBlock due to old age, we do.") \ 326 v(bool, useEagerCodeBlockJettisonTiming, false, Normal, "If true, the time slices for jettisoning a CodeBlock due to old age are shrunk significantly.") \ 325 327 \ 326 328 v(bool, useTypeProfiler, false, Normal, nullptr) \ -
trunk/Tools/ChangeLog
r204156 r204162 1 2016-08-04 Saam Barati <sbarati@apple.com> 2 3 Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a long time 4 https://bugs.webkit.org/show_bug.cgi?id=151241 5 6 Reviewed by Benjamin Poulain. 7 8 * Scripts/run-jsc-stress-tests: 9 1 10 2016-08-04 Dean Johnson <dean_johnson@apple.com> 2 11 -
trunk/Tools/Scripts/run-jsc-stress-tests
r203625 r204162 420 420 # We force all tests to use a smaller (1.5M) stack so that stack overflow tests can run faster. 421 421 BASE_OPTIONS = ["--useFTLJIT=false", "--useFunctionDotArguments=true", "--maxPerThreadStackUsage=1572864"] 422 EAGER_OPTIONS = ["--thresholdForJITAfterWarmUp=10", "--thresholdForJITSoon=10", "--thresholdForOptimizeAfterWarmUp=20", "--thresholdForOptimizeAfterLongWarmUp=20", "--thresholdForOptimizeSoon=20", "--thresholdForFTLOptimizeAfterWarmUp=20", "--thresholdForFTLOptimizeSoon=20", "--maximumEvalCacheableSourceLength=150000" ]422 EAGER_OPTIONS = ["--thresholdForJITAfterWarmUp=10", "--thresholdForJITSoon=10", "--thresholdForOptimizeAfterWarmUp=20", "--thresholdForOptimizeAfterLongWarmUp=20", "--thresholdForOptimizeSoon=20", "--thresholdForFTLOptimizeAfterWarmUp=20", "--thresholdForFTLOptimizeSoon=20", "--maximumEvalCacheableSourceLength=150000", "--useEagerCodeBlockJettisonTiming=true"] 423 423 NO_CJIT_OPTIONS = ["--useConcurrentJIT=false", "--thresholdForJITAfterWarmUp=100"] 424 424 FTL_OPTIONS = ["--useFTLJIT=true"] … … 877 877 878 878 def runDFGMaximalFlushPhase 879 run("dfg-maximal-flush-validate-no-cjit", "-- validateGraph=true", "--useMaximalFlushInsertionPhase=true", *NO_CJIT_OPTIONS)879 run("dfg-maximal-flush-validate-no-cjit", "--forceCodeBlockToJettisonDueToOldAge=true", "--validateGraph=true", "--useMaximalFlushInsertionPhase=true", *NO_CJIT_OPTIONS) 880 880 end 881 881
Note:
See TracChangeset
for help on using the changeset viewer.