Changeset 188648 in webkit


Ignore:
Timestamp:
Aug 19, 2015 1:41:30 PM (9 years ago)
Author:
mark.lam@apple.com
Message:

Add ability to save and restore JSC options.
https://bugs.webkit.org/show_bug.cgi?id=148125

Reviewed by Saam Barati.

  • API/tests/ExecutionTimeLimitTest.cpp:

(testExecutionTimeLimit):

  • Employ the new options getter/setter to run watchdog tests for each of the execution engine tiers.
  • Also altered the test scripts to be in a function instead of global code. This is one of 2 changes needed to give them an opportunity to be FTL compiled. The other is to add support for compiling CheckWatchdogTimer in the FTL (which will be addressed in a separate patch).
  • jsc.cpp:

(CommandLine::parseArguments):

  • runtime/Options.cpp:

(JSC::parse):

  • Add the ability to clear a string option with a nullptr value. This is needed to restore a default string option value which may be null.

(JSC::OptionRange::init):

  • Add the ability to clear a range option with a null value. This is needed to restore a default range option value which may be null.

(JSC::Options::initialize):
(JSC::Options::dumpOptionsIfNeeded):

  • Factor code to dump options out to dumpOptionsIfNeeded() since we will need that logic elsewhere.

(JSC::Options::setOptions):

  • Parse an options string and set each of the specified options.

(JSC::Options::dumpAllOptions):
(JSC::Options::dumpAllOptionsInALine):
(JSC::Options::dumpOption):
(JSC::Option::dump):

  • Refactored so that the underlying dumper dumps to a StringBuilder instead of stderr. This lets us reuse this code to serialize all the options into a single string for dumpAllOptionsInALine().
  • runtime/Options.h:

(JSC::OptionRange::rangeString):

