Ignore:
Timestamp:
Apr 28, 2012, 1:51:27 PM (13 years ago)
Author:
[email protected]
Message:

Clarified JSGlobalData (JavaScript VM) lifetime
https://bugs.webkit.org/show_bug.cgi?id=85142

Reviewed by Anders Carlsson.

Source/JavaScriptCore:

This was so confusing that I didn't feel like I could reason about
memory lifetime in the heap without fixing it.

The rules are:

(1) JSGlobalData owns the virtual machine and all memory in it.

(2) Deleting a JSGlobalData frees the virtual machine and all memory
in it.

(Caveat emptor: if you delete the virtual machine while you're running
JIT code or accessing GC objects, you're gonna have a bad time.)

(I opted not to make arbitrary sub-objects keep the virtual machine
alive automatically because:

(a) doing that right would be complex and slow;

(b) in the case of an exiting thread or process, there's no
clear way to give the garbage collector a chance to try again
later;

(c) continuing to run the garbage collector after we've been
asked to shut down the virtual machine seems rude;

(d) we've never really supported that feature, anyway.)

(3) Normal ref-counting will do. No need to call a battery of
specialty functions to tear down a JSGlobalData. Its foibles
notwithstanding, C++ does in fact know how to execute destructors in
order.

  • API/JSContextRef.cpp:

(JSGlobalContextCreate): Removed compatibility shim for older
operating systems because it's no longer used.

(JSGlobalContextRelease): Now that we can rely on JSGlobalData to "do
the right thing", this code is much simpler. We still have one special
case to notify the garbage collector if we're removing the last
reference to the global object, since this can improve memory behavior.

  • heap/CopiedSpace.cpp:

(JSC::CopiedSpace::freeAllBlocks):

  • heap/CopiedSpace.h:

(CopiedSpace): Renamed "destroy" => "freeAllBlocks" because true
destruction-time behaviors should be limited to our C++ destructor.

  • heap/Heap.cpp:

(JSC::Heap::~Heap):
(JSC):
(JSC::Heap::lastChanceToFinalize):

  • heap/Heap.h:

(Heap):
(JSC::Heap::heap): Renamed "destroy" => "lastChanceToFinalize" because
true destruction-time behaviors should be limited to our C++
destructor.

Reorganized the code, putting code that must run before any objects
get torn down into lastChanceToFinalize, and code that just tears down
objects into our destructor.

  • heap/Local.h:

(JSC::LocalStack::LocalStack):
(JSC::LocalStack::push):
(LocalStack): See rule (2).

  • jsc.cpp:

(functionQuit):
(main):
(printUsageStatement):
(parseArguments):
(jscmain):

  • testRegExp.cpp:

(main):
(printUsageStatement):
(parseArguments):
(realMain): See rule (3).

I removed the feature of ensuring orderly tear-down when calling quit()
or running in --help mode because it didn't seem very useful and
making it work with Windows structured exception handling and
NO_RETURN didn't seem like a fun way to spend a Saturday.

  • runtime/JSGlobalData.h:
  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData): Moved heap to be the first data
member in JSGlobalData to ensure that it's destructed last, so other
objects that reference it destruct without crashing. This allowed me
to remove clearBuiltinStructures() altogether, and helped guarantee
rule (3).

(JSC::JSGlobalData::~JSGlobalData): Explicitly call
lastChanceToFinalize() at the head of our destructor to ensure that
all pending finalizers run while the virtual machine is still in a
valid state. Trying to resurrect (re-ref) the virtual machine at this
point is not valid, but all other operations are.

Changed a null to a 0xbbadbeef to clarify just how bad this beef is.

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObject.h:

(JSGlobalObject):
(JSC::JSGlobalObject::globalData): See rule (3).

Source/WebCore:

  • bindings/js/WorkerScriptController.cpp:

(WebCore::WorkerScriptController::~WorkerScriptController): Slightly
simpler than before. We can't just rely on our default destructor
because we need to hold the JSLock when we tear down the VM.

  • bridge/NP_jsobject.cpp:

(_NPN_InvokeDefault):
(_NPN_Invoke):
(_NPN_Evaluate):
(_NPN_Construct): Don't RefPtr<> the JSGlobalData because it makes it
seem like you know something the rest of our code doesn't know. The
plugin JSGlobalData is immortal, anyway.

I also removed some timeout checker related code because that feature
doesn't work anymore, so it was effectively dead code.

Source/WebKit/mac:

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::invoke):
(WebKit::NetscapePluginInstanceProxy::invokeDefault):
(WebKit::NetscapePluginInstanceProxy::construct):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jsc.cpp

    r115523 r115579  
    8181using namespace WTF;
    8282
    83 static void cleanupGlobalData(JSGlobalData*);
    8483static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
    8584
     
    418417}
    419418
    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());
     419EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
     420{
    428421    exit(EXIT_SUCCESS);
    429422
     
    447440#endif
    448441
    449 int jscmain(int argc, char** argv, JSGlobalData*);
     442int jscmain(int argc, char** argv);
    450443
    451444int main(int argc, char** argv)
     
    492485    // Structured Exception Handling
    493486    int res = 0;
    494     JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap).leakRef();
    495487    TRY
    496         res = jscmain(argc, argv, globalData);
     488        res = jscmain(argc, argv);
    497489    EXCEPT(res = 3)
    498 
    499     cleanupGlobalData(globalData);
    500490    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();
    509491}
    510492
     
    614596}
    615597
    616 static NO_RETURN void printUsageStatement(JSGlobalData* globalData, bool help = false)
     598static NO_RETURN void printUsageStatement(bool help = false)
    617599{
    618600    fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
     
    626608#endif
    627609
    628     cleanupGlobalData(globalData);
    629610    exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
    630611}
    631612
    632 static void parseArguments(int argc, char** argv, CommandLine& options, JSGlobalData* globalData)
     613static void parseArguments(int argc, char** argv, CommandLine& options)
    633614{
    634615    int i = 1;
     
    637618        if (!strcmp(arg, "-f")) {
    638619            if (++i == argc)
    639                 printUsageStatement(globalData);
     620                printUsageStatement();
    640621            options.scripts.append(Script(true, argv[i]));
    641622            continue;
     
    643624        if (!strcmp(arg, "-e")) {
    644625            if (++i == argc)
    645                 printUsageStatement(globalData);
     626                printUsageStatement();
    646627            options.scripts.append(Script(false, argv[i]));
    647628            continue;
     
    669650        }
    670651        if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
    671             printUsageStatement(globalData, true);
     652            printUsageStatement(true);
    672653        options.scripts.append(Script(true, argv[i]));
    673654    }
     
    680661}
    681662
    682 int jscmain(int argc, char** argv, JSGlobalData* globalData)
     663int jscmain(int argc, char** argv)
    683664{
    684665    JSLock lock(SilenceAssertionsOnly);
    685666
     667    RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
     668
    686669    CommandLine options;
    687     parseArguments(argc, argv, options, globalData);
     670    parseArguments(argc, argv, options);
    688671
    689672    GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
Note: See TracChangeset for help on using the changeset viewer.