Ignore:
Timestamp:
Jun 29, 2017, 10:34:57 AM (8 years ago)
Author:
[email protected]
Message:

VMTraps has some races
https://bugs.webkit.org/show_bug.cgi?id=173941

Reviewed by Michael Saboff.

Source/JavaScriptCore:

This patch refactors much of the VMTraps API.

On the message sending side:

1) No longer uses the Yarr JIT check to determine if we are in
RegExp code. That was unsound because RegExp JIT code can be run
on compilation threads. Instead it looks at the current frame's
code block slot and checks if it is valid, which is the same as
what it did for JIT code previously.

2) Only have one signal sender thread, previously, there could be
many at once, which caused some data races. Additionally, the
signal sender thread is an automatic thread so it will deallocate
itself when not in use.

On the VMTraps breakpoint side:

1) We now have a true mapping of if we hit a breakpoint instead of
a JIT assertion. So the exception handler won't eat JIT assertions
anymore.

2) It jettisons all CodeBlocks that have VMTraps breakpoints on
them instead of every CodeBlock on the stack. This both prevents
us from hitting stale VMTraps breakpoints and also doesn't OSR
codeblocks that otherwise don't need to be jettisoned.

3) The old exception handler could theoretically fail for a couple
of reasons then resume execution with a clobbered instruction
set. This patch will kill the program if the exception handler
would fail.

This patch also refactors some of the jsc.cpp functions to take the
CommandLine options object instead of individual options. Also, there
is a new command line option that makes exceptions due to watchdog
timeouts an acceptable result.

  • API/tests/testapi.c:

(main):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::installVMTrapBreakpoints):

  • dfg/DFGCommonData.cpp:

(JSC::DFG::pcCodeBlockMap):
(JSC::DFG::CommonData::invalidate):
(JSC::DFG::CommonData::~CommonData):
(JSC::DFG::CommonData::installVMTrapBreakpoints):
(JSC::DFG::codeBlockForVMTrapPC):

  • dfg/DFGCommonData.h:
  • jsc.cpp:

(functionDollarAgentStart):
(checkUncaughtException):
(checkException):
(runWithOptions):
(printUsageStatement):
(CommandLine::parseArguments):
(jscmain):
(runWithScripts): Deleted.

  • runtime/JSLock.cpp:

(JSC::JSLock::didAcquireLock):

  • runtime/VMTraps.cpp:

(JSC::sanitizedTopCallFrame):
(JSC::VMTraps::tryInstallTrapBreakpoints):
(JSC::VMTraps::willDestroyVM):
(JSC::VMTraps::fireTrap):
(JSC::VMTraps::handleTraps):
(JSC::VMTraps::VMTraps):
(JSC::VMTraps::~VMTraps):
(JSC::findActiveVMAndStackBounds): Deleted.
(JSC::installSignalHandler): Deleted.
(JSC::VMTraps::addSignalSender): Deleted.
(JSC::VMTraps::removeSignalSender): Deleted.
(JSC::VMTraps::SignalSender::willDestroyVM): Deleted.
(JSC::VMTraps::SignalSender::send): Deleted.

  • runtime/VMTraps.h:

(JSC::VMTraps::~VMTraps): Deleted.
(JSC::VMTraps::SignalSender::SignalSender): Deleted.

Tools:

Add new testing mode for testing the Watchdog with our stress
tests.

  • Scripts/run-jsc-stress-tests:
File:
1 edited

