Changeset 119844 in webkit
- Timestamp:
- Jun 8, 2012 11:17:16 AM (12 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r119795 r119844 1 Don't rely on weak pointers for eager CodeBlock finalization 2 https://bugs.webkit.org/show_bug.cgi?id=88465 3 4 Reviewed by Gavin Barraclough. 5 6 This is incompatible with lazy weak pointer finalization. 7 8 I considered just making CodeBlock finalization lazy-friendly, but it 9 turns out that the heap is already way up in CodeBlock's business when 10 it comes to finalization, so I decided to finish the job and move full 11 responsibility for CodeBlock finalization into the heap. 12 13 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Maybe this 14 will build. 15 16 * debugger/Debugger.cpp: Updated for rename. 17 18 * heap/Heap.cpp: 19 (JSC::Heap::deleteAllCompiledCode): Renamed for consistency. Fixed a bug 20 where we would not delete code for a code block that had been previously 21 jettisoned. I don't know if this happens in practice -- I mostly did 22 this to improve consistency with deleteUnmarkedCompiledCode. 23 24 (JSC::Heap::deleteUnmarkedCompiledCode): New function, responsible for 25 eager finalization of unmarked code blocks. 26 27 (JSC::Heap::collect): Updated for rename. Updated to call 28 deleteUnmarkedCompiledCode(), which takes care of jettisoned DFG code 29 blocks too. 30 31 (JSC::Heap::addCompiledCode): Renamed, since this points to all code 32 now, not just functions. 33 34 * heap/Heap.h: 35 (Heap): Keep track of all user code, not just functions. This is a 36 negligible additional overhead, since most code is function code. 37 38 * runtime/Executable.cpp: 39 (JSC::*::finalize): Removed these functions, since we don't rely on 40 weak pointer finalization anymore. 41 42 (JSC::FunctionExecutable::FunctionExecutable): Moved linked-list stuff 43 into base class so all executables can be in the list. 44 45 (JSC::EvalExecutable::clearCode): 46 (JSC::ProgramExecutable::clearCode): 47 (JSC::FunctionExecutable::clearCode): All we need to do is delete our 48 CodeBlock -- that will delete all of its internal data structures. 49 50 (JSC::FunctionExecutable::clearCodeIfNotCompiling): Factored out a helper 51 function to improve clarity. 52 53 * runtime/Executable.h: 54 (JSC::ExecutableBase): Moved linked-list stuff 55 into base class so all executables can be in the list. 56 57 (JSC::NativeExecutable::create): 58 (NativeExecutable): 59 (ScriptExecutable): 60 (JSC::ScriptExecutable::finishCreation): 61 (JSC::EvalExecutable::create): 62 (EvalExecutable): 63 (JSC::ProgramExecutable::create): 64 (ProgramExecutable): 65 (FunctionExecutable): 66 (JSC::FunctionExecutable::create): Don't use a finalizer -- the heap 67 will call us back to destroy our code block. 68 69 (JSC::FunctionExecutable::discardCode): Renamed to clearCodeIfNotCompiling() 70 for clarity. 71 72 (JSC::FunctionExecutable::isCompiling): New helper function, for clarity. 73 74 (JSC::ScriptExecutable::clearCodeVirtual): New helper function, since 75 the heap needs to make polymorphic calls to clear code. 76 77 * runtime/JSGlobalData.cpp: 78 (JSC::StackPreservingRecompiler::operator()): 79 * runtime/JSGlobalObject.cpp: 80 (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Updated for 81 renames. 82 1 83 2012-06-07 Filip Pizlo <fpizlo@apple.com> 2 84 -
trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
r119655 r119844 152 152 ?detachThread@WTF@@YAXI@Z 153 153 ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z 154 ?d iscardAllCompiledCode@Heap@JSC@@QAEXXZ154 ?deleteAllCompiledCode@Heap@JSC@@QAEXXZ 155 155 ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z 156 156 ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z -
trunk/Source/JavaScriptCore/debugger/Debugger.cpp
r112555 r119844 80 80 81 81 ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec(); 82 executable-> discardCode();82 executable->clearCodeIfNotCompiling(); 83 83 if (m_debugger == function->scope()->globalObject->debugger()) 84 84 m_sourceProviders.add(executable->source().provider(), exec); -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r119633 r119844 644 644 } 645 645 646 void Heap::d iscardAllCompiledCode()647 { 648 // If JavaScript is running, it's not safe to recompile, since we'll end649 // up throwing awaycode that is live on the stack.646 void Heap::deleteAllCompiledCode() 647 { 648 // If JavaScript is running, it's not safe to delete code, since we'll end 649 // up deleting code that is live on the stack. 650 650 if (m_globalData->dynamicGlobalObject) 651 651 return; 652 652 653 for (FunctionExecutable* current = m_functions.head(); current; current = current->next()) 654 current->discardCode(); 653 for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) { 654 if (!current->isFunctionExecutable()) 655 continue; 656 static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling(); 657 } 658 659 m_dfgCodeBlocks.clearMarks(); 660 m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks(); 661 } 662 663 void Heap::deleteUnmarkedCompiledCode() 664 { 665 ExecutableBase* next; 666 for (ExecutableBase* current = m_compiledCode.head(); current; current = next) { 667 next = current->next(); 668 if (isMarked(current)) 669 continue; 670 671 // We do this because executable memory is limited on some platforms and because 672 // CodeBlock requires eager finalization. 673 ExecutableBase::clearCodeVirtual(current); 674 m_compiledCode.remove(current); 675 } 676 677 m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks(); 655 678 } 656 679 … … 681 704 double lastGCStartTime = WTF::currentTime(); 682 705 if (lastGCStartTime - m_lastCodeDiscardTime > minute) { 683 d iscardAllCompiledCode();706 deleteAllCompiledCode(); 684 707 m_lastCodeDiscardTime = WTF::currentTime(); 685 708 } … … 704 727 } 705 728 729 JAVASCRIPTCORE_GC_MARKED(); 730 706 731 { 707 732 GCPHASE(FinalizeUnconditionalFinalizers); … … 714 739 m_globalData->smallStrings.finalizeSmallStrings(); 715 740 } 716 717 JAVASCRIPTCORE_GC_MARKED();718 741 719 742 { 720 743 GCPHASE(DeleteCodeBlocks); 721 m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();744 deleteUnmarkedCompiledCode(); 722 745 } 723 746 … … 809 832 } 810 833 811 void Heap::addFunctionExecutable(FunctionExecutable* executable) 812 { 813 m_functions.append(executable); 814 } 815 816 void Heap::removeFunctionExecutable(FunctionExecutable* executable) 817 { 818 m_functions.remove(executable); 834 void Heap::addCompiledCode(ExecutableBase* executable) 835 { 836 m_compiledCode.append(executable); 819 837 } 820 838 -
trunk/Source/JavaScriptCore/heap/Heap.h
r119655 r119844 43 43 class CopiedSpace; 44 44 class CodeBlock; 45 class FunctionExecutable;45 class ExecutableBase; 46 46 class GCActivityCallback; 47 47 class GlobalCodeBlock; … … 117 117 typedef void (*Finalizer)(JSCell*); 118 118 JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer); 119 void addFunctionExecutable(FunctionExecutable*); 120 void removeFunctionExecutable(FunctionExecutable*); 119 void addCompiledCode(ExecutableBase*); 121 120 122 121 void notifyIsSafeToCollect() { m_isSafeToCollect = true; } … … 160 159 void increaseLastGCLength(double amount) { m_lastGCLength += amount; } 161 160 162 JS_EXPORT_PRIVATE void d iscardAllCompiledCode();161 JS_EXPORT_PRIVATE void deleteAllCompiledCode(); 163 162 164 163 void didAllocate(size_t); … … 195 194 void harvestWeakReferences(); 196 195 void finalizeUnconditionalFinalizers(); 196 void deleteUnmarkedCompiledCode(); 197 197 198 198 RegisterFile& registerFile(); … … 240 240 double m_lastCodeDiscardTime; 241 241 242 DoublyLinkedList< FunctionExecutable> m_functions;242 DoublyLinkedList<ExecutableBase> m_compiledCode; 243 243 }; 244 244 -
trunk/Source/JavaScriptCore/runtime/Executable.cpp
r118616 r119844 48 48 #endif 49 49 50 inlinevoid ExecutableBase::clearCode()50 void ExecutableBase::clearCode() 51 51 { 52 52 #if ENABLE(JIT) … … 98 98 } 99 99 #endif 100 101 void NativeExecutable::finalize(JSCell* cell)102 {103 jsCast<NativeExecutable*>(cell)->clearCode();104 }105 100 106 101 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; … … 147 142 , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName) 148 143 , m_symbolTable(0) 149 , m_next(0)150 , m_prev(0)151 144 { 152 145 } … … 160 153 , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName) 161 154 , m_symbolTable(0) 162 , m_next(0)163 , m_prev(0)164 155 { 165 156 } … … 293 284 } 294 285 295 void EvalExecutable::finalize(JSCell* cell) 296 { 297 jsCast<EvalExecutable*>(cell)->clearCode(); 298 } 299 300 inline void EvalExecutable::clearCode() 301 { 302 if (m_evalCodeBlock) { 303 m_evalCodeBlock->clearEvalCache(); 304 m_evalCodeBlock.clear(); 305 } 286 void EvalExecutable::clearCode() 287 { 288 m_evalCodeBlock.clear(); 306 289 Base::clearCode(); 307 290 } … … 425 408 } 426 409 427 void ProgramExecutable::finalize(JSCell* cell) 428 { 429 jsCast<ProgramExecutable*>(cell)->clearCode(); 430 } 431 432 inline void ProgramExecutable::clearCode() 433 { 434 if (m_programCodeBlock) { 435 m_programCodeBlock->clearEvalCache(); 436 m_programCodeBlock.clear(); 437 } 410 void ProgramExecutable::clearCode() 411 { 412 m_programCodeBlock.clear(); 438 413 Base::clearCode(); 439 414 } … … 643 618 } 644 619 645 void FunctionExecutable::discardCode() 646 { 647 #if ENABLE(JIT) 648 // These first two checks are to handle the rare case where 649 // we are trying to evict code for a function during its 650 // codegen. 651 if (!m_jitCodeForCall && m_codeBlockForCall) 620 void FunctionExecutable::clearCodeIfNotCompiling() 621 { 622 if (isCompiling()) 652 623 return; 653 if (!m_jitCodeForConstruct && m_codeBlockForConstruct)654 return;655 #endif656 624 clearCode(); 657 625 } 658 626 659 void FunctionExecutable::finalize(JSCell* cell) 660 { 661 FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); 662 Heap::heap(executable)->removeFunctionExecutable(executable); 663 executable->clearCode(); 664 } 665 666 inline void FunctionExecutable::clearCode() 667 { 668 if (m_codeBlockForCall) { 669 m_codeBlockForCall->clearEvalCache(); 670 m_codeBlockForCall.clear(); 671 } 672 if (m_codeBlockForConstruct) { 673 m_codeBlockForConstruct->clearEvalCache(); 674 m_codeBlockForConstruct.clear(); 675 } 627 void FunctionExecutable::clearCode() 628 { 629 m_codeBlockForCall.clear(); 630 m_codeBlockForConstruct.clear(); 676 631 Base::clearCode(); 677 632 } -
trunk/Source/JavaScriptCore/runtime/Executable.h
r118966 r119844 55 55 } 56 56 57 class ExecutableBase : public JSCell { 57 class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> { 58 friend class WTF::DoublyLinkedListNode<ExecutableBase>; 58 59 friend class JIT; 59 60 … … 81 82 #endif 82 83 84 bool isFunctionExecutable() 85 { 86 return structure()->typeInfo().type() == FunctionExecutableType; 87 } 88 83 89 bool isHostFunction() const 84 90 { … … 89 95 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } 90 96 97 void clearCode(); 98 91 99 static JS_EXPORTDATA const ClassInfo s_info; 92 100 … … 98 106 #if ENABLE(JIT) 99 107 public: 108 static void clearCodeVirtual(ExecutableBase*); 109 100 110 JITCode& generatedJITCodeForCall() 101 111 { … … 169 179 170 180 protected: 181 ExecutableBase* m_prev; 182 ExecutableBase* m_next; 183 171 184 JITCode m_jitCodeForCall; 172 185 JITCode m_jitCodeForConstruct; … … 174 187 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; 175 188 #endif 176 void clearCode();177 189 }; 178 190 … … 195 207 executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); 196 208 } 197 globalData.heap.addFinalizer(executable, &finalize);198 209 return executable; 199 210 } … … 206 217 NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); 207 218 executable->finishCreation(globalData); 208 globalData.heap.addFinalizer(executable, &finalize);209 219 return executable; 210 220 } … … 247 257 #endif 248 258 249 static void finalize(JSCell*);250 251 259 private: 252 260 NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) … … 304 312 { 305 313 Base::finishCreation(globalData); 314 globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). 315 306 316 #if ENABLE(CODEBLOCK_SAMPLING) 307 317 if (SamplingTool* sampler = globalData.interpreter->sampler()) … … 359 369 EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); 360 370 executable->finishCreation(exec->globalData()); 361 exec->globalData().heap.addFinalizer(executable, &finalize);362 371 return executable; 363 372 } … … 378 387 void unlinkCalls(); 379 388 380 protected:381 389 void clearCode(); 382 static void finalize(JSCell*);383 390 384 391 private: … … 401 408 ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); 402 409 executable->finishCreation(exec->globalData()); 403 exec->globalData().heap.addFinalizer(executable, &finalize);404 410 return executable; 405 411 } … … 448 454 void unlinkCalls(); 449 455 450 protected:451 456 void clearCode(); 452 static void finalize(JSCell*);453 457 454 458 private: … … 462 466 }; 463 467 464 class FunctionExecutable : public ScriptExecutable , public DoublyLinkedListNode<FunctionExecutable>{468 class FunctionExecutable : public ScriptExecutable { 465 469 friend class JIT; 466 470 friend class LLIntOffsetsExtractor; 467 friend class WTF::DoublyLinkedListNode<FunctionExecutable>;468 471 public: 469 472 typedef ScriptExecutable Base; … … 473 476 FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); 474 477 executable->finishCreation(exec->globalData(), name, firstLine, lastLine); 475 exec->globalData().heap.addFunctionExecutable(executable);476 exec->globalData().heap.addFinalizer(executable, &finalize);477 478 return executable; 478 479 } … … 482 483 FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); 483 484 executable->finishCreation(globalData, name, firstLine, lastLine); 484 globalData.heap.addFunctionExecutable(executable);485 globalData.heap.addFinalizer(executable, &finalize);486 485 return executable; 487 486 } … … 640 639 SharedSymbolTable* symbolTable() const { return m_symbolTable; } 641 640 642 void discardCode();641 void clearCodeIfNotCompiling(); 643 642 static void visitChildren(JSCell*, SlotVisitor&); 644 643 static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); … … 652 651 void unlinkCalls(); 653 652 653 void clearCode(); 654 654 655 protected: 655 void clearCode();656 static void finalize(JSCell*);657 658 656 void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine) 659 657 { … … 678 676 return m_codeBlockForConstruct; 679 677 } 680 678 679 bool isCompiling() 680 { 681 #if ENABLE(JIT) 682 if (!m_jitCodeForCall && m_codeBlockForCall) 683 return true; 684 if (!m_jitCodeForConstruct && m_codeBlockForConstruct) 685 return true; 686 #endif 687 return false; 688 } 689 681 690 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; 682 691 unsigned m_numCapturedVariables : 31; … … 690 699 WriteBarrier<JSString> m_nameValue; 691 700 SharedSymbolTable* m_symbolTable; 692 FunctionExecutable* m_next;693 FunctionExecutable* m_prev;694 701 }; 695 702 … … 724 731 return false; 725 732 return function->nativeFunction() == nativeFunction; 733 } 734 735 inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) 736 { 737 switch (executable->structure()->typeInfo().type()) { 738 case EvalExecutableType: 739 return jsCast<EvalExecutable*>(executable)->clearCode(); 740 case ProgramExecutableType: 741 return jsCast<ProgramExecutable*>(executable)->clearCode(); 742 case FunctionExecutableType: 743 return jsCast<FunctionExecutable*>(executable)->clearCode(); 744 default: 745 return jsCast<NativeExecutable*>(executable)->clearCode(); 746 } 726 747 } 727 748 -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp
r119441 r119844 420 420 if (currentlyExecutingFunctions.contains(executable)) 421 421 return; 422 executable-> discardCode();422 executable->clearCodeIfNotCompiling(); 423 423 } 424 424 }; -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r119655 r119844 444 444 #if ENABLE(ASSEMBLER) 445 445 if (ExecutableAllocator::underMemoryPressure()) 446 globalData.heap.d iscardAllCompiledCode();446 globalData.heap.deleteAllCompiledCode(); 447 447 #endif 448 448
Note: See TracChangeset
for help on using the changeset viewer.