Changeset 115579 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Apr 28, 2012, 1:51:27 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/JSContextRef.cpp
r115156 r115579 39 39 #include <wtf/text/StringHash.h> 40 40 41 42 #if OS(DARWIN)43 #include <mach-o/dyld.h>44 45 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.046 #endif47 48 41 using namespace JSC; 42 43 // From the API's perspective, a context group remains alive iff 44 // (a) it has been JSContextGroupRetained 45 // OR 46 // (b) one of its contexts has been JSContextRetained 49 47 50 48 JSContextGroupRef JSContextGroupCreate() … … 65 63 } 66 64 65 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained. 66 67 67 JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) 68 68 { 69 69 initializeThreading(); 70 #if OS(DARWIN)71 // When running on Tiger or Leopard, or if the application was linked before JSGlobalContextCreate was changed72 // to use a unique JSGlobalData, we use a shared one for compatibility.73 #ifndef BUILDING_ON_LEOPARD74 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {75 #else76 {77 #endif78 JSLock lock(LockForReal);79 return JSGlobalContextCreateInGroup(toRef(&JSGlobalData::sharedInstance()), globalObjectClass);80 }81 #endif // OS(DARWIN)82 83 70 return JSGlobalContextCreateInGroup(0, globalObjectClass); 84 71 } … … 126 113 127 114 JSGlobalData& globalData = exec->globalData(); 128 JSGlobalObject* dgo = exec->dynamicGlobalObject();129 115 IdentifierTable* savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(globalData.identifierTable); 130 116 131 // One reference is held by JSGlobalObject, another added by JSGlobalContextRetain(). 132 bool releasingContextGroup = globalData.refCount() == 2; 133 bool releasingGlobalObject = Heap::heap(dgo)->unprotect(dgo); 134 // If this is the last reference to a global data, it should also 135 // be the only remaining reference to the global object too! 136 ASSERT(!releasingContextGroup || releasingGlobalObject); 137 138 // An API 'JSGlobalContextRef' retains two things - a global object and a 139 // global data (or context group, in API terminology). 140 // * If this is the last reference to any contexts in the given context group, 141 // call destroy on the heap (the global data is being freed). 142 // * If this was the last reference to the global object, then unprotecting 143 // it may release a lot of GC memory - tickle the activity callback to 144 // garbage collect soon. 145 // * If there are more references remaining the the global object, then do nothing 146 // (specifically that is more protects, which we assume come from other JSGlobalContextRefs). 147 if (releasingContextGroup) { 148 globalData.clearBuiltinStructures(); 149 globalData.heap.destroy(); 150 } else if (releasingGlobalObject) { 117 bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); 118 if (protectCountIsZero) { 151 119 globalData.heap.activityCallback()->synchronize(); 152 120 globalData.heap.reportAbandonedObjectGraph(); 153 121 } 154 155 122 globalData.deref(); 156 123 -
trunk/Source/JavaScriptCore/ChangeLog
r115548 r115579 1 2012-04-28 Geoffrey Garen <[email protected]> 2 3 Clarified JSGlobalData (JavaScript VM) lifetime 4 https://bugs.webkit.org/show_bug.cgi?id=85142 5 6 Reviewed by Anders Carlsson. 7 8 This was so confusing that I didn't feel like I could reason about 9 memory lifetime in the heap without fixing it. 10 11 The rules are: 12 13 (1) JSGlobalData owns the virtual machine and all memory in it. 14 15 (2) Deleting a JSGlobalData frees the virtual machine and all memory 16 in it. 17 18 (Caveat emptor: if you delete the virtual machine while you're running 19 JIT code or accessing GC objects, you're gonna have a bad time.) 20 21 (I opted not to make arbitrary sub-objects keep the virtual machine 22 alive automatically because: 23 24 (a) doing that right would be complex and slow; 25 26 (b) in the case of an exiting thread or process, there's no 27 clear way to give the garbage collector a chance to try again 28 later; 29 30 (c) continuing to run the garbage collector after we've been 31 asked to shut down the virtual machine seems rude; 32 33 (d) we've never really supported that feature, anyway.) 34 35 (3) Normal ref-counting will do. No need to call a battery of 36 specialty functions to tear down a JSGlobalData. Its foibles 37 notwithstanding, C++ does in fact know how to execute destructors in 38 order. 39 40 * API/JSContextRef.cpp: 41 (JSGlobalContextCreate): Removed compatibility shim for older 42 operating systems because it's no longer used. 43 44 (JSGlobalContextRelease): Now that we can rely on JSGlobalData to "do 45 the right thing", this code is much simpler. We still have one special 46 case to notify the garbage collector if we're removing the last 47 reference to the global object, since this can improve memory behavior. 48 49 * heap/CopiedSpace.cpp: 50 (JSC::CopiedSpace::freeAllBlocks): 51 * heap/CopiedSpace.h: 52 (CopiedSpace): Renamed "destroy" => "freeAllBlocks" because true 53 destruction-time behaviors should be limited to our C++ destructor. 54 55 * heap/Heap.cpp: 56 (JSC::Heap::~Heap): 57 (JSC): 58 (JSC::Heap::lastChanceToFinalize): 59 * heap/Heap.h: 60 (Heap): 61 (JSC::Heap::heap): Renamed "destroy" => "lastChanceToFinalize" because 62 true destruction-time behaviors should be limited to our C++ 63 destructor. 64 65 Reorganized the code, putting code that must run before any objects 66 get torn down into lastChanceToFinalize, and code that just tears down 67 objects into our destructor. 68 69 * heap/Local.h: 70 (JSC::LocalStack::LocalStack): 71 (JSC::LocalStack::push): 72 (LocalStack): See rule (2). 73 74 * jsc.cpp: 75 (functionQuit): 76 (main): 77 (printUsageStatement): 78 (parseArguments): 79 (jscmain): 80 * testRegExp.cpp: 81 (main): 82 (printUsageStatement): 83 (parseArguments): 84 (realMain): See rule (3). 85 86 I removed the feature of ensuring orderly tear-down when calling quit() 87 or running in --help mode because it didn't seem very useful and 88 making it work with Windows structured exception handling and 89 NO_RETURN didn't seem like a fun way to spend a Saturday. 90 91 * runtime/JSGlobalData.h: 92 * runtime/JSGlobalData.cpp: 93 (JSC::JSGlobalData::JSGlobalData): Moved heap to be the first data 94 member in JSGlobalData to ensure that it's destructed last, so other 95 objects that reference it destruct without crashing. This allowed me 96 to remove clearBuiltinStructures() altogether, and helped guarantee 97 rule (3). 98 99 (JSC::JSGlobalData::~JSGlobalData): Explicitly call 100 lastChanceToFinalize() at the head of our destructor to ensure that 101 all pending finalizers run while the virtual machine is still in a 102 valid state. Trying to resurrect (re-ref) the virtual machine at this 103 point is not valid, but all other operations are. 104 105 Changed a null to a 0xbbadbeef to clarify just how bad this beef is. 106 107 * runtime/JSGlobalObject.cpp: 108 (JSC::JSGlobalObject::init): 109 * runtime/JSGlobalObject.h: 110 (JSGlobalObject): 111 (JSC::JSGlobalObject::globalData): See rule (3). 112 1 113 2012-04-27 Geoffrey Garen <[email protected]> 2 114 -
trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp
r114698 r115579 250 250 } 251 251 252 void CopiedSpace:: destroy()252 void CopiedSpace::freeAllBlocks() 253 253 { 254 254 while (!m_toSpace->isEmpty()) { -
trunk/Source/JavaScriptCore/heap/CopiedSpace.h
r114698 r115579 70 70 size_t capacity(); 71 71 72 void destroy();72 void freeAllBlocks(); 73 73 74 74 static CopiedBlock* blockFor(void*); -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r115545 r115579 342 342 Heap::~Heap() 343 343 { 344 // Destroy our block freeing thread. 344 delete m_markListSet; 345 346 m_objectSpace.shrink(); 347 m_storageSpace.freeAllBlocks(); 348 releaseFreeBlocks(); 345 349 { 346 350 MutexLocker locker(m_freeBlockLock); … … 350 354 waitForThreadCompletion(m_blockFreeingThread); 351 355 352 // The destroy function must already have been called, so assert this. 353 ASSERT(!m_globalData); 354 } 355 356 void Heap::destroy() 357 { 358 JSLock lock(SilenceAssertionsOnly); 359 360 if (!m_globalData) 361 return; 362 356 ASSERT(!size()); 357 ASSERT(!capacity()); 358 } 359 360 // The JSGlobalData is being destroyed and the collector will never run again. 361 // Run all pending finalizers now because we won't get another chance. 362 void Heap::lastChanceToFinalize() 363 { 363 364 ASSERT(!m_globalData->dynamicGlobalObject); 364 365 ASSERT(m_operationInProgress == NoOperation); 365 366 // The global object is not GC protected at this point, so sweeping may delete it 367 // (and thus the global data) before other objects that may use the global data. 368 RefPtr<JSGlobalData> protect(m_globalData); 369 370 #if ENABLE(JIT) 371 m_globalData->jitStubs->clearHostFunctionStubs(); 372 #endif 373 374 delete m_markListSet; 375 m_markListSet = 0; 376 366 367 // FIXME: Make this a release-mode crash once we're sure no one's doing this. 368 if (size_t size = m_protectedValues.size()) 369 LOG_ERROR("JavaScriptCore heap deallocated while %ld values were still protected", size); 370 371 m_weakSet.finalizeAll(); 377 372 canonicalizeCellLivenessData(); 378 373 clearMarks(); 379 380 m_weakSet.finalizeAll(); 374 sweep(); 381 375 m_globalData->smallStrings.finalizeSmallStrings(); 382 m_objectSpace.shrink();383 m_storageSpace.destroy();384 ASSERT(!size());385 376 386 377 #if ENABLE(SIMPLE_HEAP_PROFILING) … … 388 379 m_destroyedTypeCounts.dump(WTF::dataFile(), "Destroyed Type Counts"); 389 380 #endif 390 391 releaseFreeBlocks();392 393 m_globalData = 0;394 381 } 395 382 -
trunk/Source/JavaScriptCore/heap/Heap.h
r115288 r115579 75 75 friend class JIT; 76 76 friend class MarkStackThreadSharedData; 77 static Heap* heap( JSValue); // 0 for immediate values78 static Heap* heap( JSCell*);77 static Heap* heap(const JSValue); // 0 for immediate values 78 static Heap* heap(const JSCell*); 79 79 80 80 static bool isMarked(const void*); … … 88 88 Heap(JSGlobalData*, HeapSize); 89 89 ~Heap(); 90 JS_EXPORT_PRIVATE void destroy(); // JSGlobalData must call destroy() before ~Heap().90 JS_EXPORT_PRIVATE void lastChanceToFinalize(); 91 91 92 92 JSGlobalData* globalData() const { return m_globalData; } … … 267 267 } 268 268 269 inline Heap* Heap::heap( JSCell* cell)269 inline Heap* Heap::heap(const JSCell* cell) 270 270 { 271 271 return MarkedBlock::blockFor(cell)->heap(); 272 272 } 273 273 274 inline Heap* Heap::heap( JSValue v)274 inline Heap* Heap::heap(const JSValue v) 275 275 { 276 276 if (!v.isCell()) -
trunk/Source/JavaScriptCore/heap/Local.h
r96465 r115579 103 103 public: 104 104 LocalStack(JSGlobalData& globalData) 105 : m_globalData( &globalData)105 : m_globalData(globalData) 106 106 , m_count(0) 107 107 { … … 123 123 { 124 124 if (m_count == m_stack.size()) 125 m_stack.append(Local<T>( *m_globalData, value));125 m_stack.append(Local<T>(m_globalData, value)); 126 126 else 127 127 m_stack[m_count] = value; … … 133 133 134 134 private: 135 RefPtr<JSGlobalData>m_globalData;135 JSGlobalData& m_globalData; 136 136 Vector<Local<T>, inlineCapacity> m_stack; 137 137 unsigned m_count; -
trunk/Source/JavaScriptCore/jsc.cpp
r115523 r115579 81 81 using namespace WTF; 82 82 83 static void cleanupGlobalData(JSGlobalData*);84 83 static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer); 85 84 … … 418 417 } 419 418 420 EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec) 421 { 422 // Technically, destroying the heap in the middle of JS execution is a no-no, 423 // but we want to maintain compatibility with the Mozilla test suite, so 424 // we pretend that execution has terminated to avoid ASSERTs, then tear down the heap. 425 exec->globalData().dynamicGlobalObject = 0; 426 427 cleanupGlobalData(&exec->globalData()); 419 EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*) 420 { 428 421 exit(EXIT_SUCCESS); 429 422 … … 447 440 #endif 448 441 449 int jscmain(int argc, char** argv , JSGlobalData*);442 int jscmain(int argc, char** argv); 450 443 451 444 int main(int argc, char** argv) … … 492 485 // Structured Exception Handling 493 486 int res = 0; 494 JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap).leakRef();495 487 TRY 496 res = jscmain(argc, argv , globalData);488 res = jscmain(argc, argv); 497 489 EXCEPT(res = 3) 498 499 cleanupGlobalData(globalData);500 490 return res; 501 }502 503 static void cleanupGlobalData(JSGlobalData* globalData)504 {505 JSLock lock(SilenceAssertionsOnly);506 globalData->clearBuiltinStructures();507 globalData->heap.destroy();508 globalData->deref();509 491 } 510 492 … … 614 596 } 615 597 616 static NO_RETURN void printUsageStatement( JSGlobalData* globalData,bool help = false)598 static NO_RETURN void printUsageStatement(bool help = false) 617 599 { 618 600 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n"); … … 626 608 #endif 627 609 628 cleanupGlobalData(globalData);629 610 exit(help ? EXIT_SUCCESS : EXIT_FAILURE); 630 611 } 631 612 632 static void parseArguments(int argc, char** argv, CommandLine& options , JSGlobalData* globalData)613 static void parseArguments(int argc, char** argv, CommandLine& options) 633 614 { 634 615 int i = 1; … … 637 618 if (!strcmp(arg, "-f")) { 638 619 if (++i == argc) 639 printUsageStatement( globalData);620 printUsageStatement(); 640 621 options.scripts.append(Script(true, argv[i])); 641 622 continue; … … 643 624 if (!strcmp(arg, "-e")) { 644 625 if (++i == argc) 645 printUsageStatement( globalData);626 printUsageStatement(); 646 627 options.scripts.append(Script(false, argv[i])); 647 628 continue; … … 669 650 } 670 651 if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) 671 printUsageStatement( globalData,true);652 printUsageStatement(true); 672 653 options.scripts.append(Script(true, argv[i])); 673 654 } … … 680 661 } 681 662 682 int jscmain(int argc, char** argv , JSGlobalData* globalData)663 int jscmain(int argc, char** argv) 683 664 { 684 665 JSLock lock(SilenceAssertionsOnly); 685 666 667 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap); 668 686 669 CommandLine options; 687 parseArguments(argc, argv, options , globalData);670 parseArguments(argc, argv, options); 688 671 689 672 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments); -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp
r115248 r115579 90 90 91 91 JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize) 92 : globalDataType(globalDataType) 92 : heap(this, heapSize) 93 , globalDataType(globalDataType) 93 94 , clientData(0) 94 95 , topCallFrame(CallFrame::noCaller()) … … 120 121 , keywords(adoptPtr(new Keywords(this))) 121 122 , interpreter(0) 122 , heap(this, heapSize)123 123 , jsArrayClassInfo(&JSArray::s_info) 124 124 , jsFinalObjectClassInfo(&JSFinalObject::s_info) … … 211 211 } 212 212 213 void JSGlobalData::clearBuiltinStructures()214 {215 structureStructure.clear();216 debuggerActivationStructure.clear();217 activationStructure.clear();218 interruptedExecutionErrorStructure.clear();219 terminatedExecutionErrorStructure.clear();220 staticScopeStructure.clear();221 strictEvalActivationStructure.clear();222 stringStructure.clear();223 notAnObjectStructure.clear();224 propertyNameIteratorStructure.clear();225 getterSetterStructure.clear();226 apiWrapperStructure.clear();227 scopeChainNodeStructure.clear();228 executableStructure.clear();229 nativeExecutableStructure.clear();230 evalExecutableStructure.clear();231 programExecutableStructure.clear();232 functionExecutableStructure.clear();233 regExpStructure.clear();234 structureChainStructure.clear();235 }236 237 213 JSGlobalData::~JSGlobalData() 238 214 { 239 // By the time this is destroyed, heap.destroy() must already have been called.215 heap.lastChanceToFinalize(); 240 216 241 217 delete interpreter; 242 218 #ifndef NDEBUG 243 // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance. 244 interpreter = 0; 219 interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); 245 220 #endif 246 221 -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.h
r113445 r115579 153 153 void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } 154 154 155 Heap heap; // The heap is our first data member to ensure that it's destructed after all the objects that reference it. 156 155 157 GlobalDataType globalDataType; 156 158 ClientData* clientData; … … 253 255 TimeoutChecker timeoutChecker; 254 256 Terminator terminator; 255 Heap heap;256 257 257 258 JSValue exception; … … 330 331 #endif 331 332 JS_EXPORT_PRIVATE void dumpRegExpTrace(); 332 JS_EXPORT_PRIVATE void clearBuiltinStructures();333 333 334 334 bool isCollectorBusy() { return heap.isBusy(); } -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r112624 r115579 134 134 structure()->disableSpecificFunctionTracking(); 135 135 136 m_globalData = Heap::heap(this)->globalData(); 137 m_globalScopeChain.set(*m_globalData, this, ScopeChainNode::create(0, this, m_globalData.get(), this, thisValue)); 136 m_globalScopeChain.set(globalData(), this, ScopeChainNode::create(0, this, &globalData(), this, thisValue)); 138 137 139 138 JSGlobalObject::globalExec()->init(0, 0, m_globalScopeChain.get(), CallFrame::noCaller(), 0, 0); -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h
r113363 r115579 87 87 protected: 88 88 89 RefPtr<JSGlobalData> m_globalData;90 91 89 size_t m_registerArraySize; 92 90 Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; … … 303 301 void resetPrototype(JSGlobalData&, JSValue prototype); 304 302 305 JSGlobalData& globalData() const { return * m_globalData.get(); }303 JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); } 306 304 307 305 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) -
trunk/Source/JavaScriptCore/testRegExp.cpp
r112454 r115579 55 55 using namespace WTF; 56 56 57 static void cleanupGlobalData(JSGlobalData*);58 59 57 struct CommandLine { 60 58 CommandLine() … … 160 158 #endif 161 159 162 int realMain(int argc, char** argv , JSGlobalData*);160 int realMain(int argc, char** argv); 163 161 164 162 int main(int argc, char** argv) … … 194 192 // Structured Exception Handling 195 193 int res = 0; 196 JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap).leakRef();197 194 TRY 198 res = realMain(argc, argv , globalData);195 res = realMain(argc, argv); 199 196 EXCEPT(res = 3) 200 201 cleanupGlobalData(globalData);202 197 return res; 203 }204 205 static void cleanupGlobalData(JSGlobalData* globalData)206 {207 JSLock lock(SilenceAssertionsOnly);208 globalData->clearBuiltinStructures();209 globalData->heap.destroy();210 globalData->deref();211 198 } 212 199 … … 481 468 #define RUNNING_FROM_XCODE 0 482 469 483 static NO_RETURN void printUsageStatement( JSGlobalData* globalData,bool help = false)470 static NO_RETURN void printUsageStatement(bool help = false) 484 471 { 485 472 fprintf(stderr, "Usage: regexp_test [options] file\n"); … … 487 474 fprintf(stderr, " -v|--verbose Verbose output\n"); 488 475 489 cleanupGlobalData(globalData);490 476 exit(help ? EXIT_SUCCESS : EXIT_FAILURE); 491 477 } 492 478 493 static void parseArguments(int argc, char** argv, CommandLine& options , JSGlobalData* globalData)479 static void parseArguments(int argc, char** argv, CommandLine& options) 494 480 { 495 481 int i = 1; … … 497 483 const char* arg = argv[i]; 498 484 if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) 499 printUsageStatement( globalData,true);485 printUsageStatement(true); 500 486 if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) 501 487 options.verbose = true; … … 508 494 } 509 495 510 int realMain(int argc, char** argv , JSGlobalData* globalData)496 int realMain(int argc, char** argv) 511 497 { 512 498 JSLock lock(SilenceAssertionsOnly); 513 499 500 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap); 501 514 502 CommandLine options; 515 parseArguments(argc, argv, options , globalData);503 parseArguments(argc, argv, options); 516 504 517 505 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
Note:
See TracChangeset
for help on using the changeset viewer.