Legend:

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

    r218816 r218936  
    987987template<typename Func>
    988988int runJSC(CommandLine, bool isWorker, const Func&);
    989 static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success);
     989static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, CommandLine&, bool& success);
    990990
    991991class Message : public ThreadSafeRefCounted<Message> {
     
    12111211    String m_profilerOutput;
    12121212    String m_uncaughtExceptionName;
     1213    bool m_treatWatchdogExceptionAsSuccess { false };
    12131214    bool m_alwaysDumpUncaughtException { false };
    12141215    bool m_dumpSamplingProfilerData { false };
     
    26182619                    if (evaluationException)
    26192620                        result = evaluationException->value();
    2620                     checkException(globalObject, true, evaluationException, result, String(), false, false, success);
     2621                    checkException(globalObject, true, evaluationException, result, commandLine, success);
    26212622                    if (!success)
    26222623                        exit(1);
     
    32933294}
    32943295
    3295 static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const String& expectedExceptionName, bool alwaysDumpException)
    3296 {
     3296static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, CommandLine& options)
     3297{
     3298    const String& expectedExceptionName = options.m_uncaughtExceptionName;
    32973299    auto scope = DECLARE_CATCH_SCOPE(vm);
    32983300    scope.clearException();
     
    33153317    }
    33163318    if (isInstanceOfExpectedException) {
    3317         if (alwaysDumpException)
     3319        if (options.m_alwaysDumpUncaughtException)
    33183320            dumpException(globalObject, exception);
    33193321        return true;
     
    33253327}
    33263328
    3327 static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success)
     3329static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, CommandLine& options, bool& success)
    33283330{
    33293331    VM& vm = globalObject->vm();
    3330     if (!uncaughtExceptionName || !isLastFile) {
     3332
     3333    if (options.m_treatWatchdogExceptionAsSuccess && value.inherits(vm, TerminatedExecutionError::info())) {
     3334        ASSERT(hasException);
     3335        return;
     3336    }
     3337
     3338    if (!options.m_uncaughtExceptionName || !isLastFile) {
    33313339        success = success && !hasException;
    3332         if (dump && !hasException)
     3340        if (options.m_dump && !hasException)
    33333341            printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
    33343342        if (hasException)
    33353343            dumpException(globalObject, value);
    33363344    } else
    3337         success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
    3338 }
    3339 
    3340 static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
    3341 {
     3345        success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), options);
     3346}
     3347
     3348static bool runWithOptions(GlobalObject* globalObject, CommandLine& options)
     3349{
     3350    Vector<Script>& scripts = options.m_scripts;
    33423351    String fileName;
    33433352    Vector<char> scriptBuffer;
    33443353
    3345     if (dump)
     3354    if (options.m_dump)
    33463355        JSC::Options::dumpGeneratedBytecodes() = true;
    33473356
     
    33563365    for (size_t i = 0; i < scripts.size(); i++) {
    33573366        JSInternalPromise* promise = nullptr;
    3358         bool isModule = module || scripts[i].scriptType == Script::ScriptType::Module;
     3367        bool isModule = options.m_module || scripts[i].scriptType == Script::ScriptType::Module;
    33593368        if (scripts[i].codeSource == Script::CodeSource::File) {
    33603369            fileName = scripts[i].argument;
     
    33833392
    33843393            JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
    3385                 checkException(globalObject, isLastFile, false, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
     3394                checkException(globalObject, isLastFile, false, exec->argument(0), options, success);
    33863395                return JSValue::encode(jsUndefined());
    33873396            });
    33883397
    33893398            JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
    3390                 checkException(globalObject, isLastFile, true, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
     3399                checkException(globalObject, isLastFile, true, exec->argument(0), options, success);
    33913400                return JSValue::encode(jsUndefined());
    33923401            });
     
    34013410            if (evaluationException)
    34023411                returnValue = evaluationException->value();
    3403             checkException(globalObject, isLastFile, evaluationException, returnValue, uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
     3412            checkException(globalObject, isLastFile, evaluationException, returnValue, options, success);
    34043413        }
    34053414
     
    35033512    fprintf(stderr, "  --module-file=<file>       Parse and evaluate the given file as module (this option may be passed more than once)\n");
    35043513    fprintf(stderr, "  --exception=<name>         Check the last script exits with an uncaught exception with the specified name\n");
     3514    fprintf(stderr, "  --watchdog-exception-ok    Uncaught watchdog exceptions exit with success\n");
    35053515    fprintf(stderr, "  --dumpException            Dump uncaught exception text\n");
    35063516    fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
     
    36293639        if (!strncmp(arg, "--exception=", exceptionStrLength)) {
    36303640            m_uncaughtExceptionName = String(arg + exceptionStrLength);
     3641            continue;
     3642        }
     3643
     3644        if (!strcmp(arg, "--watchdog-exception-ok")) {
     3645            m_treatWatchdogExceptionAsSuccess = true;
    36313646            continue;
    36323647        }
     
    37793794        options, false,
    37803795        [&] (VM&, GlobalObject* globalObject) {
    3781             return runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
     3796            return runWithOptions(globalObject, options);
    37823797        });
    37833798
Note: See TracChangeset for help on using the changeset viewer.