Location:
trunk/Source/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp

    r188329 r188648  
    2727#include "ExecutionTimeLimitTest.h"
    2828
     29#include "InitializeThreading.h"
    2930#include "JSContextRefPrivate.h"
    3031#include "JavaScriptCore.h"
     32#include "Options.h"
    3133#include <chrono>
    3234#include <wtf/CurrentTime.h>
     35#include <wtf/text/StringBuilder.h>
    3336
    3437using namespace std::chrono;
     38using JSC::Options;
    3539
    3640static JSGlobalContextRef context = nullptr;
     
    7983}
    8084
     85struct TierOptions {
     86    const char* tier;
     87    unsigned timeLimitAdjustmentMillis;
     88    const char* optionsStr;
     89};
    8190
    8291int testExecutionTimeLimit()
    8392{
    84     context = JSGlobalContextCreateInGroup(nullptr, nullptr);
    85 
    86     JSContextGroupRef contextGroup = JSContextGetGroup(context);
    87     JSObjectRef globalObject = JSContextGetGlobalObject(context);
    88     ASSERT(JSValueIsObject(context, globalObject));
    89 
    90     JSValueRef v = nullptr;
    91     JSValueRef exception = nullptr;
     93    static const TierOptions tierOptionsList[] = {
     94        { "LLINT",    0,   "--enableConcurrentJIT=false --useLLInt=true --useJIT=false" },
     95        { "Baseline", 0,   "--enableConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=false" },
     96        { "DFG",      0,   "--enableConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=false" },
     97        { "FTL",      200, "--enableConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=true" },
     98    };
     99   
    92100    bool failed = false;
    93101
    94     JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime");
    95     JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback);
    96     JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr);
    97     JSStringRelease(currentCPUTimeStr);
    98    
    99     /* Test script timeout: */
    100     JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0);
    101     {
    102         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
    103         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
    104         exception = nullptr;
    105         shouldTerminateCallbackWasCalled = false;
    106         auto startTime = currentCPUTime();
    107         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
    108         auto endTime = currentCPUTime();
    109        
    110         if (((endTime - startTime) < milliseconds(150)) && shouldTerminateCallbackWasCalled)
    111             printf("PASS: script timed out as expected.\n");
    112         else {
    113             if (!((endTime - startTime) < milliseconds(150)))
    114                 printf("FAIL: script did not time out as expected.\n");
    115             if (!shouldTerminateCallbackWasCalled)
    116                 printf("FAIL: script timeout callback was not called.\n");
    117             failed = true;
    118         }
    119        
    120         if (!exception) {
    121             printf("FAIL: TerminatedExecutionException was not thrown.\n");
    122             failed = true;
    123         }
     102    JSC::initializeThreading();
     103    Options::initialize(); // Ensure options is initialized first.
     104
     105    for (auto tierOptions : tierOptionsList) {
     106        StringBuilder savedOptionsBuilder;
     107        Options::dumpAllOptionsInALine(savedOptionsBuilder);
     108
     109        Options::setOptions(tierOptions.optionsStr);
     110       
     111        unsigned tierAdjustmentMillis = tierOptions.timeLimitAdjustmentMillis;
     112        double timeLimit;
     113
     114        context = JSGlobalContextCreateInGroup(nullptr, nullptr);
     115
     116        JSContextGroupRef contextGroup = JSContextGetGroup(context);
     117        JSObjectRef globalObject = JSContextGetGlobalObject(context);
     118        ASSERT(JSValueIsObject(context, globalObject));
     119
     120        JSValueRef scriptResult = nullptr;
     121        JSValueRef exception = nullptr;
     122
     123        JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime");
     124        JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback);
     125        JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr);
     126        JSStringRelease(currentCPUTimeStr);
     127       
     128        /* Test script timeout: */
     129        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
     130        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0);
     131        {
     132            unsigned timeAfterWatchdogShouldHaveFired = 150 + tierAdjustmentMillis;
     133
     134            StringBuilder scriptBuilder;
     135            scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
     136            scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0);
     137            scriptBuilder.append(") break; } } foo();");
     138
     139            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
     140            exception = nullptr;
     141            shouldTerminateCallbackWasCalled = false;
     142            auto startTime = currentCPUTime();
     143            scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
     144            auto endTime = currentCPUTime();
     145
     146            if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && shouldTerminateCallbackWasCalled)
     147                printf("PASS: %s script timed out as expected.\n", tierOptions.tier);
     148            else {
     149                if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired))
     150                    printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier);
     151                if (!shouldTerminateCallbackWasCalled)
     152                    printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier);
     153                failed = true;
     154            }
     155           
     156            if (!exception) {
     157                printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier);
     158                failed = true;
     159            }
     160        }
     161
     162        /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */
     163        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
     164        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0);
     165        {
     166            unsigned timeAfterWatchdogShouldHaveFired = 150 + tierAdjustmentMillis;
     167           
     168            StringBuilder scriptBuilder;
     169            scriptBuilder.append("function foo() { var startTime = currentCPUTime(); try { while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
     170            scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0);
     171            scriptBuilder.append(") break; } } catch(e) { } } foo();");
     172
     173            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
     174            exception = nullptr;
     175            shouldTerminateCallbackWasCalled = false;
     176
     177            auto startTime = currentCPUTime();
     178            scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
     179            auto endTime = currentCPUTime();
     180           
     181            if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) || !shouldTerminateCallbackWasCalled) {
     182                if (!((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)))
     183                    printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier);
     184                if (!shouldTerminateCallbackWasCalled)
     185                    printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier);
     186                failed = true;
     187            }
     188           
     189            if (exception)
     190                printf("PASS: %s TerminatedExecutionException was not catchable as expected.\n", tierOptions.tier);
     191            else {
     192                printf("FAIL: %s TerminatedExecutionException was caught.\n", tierOptions.tier);
     193                failed = true;
     194            }
     195        }
     196       
     197        /* Test script timeout with no callback: */
     198        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
     199        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, 0, 0);
     200        {
     201            unsigned timeAfterWatchdogShouldHaveFired = 150 + tierAdjustmentMillis;
     202           
     203            StringBuilder scriptBuilder;
     204            scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
     205            scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0);
     206            scriptBuilder.append(") break; } } foo();");
     207           
     208            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
     209            exception = nullptr;
     210            shouldTerminateCallbackWasCalled = false;
     211
     212            auto startTime = currentCPUTime();
     213            scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
     214            auto endTime = currentCPUTime();
     215           
     216            if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && !shouldTerminateCallbackWasCalled)
     217                printf("PASS: %s script timed out as expected when no callback is specified.\n", tierOptions.tier);
     218            else {
     219                if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired))
     220                    printf("FAIL: %s script did not time out as expected when no callback is specified.\n", tierOptions.tier);
     221                else
     222                    printf("FAIL: %s script called stale callback function.\n", tierOptions.tier);
     223                failed = true;
     224            }
     225           
     226            if (!exception) {
     227                printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier);
     228                failed = true;
     229            }
     230        }
     231       
     232        /* Test script timeout cancellation: */
     233        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
     234        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, cancelTerminateCallback, 0);
     235        {
     236            unsigned timeAfterWatchdogShouldHaveFired = 150 + tierAdjustmentMillis;
     237           
     238            StringBuilder scriptBuilder;
     239            scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
     240            scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0);
     241            scriptBuilder.append(") break; } } foo();");
     242
     243            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
     244            exception = nullptr;
     245            cancelTerminateCallbackWasCalled = false;
     246
     247            auto startTime = currentCPUTime();
     248            scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
     249            auto endTime = currentCPUTime();
     250           
     251            if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) && cancelTerminateCallbackWasCalled && !exception)
     252                printf("PASS: %s script timeout was cancelled as expected.\n", tierOptions.tier);
     253            else {
     254                if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) || exception)
     255                    printf("FAIL: %s script timeout was not cancelled.\n", tierOptions.tier);
     256                if (!cancelTerminateCallbackWasCalled)
     257                    printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier);
     258                failed = true;
     259            }
     260           
     261            if (exception) {
     262                printf("FAIL: %s Unexpected TerminatedExecutionException thrown.\n", tierOptions.tier);
     263                failed = true;
     264            }
     265        }
     266       
     267        /* Test script timeout extension: */
     268        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
     269        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, extendTerminateCallback, 0);
     270        {
     271            unsigned timeBeforeExtendedDeadline = 200 + tierAdjustmentMillis;
     272            unsigned timeAfterExtendedDeadline = 350 + tierAdjustmentMillis;
     273            unsigned maxBusyLoopTime = 500 + tierAdjustmentMillis;
     274
     275            StringBuilder scriptBuilder;
     276            scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
     277            scriptBuilder.appendNumber(maxBusyLoopTime / 1000.0); // in seconds.
     278            scriptBuilder.append(") break; } } foo();");
     279
     280            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
     281            exception = nullptr;
     282            extendTerminateCallbackCalled = 0;
     283
     284            auto startTime = currentCPUTime();
     285            scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
     286            auto endTime = currentCPUTime();
     287            auto deltaTime = endTime - startTime;
     288           
     289            if ((deltaTime >= milliseconds(timeBeforeExtendedDeadline)) && (deltaTime < milliseconds(timeAfterExtendedDeadline)) && (extendTerminateCallbackCalled == 2) && exception)
     290                printf("PASS: %s script timeout was extended as expected.\n", tierOptions.tier);
     291            else {
     292                if (deltaTime < milliseconds(timeBeforeExtendedDeadline))
     293                    printf("FAIL: %s script timeout was not extended as expected.\n", tierOptions.tier);
     294                else if (deltaTime >= milliseconds(timeAfterExtendedDeadline))
     295                    printf("FAIL: %s script did not timeout.\n", tierOptions.tier);
     296               
     297                if (extendTerminateCallbackCalled < 1)
     298                    printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier);
     299                if (extendTerminateCallbackCalled < 2)
     300                    printf("FAIL: %s script timeout callback was not called after timeout extension.\n", tierOptions.tier);
     301               
     302                if (!exception)
     303                    printf("FAIL: %s TerminatedExecutionException was not thrown during timeout extension test.\n", tierOptions.tier);
     304               
     305                failed = true;
     306            }
     307        }
     308
     309        JSGlobalContextRelease(context);
     310
     311        Options::setOptions(savedOptionsBuilder.toString().ascii().data());
    124312    }
    125313   
    126     /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */
    127     JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0);
    128     {
    129         const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }";
    130         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
    131         exception = nullptr;
    132         shouldTerminateCallbackWasCalled = false;
    133         auto startTime = currentCPUTime();
    134         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
    135         auto endTime = currentCPUTime();
    136        
    137         if (((endTime - startTime) >= milliseconds(150)) || !shouldTerminateCallbackWasCalled) {
    138             if (!((endTime - startTime) < milliseconds(150)))
    139                 printf("FAIL: script did not time out as expected.\n");
    140             if (!shouldTerminateCallbackWasCalled)
    141                 printf("FAIL: script timeout callback was not called.\n");
    142             failed = true;
    143         }
    144        
    145         if (exception)
    146             printf("PASS: TerminatedExecutionException was not catchable as expected.\n");
    147         else {
    148             printf("FAIL: TerminatedExecutionException was caught.\n");
    149             failed = true;
    150         }
    151     }
    152    
    153     /* Test script timeout with no callback: */
    154     JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0);
    155     {
    156         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
    157         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
    158         exception = nullptr;
    159         auto startTime = currentCPUTime();
    160         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
    161         auto endTime = currentCPUTime();
    162        
    163         if (((endTime - startTime) < milliseconds(150)) && shouldTerminateCallbackWasCalled)
    164             printf("PASS: script timed out as expected when no callback is specified.\n");
    165         else {
    166             if (!((endTime - startTime) < milliseconds(150)))
    167                 printf("FAIL: script did not time out as expected when no callback is specified.\n");
    168             failed = true;
    169         }
    170        
    171         if (!exception) {
    172             printf("FAIL: TerminatedExecutionException was not thrown.\n");
    173             failed = true;
    174         }
    175     }
    176    
    177     /* Test script timeout cancellation: */
    178     JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0);
    179     {
    180         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
    181         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
    182         exception = nullptr;
    183         auto startTime = currentCPUTime();
    184         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
    185         auto endTime = currentCPUTime();
    186        
    187         if (((endTime - startTime) >= milliseconds(150)) && cancelTerminateCallbackWasCalled && !exception)
    188             printf("PASS: script timeout was cancelled as expected.\n");
    189         else {
    190             if (((endTime - startTime) < milliseconds(150)) || exception)
    191                 printf("FAIL: script timeout was not cancelled.\n");
    192             if (!cancelTerminateCallbackWasCalled)
    193                 printf("FAIL: script timeout callback was not called.\n");
    194             failed = true;
    195         }
    196        
    197         if (exception) {
    198             printf("FAIL: Unexpected TerminatedExecutionException thrown.\n");
    199             failed = true;
    200         }
    201     }
    202    
    203     /* Test script timeout extension: */
    204     JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0);
    205     {
    206         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } ";
    207         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
    208         exception = nullptr;
    209         auto startTime = currentCPUTime();
    210         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
    211         auto endTime = currentCPUTime();
    212         auto deltaTime = endTime - startTime;
    213        
    214         if ((deltaTime >= milliseconds(300)) && (deltaTime < milliseconds(500)) && (extendTerminateCallbackCalled == 2) && exception)
    215             printf("PASS: script timeout was extended as expected.\n");
    216         else {
    217             if (deltaTime < milliseconds(200))
    218                 printf("FAIL: script timeout was not extended as expected.\n");
    219             else if (deltaTime >= milliseconds(500))
    220                 printf("FAIL: script did not timeout.\n");
    221            
    222             if (extendTerminateCallbackCalled < 1)
    223                 printf("FAIL: script timeout callback was not called.\n");
    224             if (extendTerminateCallbackCalled < 2)
    225                 printf("FAIL: script timeout callback was not called after timeout extension.\n");
    226            
    227             if (!exception)
    228                 printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n");
    229            
    230             failed = true;
    231         }
    232     }
    233 
    234     JSGlobalContextRelease(context);
    235314    return failed;
    236315}
  • trunk/Source/JavaScriptCore/ChangeLog

    r188642 r188648  
     12015-08-19  Mark Lam  <mark.lam@apple.com>
     2
     3        Add ability to save and restore JSC options.
     4        https://bugs.webkit.org/show_bug.cgi?id=148125
     5
     6        Reviewed by Saam Barati.
     7
     8        * API/tests/ExecutionTimeLimitTest.cpp:
     9        (testExecutionTimeLimit):
     10        - Employ the new options getter/setter to run watchdog tests for each of the
     11          execution engine tiers.
     12        - Also altered the test scripts to be in a function instead of global code.
     13          This is one of 2 changes needed to give them an opportunity to be FTL compiled.
     14          The other is to add support for compiling CheckWatchdogTimer in the FTL (which
     15          will be addressed in a separate patch).
     16
     17        * jsc.cpp:
     18        (CommandLine::parseArguments):
     19        * runtime/Options.cpp:
     20        (JSC::parse):
     21        - Add the ability to clear a string option with a nullptr value.
     22          This is needed to restore a default string option value which may be null.
     23
     24        (JSC::OptionRange::init):
     25        - Add the ability to clear a range option with a null value.
     26          This is needed to restore a default range option value which may be null.
     27
     28        (JSC::Options::initialize):
     29        (JSC::Options::dumpOptionsIfNeeded):
     30        - Factor code to dump options out to dumpOptionsIfNeeded() since we will need
     31          that logic elsewhere.
     32
     33        (JSC::Options::setOptions):
     34        - Parse an options string and set each of the specified options.
     35
     36        (JSC::Options::dumpAllOptions):
     37        (JSC::Options::dumpAllOptionsInALine):
     38        (JSC::Options::dumpOption):
     39        (JSC::Option::dump):
     40        - Refactored so that the underlying dumper dumps to a StringBuilder instead of
     41          stderr.  This lets us reuse this code to serialize all the options into a
     42          single string for dumpAllOptionsInALine().
     43
     44        * runtime/Options.h:
     45        (JSC::OptionRange::rangeString):
     46
    1472015-08-18  Filip Pizlo  <fpizlo@apple.com>
    248
  • trunk/Source/JavaScriptCore/jsc.cpp

    r188549 r188648  
    15511551
    15521552    if (needToDumpOptions)
    1553         JSC::Options::dumpAllOptions(JSC::Options::DumpLevel::Verbose, "All JSC runtime options:", stderr);
     1553        JSC::Options::dumpAllOptions(stderr, JSC::Options::DumpLevel::Verbose, "All JSC runtime options:");
    15541554    JSC::Options::ensureOptionsAreCoherent();
    15551555    if (needToExit)
  • trunk/Source/JavaScriptCore/runtime/Options.cpp

    r187125 r188648  
    3939#include <wtf/StdLibExtras.h>
    4040#include <wtf/StringExtras.h>
     41#include <wtf/text/StringBuilder.h>
    4142
    4243#if OS(DARWIN) && ENABLE(PARALLEL_GC)
     
    8586static bool parse(const char* string, const char*& value)
    8687{
     88    if (!strlen(string))
     89        string = nullptr;
    8790    value = string;
    8891    return true;
     
    150153}
    151154
     155const char* const OptionRange::s_nullRangeStr = "<null>";
     156
    152157bool OptionRange::init(const char* rangeString)
    153158{
     
    156161
    157162    bool invert = false;
    158 
    159     if (m_state > Uninitialized)
    160         return true;
    161163
    162164    if (!rangeString) {
     
    165167    }
    166168
     169    if (!strcmp(rangeString, s_nullRangeStr)) {
     170        m_state = Uninitialized;
     171        return true;
     172    }
     173   
    167174    m_rangeString = rangeString;
    168175
     
    361368            ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
    362369
    363             if (Options::showOptions()) {
    364                 DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
    365                 if (level > DumpLevel::Verbose)
    366                     level = DumpLevel::Verbose;
    367 
    368                 const char* title = nullptr;
    369                 switch (level) {
    370                 case DumpLevel::None:
    371                     break;
    372                 case DumpLevel::Overridden:
    373                     title = "Overridden JSC options:";
    374                     break;
    375                 case DumpLevel::All:
    376                     title = "All JSC options:";
    377                     break;
    378                 case DumpLevel::Verbose:
    379                     title = "All JSC options with descriptions:";
    380                     break;
    381                 }
    382                 dumpAllOptions(level, title);
    383             }
    384 
     370            dumpOptionsIfNeeded();
    385371            ensureOptionsAreCoherent();
    386372        });
     373}
     374
     375void Options::dumpOptionsIfNeeded()
     376{
     377    if (Options::showOptions()) {
     378        DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
     379        if (level > DumpLevel::Verbose)
     380            level = DumpLevel::Verbose;
     381           
     382        const char* title = nullptr;
     383        switch (level) {
     384        case DumpLevel::None:
     385            break;
     386        case DumpLevel::Overridden:
     387            title = "Overridden JSC options:";
     388            break;
     389        case DumpLevel::All:
     390            title = "All JSC options:";
     391            break;
     392        case DumpLevel::Verbose:
     393            title = "All JSC options with descriptions:";
     394            break;
     395        }
     396
     397        StringBuilder builder;
     398        dumpAllOptions(builder, level, title, nullptr, "   ", "\n", ShowDefaults);
     399        dataLog(builder.toString());
     400    }
     401}
     402
     403bool Options::setOptions(const char* optionsStr)
     404{
     405    Vector<char*> options;
     406
     407    size_t length = strlen(optionsStr);
     408    char* optionsStrCopy = WTF::fastStrDup(optionsStr);
     409    char* end = optionsStrCopy + length;
     410    char* p = optionsStrCopy;
     411
     412    while (p < end) {
     413        char* optionStart = p;
     414        p = strstr(p, "=");
     415        if (!p) {
     416            dataLogF("'=' not found in option string: %p\n", optionStart);
     417            return false;
     418        }
     419        p++;
     420
     421        char* valueBegin = p;
     422        bool hasStringValue = false;
     423        const int minStringLength = 2; // The min is an empty string i.e. 2 double quotes.
     424        if ((p + minStringLength < end) && (*p == '"')) {
     425            p = strstr(p + 1, "\"");
     426            if (!p) {
     427                dataLogF("Missing trailing '\"' in option string: %p\n", optionStart);
     428                return false; // End of string not found.
     429            }
     430            hasStringValue = true;
     431        }
     432
     433        p = strstr(p, " ");
     434        if (!p)
     435            p = end; // No more " " separator. Hence, this is the last arg.
     436
     437        // If we have a well-formed string value, strip the quotes.
     438        if (hasStringValue) {
     439            char* valueEnd = p;
     440            ASSERT((*valueBegin == '"') && ((valueEnd - valueBegin) >= minStringLength) && (valueEnd[-1] == '"'));
     441            memmove(valueBegin, valueBegin + 1, valueEnd - valueBegin - minStringLength);
     442            valueEnd[-minStringLength] = '\0';
     443        }
     444
     445        // Strip leading -- if present.
     446        if ((p -  optionStart > 2) && optionStart[0] == '-' && optionStart[1] == '-')
     447            optionStart += 2;
     448
     449        *p++ = '\0';
     450        options.append(optionStart);
     451    }
     452
     453    bool success = true;
     454    for (auto& option : options) {
     455        bool optionSuccess = setOption(option);
     456        if (!optionSuccess) {
     457            dataLogF("Failed to set option : %s\n", option);
     458            success = false;
     459        }
     460    }
     461
     462    dumpOptionsIfNeeded();
     463    return success;
    387464}
    388465
     
    421498}
    422499
    423 void Options::dumpAllOptions(DumpLevel level, const char* title, FILE* stream)
    424 {
    425     if (title)
    426         fprintf(stream, "%s\n", title);
    427     for (int id = 0; id < numberOfOptions; id++)
    428         dumpOption(level, static_cast<OptionID>(id), stream, "   ", "\n");
    429 }
    430 
    431 void Options::dumpOption(DumpLevel level, OptionID id, FILE* stream, const char* header, const char* footer)
     500void Options::dumpAllOptions(StringBuilder& builder, DumpLevel level, const char* title,
     501    const char* separator, const char* optionHeader, const char* optionFooter, ShowDefaultsOption showDefaultsOption)
     502{
     503    if (title) {
     504        builder.append(title);
     505        builder.append('\n');
     506    }
     507
     508    for (int id = 0; id < numberOfOptions; id++) {
     509        if (separator && id)
     510            builder.append(separator);
     511        dumpOption(builder, level, static_cast<OptionID>(id), optionHeader, optionFooter, showDefaultsOption);
     512    }
     513}
     514
     515void Options::dumpAllOptionsInALine(StringBuilder& builder)
     516{
     517    dumpAllOptions(builder, DumpLevel::All, nullptr, " ", nullptr, nullptr, DontShowDefaults);
     518}
     519
     520void Options::dumpAllOptions(FILE* stream, DumpLevel level, const char* title)
     521{
     522    StringBuilder builder;
     523    dumpAllOptions(builder, level, title, nullptr, "   ", "\n", ShowDefaults);
     524    fprintf(stream, "%s", builder.toString().ascii().data());
     525}
     526
     527void Options::dumpOption(StringBuilder& builder, DumpLevel level, OptionID id,
     528    const char* header, const char* footer, ShowDefaultsOption showDefaultsOption)
    432529{
    433530    if (id >= numberOfOptions)
     
    441538        return;
    442539
    443     fprintf(stream, "%s%s: ", header, option.name());
    444     option.dump(stream);
    445 
    446     if (wasOverridden) {
    447         fprintf(stream, " (default: ");
    448         option.defaultOption().dump(stream);
    449         fprintf(stream, ")");
    450     }
    451 
    452     if (needsDescription)
    453         fprintf(stream, "   ... %s", option.description());
    454 
    455     fprintf(stream, "%s", footer);
     540    if (header)
     541        builder.append(header);
     542    builder.append(option.name());
     543    builder.append('=');
     544    option.dump(builder);
     545
     546    if (wasOverridden && (showDefaultsOption == ShowDefaults)) {
     547        builder.append(" (default: ");
     548        option.defaultOption().dump(builder);
     549        builder.append(")");
     550    }
     551
     552    if (needsDescription) {
     553        builder.append("   ... ");
     554        builder.append(option.description());
     555    }
     556
     557    builder.append(footer);
    456558}
    457559
     
    467569}
    468570
    469 void Option::dump(FILE* stream) const
     571void Option::dump(StringBuilder& builder) const
    470572{
    471573    switch (type()) {
    472574    case Options::Type::boolType:
    473         fprintf(stream, "%s", m_entry.boolVal ? "true" : "false");
     575        builder.append(m_entry.boolVal ? "true" : "false");
    474576        break;
    475577    case Options::Type::unsignedType:
    476         fprintf(stream, "%u", m_entry.unsignedVal);
     578        builder.appendNumber(m_entry.unsignedVal);
    477579        break;
    478580    case Options::Type::doubleType:
    479         fprintf(stream, "%lf", m_entry.doubleVal);
     581        builder.appendNumber(m_entry.doubleVal);
    480582        break;
    481583    case Options::Type::int32Type:
    482         fprintf(stream, "%d", m_entry.int32Val);
     584        builder.appendNumber(m_entry.int32Val);
    483585        break;
    484586    case Options::Type::optionRangeType:
    485         fprintf(stream, "%s", m_entry.optionRangeVal.rangeString());
     587        builder.append(m_entry.optionRangeVal.rangeString());
    486588        break;
    487589    case Options::Type::optionStringType: {
     
    489591        if (!option)
    490592            option = "";
    491         fprintf(stream, "%s", option);
     593        builder.append('"');
     594        builder.append(option);
     595        builder.append('"');
    492596        break;
    493597    }
    494598    case Options::Type::gcLogLevelType: {
    495         fprintf(stream, "%s", GCLogging::levelAsString(m_entry.gcLogLevelVal));
     599        builder.append(GCLogging::levelAsString(m_entry.gcLogLevelVal));
    496600        break;
    497601    }
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r188355 r188648  
    3333#include <wtf/PrintStream.h>
    3434#include <wtf/StdLibExtras.h>
     35
     36namespace WTF {
     37class StringBuilder;
     38}
     39using WTF::StringBuilder;
    3540
    3641namespace JSC {
     
    8186    bool init(const char*);
    8287    bool isInRange(unsigned);
    83     const char* rangeString() const { return (m_state > InitError) ? m_rangeString : "<null>"; }
     88    const char* rangeString() const { return (m_state > InitError) ? m_rangeString : s_nullRangeStr; }
    8489   
    8590    void dump(PrintStream& out) const;
    8691
    8792private:
     93    static const char* const s_nullRangeStr;
     94
    8895    RangeState m_state;
    8996    const char* m_rangeString;
     
    360367    JS_EXPORT_PRIVATE static void initialize();
    361368
     369    // Parses a string of options where each option is of the format "--<optionName>=<value>"
     370    // and are separated by a space. The leading "--" is optional and will be ignored.
     371    JS_EXPORT_PRIVATE static bool setOptions(const char* optionsList);
     372
    362373    // Parses a single command line option in the format "<optionName>=<value>"
    363374    // (no spaces allowed) and set the specified option if appropriate.
    364375    JS_EXPORT_PRIVATE static bool setOption(const char* arg);
    365     JS_EXPORT_PRIVATE static void dumpAllOptions(DumpLevel, const char* title = nullptr, FILE* stream = stdout);
    366     static void dumpOption(DumpLevel, OptionID, FILE* stream = stdout, const char* header = "", const char* footer = "");
     376
     377    JS_EXPORT_PRIVATE static void dumpAllOptions(FILE*, DumpLevel, const char* title = nullptr);
     378    JS_EXPORT_PRIVATE static void dumpAllOptionsInALine(StringBuilder&);
     379
    367380    JS_EXPORT_PRIVATE static void ensureOptionsAreCoherent();
    368381
     
    396409    Options();
    397410
     411    enum ShowDefaultsOption {
     412        DontShowDefaults,
     413        ShowDefaults
     414    };
     415    static void dumpOptionsIfNeeded();
     416    static void dumpAllOptions(StringBuilder&, DumpLevel, const char* title,
     417        const char* separator, const char* optionHeader, const char* optionFooter, ShowDefaultsOption);
     418    static void dumpOption(StringBuilder&, DumpLevel, OptionID,
     419        const char* optionHeader, const char* optionFooter, ShowDefaultsOption);
     420
    398421    // Declare the singleton instance of the options store:
    399422    JS_EXPORTDATA static Entry s_options[numberOfOptions];
     
    412435    }
    413436   
    414     void dump(FILE*) const;
     437    void dump(StringBuilder&) const;
     438
    415439    bool operator==(const Option& other) const;
    416440    bool operator!=(const Option& other) const { return !(*this == other); }
Note: See TracChangeset for help on using the changeset viewer.